diff options
| author | Skip Montanaro <[email protected]> | 2021-02-16 14:40:46 -0600 |
|---|---|---|
| committer | Skip Montanaro <[email protected]> | 2021-02-16 14:40:46 -0600 |
| commit | a19a216bc60160c162e616145ef091dd18ce4e61 (patch) | |
| tree | fa4bdff21f9b04a125c84a2bfab8a1c738359e15 | |
| download | python-0.9.1-patched-QoL-a19a216bc60160c162e616145ef091dd18ce4e61.tar.xz python-0.9.1-patched-QoL-a19a216bc60160c162e616145ef091dd18ce4e61.zip | |
Python 0.9.1 as posted in alt.sources
271 files changed, 96470 insertions, 0 deletions
@@ -0,0 +1,71 @@ +This is Python, an extensible interpreted programming language that +combines remarkable power with very clear syntax. + +This is version 0.9 (the first beta release), patchlevel 1. + +Python can be used instead of shell, Awk or Perl scripts, to write +prototypes of real applications, or as an extension language of large +systems, you name it. There are built-in modules that interface to +the operating system and to various window systems: X11, the Mac +window system (you need STDWIN for these two), and Silicon Graphics' +GL library. It runs on most modern versions of UNIX, on the Mac, and +I wouldn't be surprised if it ran on MS-DOS unchanged. I developed it +mostly on an SGI IRIS workstation (using IRIX 3.1 and 3.2) and on the +Mac, but have tested it also on SunOS (4.1) and BSD 4.3 (tahoe). + +Building and installing Python is easy (but do read the Makefile). +A UNIX style manual page and extensive documentation (in LaTeX format) +are provided. (In the beta release, the documentation is still under +development.) + +Please try it out and send me your comments (on anything -- the +language design, implementation, portability, installation, +documentation) and the modules you wrote for it, to make the first +real release better. If you needed to hack the source to get it to +compile and run on a particular machine, send me the fixes -- I'll try +to incorporate them into the next patch. If you can't get it to work +at all, send me a *detailed* description of the problem and I may look +into it. + +If you want to profit of the X11 or Mac window interface, you'll need +STDWIN. This is a portable window system interface by the same +author. The versions of STDWIN floating around on some archives are +not sufficiently up-to-date for use with Python. I will distribute +the latest and greatest STDWIN version at about the same time as Python. + +I am the author of Python: + + Guido van Rossum + CWI, dept. CST + Kruislaan 413 + 1098 SJ Amsterdam + The Netherlands + + E-mail: [email protected] + +The Python source is copyrighted, but you can freely use and copy it +as long as you don't change or remove the copyright: + +/*********************************************************** +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. + +******************************************************************/ diff --git a/demo/README b/demo/README new file mode 100644 index 0000000..a9ff224 --- /dev/null +++ b/demo/README @@ -0,0 +1,22 @@ +This directory contains various demonstrations of what you can do with +Python. The demos are grouped sub(sub*)directories according to +required optional built-in modules. + +scripts Some useful Python scripts that I put in my bin + directory. No optional built-in modules meeded. + +sgi Demos that only run on Silicon Graphics machines. + Require the built-in modules 'audio' and/or 'gl'. + +stdwin Demos that use the STDWIN library. Require the 'stdwin' + built-in module. + +WARNING: some scripts are executable and have a first line saying + + #! /ufs/guido/bin/sgi/python + +This is unlikely to give good results anywhere else except in my +office. Edit the first line before installing such scripts; to try +them out, you can just say "python file.py". (The .py suffix is not +necessary in this case, but makes it possible to debug the modules +interactively by importing them.) diff --git a/demo/scripts/findlinksto.py b/demo/scripts/findlinksto.py new file mode 100755 index 0000000..210441e --- /dev/null +++ b/demo/scripts/findlinksto.py @@ -0,0 +1,29 @@ +#! /ufs/guido/bin/sgi/python + +# findlinksto +# +# find symbolic links to a given path + +import posix, path, sys + +def visit(pattern, dirname, names): + if path.islink(dirname): + names[:] = [] + return + if path.ismount(dirname): + print 'descend into', dirname + n = len(pattern) + for name in names: + name = path.cat(dirname, name) + try: + linkto = posix.readlink(name) + if linkto[:n] = pattern: + print name, '->', linkto + except posix.error: + pass + +def main(pattern, args): + for dirname in args: + path.walk(dirname, visit, pattern) + +main(sys.argv[1], sys.argv[2:]) diff --git a/demo/scripts/mkreal.py b/demo/scripts/mkreal.py new file mode 100755 index 0000000..19fef28 --- /dev/null +++ b/demo/scripts/mkreal.py @@ -0,0 +1,65 @@ +#! /ufs/guido/bin/sgi/python + +# mkreal +# +# turn a symlink to a directory into a real directory + +import sys +import posix +import path +from stat import * + +cat = path.cat + +error = 'mkreal error' + +BUFSIZE = 32*1024 + +def mkrealfile(name): + st = posix.stat(name) # Get the mode + mode = S_IMODE(st[ST_MODE]) + linkto = posix.readlink(name) # Make sure again it's a symlink + f_in = open(name, 'r') # This ensures it's a file + posix.unlink(name) + f_out = open(name, 'w') + while 1: + buf = f_in.read(BUFSIZE) + if not buf: break + f_out.write(buf) + del f_out # Flush data to disk before changing mode + posix.chmod(name, mode) + +def mkrealdir(name): + st = posix.stat(name) # Get the mode + mode = S_IMODE(st[ST_MODE]) + linkto = posix.readlink(name) + files = posix.listdir(name) + posix.unlink(name) + posix.mkdir(name, mode) + posix.chmod(name, mode) + linkto = cat('..', linkto) + # + for file in files: + if file not in ('.', '..'): + posix.symlink(cat(linkto, file), cat(name, file)) + +def main(): + sys.stdout = sys.stderr + progname = path.basename(sys.argv[0]) + args = sys.argv[1:] + if not args: + print 'usage:', progname, 'path ...' + sys.exit(2) + status = 0 + for name in args: + if not path.islink(name): + print progname+':', name+':', 'not a symlink' + status = 1 + else: + if path.isdir(name): + mkrealdir(name) + else: + mkrealfile(name) + sys.exit(status) + +main() diff --git a/demo/scripts/ptags.py b/demo/scripts/ptags.py new file mode 100755 index 0000000..0f99650 --- /dev/null +++ b/demo/scripts/ptags.py @@ -0,0 +1,66 @@ +#! /ufs/guido/bin/sgi/python + +# ptags +# +Create a tags file for Python programs +# Tagged are: +# - functions (even inside other defs or classes) +# - classes +# - filenames +# Warns about files it cannot open. +# No warnings about duplicate tags. + +import sys +import posix +import path +import string + +keywords = ['def', 'class'] # If you add keywords, update starts!!! +starts = 'dc' # Starting characters of keywords + +whitespace = string.whitespace +identchars = string.letters + string.digits + '_' + +tags = [] # Modified! + +def main(): + args = sys.argv[1:] + for file in args: treat_file(file) + if tags: + fp = open('tags', 'w') + tags.sort() + for s in tags: fp.write(s) + +def treat_file(file): + try: + fp = open(file, 'r') + except: + print 'Cannot open', file + return + base = path.basename(file) + if base[-3:] = '.py': base = base[:-3] + s = base + '\t' + file + '\t' + '1\n' + tags.append(s) + while 1: + line = fp.readline() + if not line: break + maketag(line, file) + +def maketag(line, file): + i = 0 + while line[i:i+1] in whitespace: i = i+1 + if line[i:i+1] not in starts: return + n = len(line) + j = i + while i < n and line[i] not in whitespace: i = i+1 + if line[j:i] not in keywords: return + while i < n and line[i] in whitespace: i = i+1 + j = i + while i < n and line[i] in identchars: i = i+1 + name = line[j:i] + while i < n and line[i] in whitespace: i = i+1 + if i < n and line[i] = '(': i = i+1 + s = name + '\t' + file + '\t' + '/^' + line[:i] + '/\n' + tags.append(s) + +main() diff --git a/demo/scripts/suff.py b/demo/scripts/suff.py new file mode 100755 index 0000000..f6bd6bf --- /dev/null +++ b/demo/scripts/suff.py @@ -0,0 +1,29 @@ +#! /ufs/guido/bin/sgi/python + +# suff +# +# show different suffixes amongst arguments + +import sys + +def main(): + files = sys.argv[1:] + suffixes = {} + for file in files: + suff = getsuffix(file) + if not suffixes.has_key(suff): + suffixes[suff] = [] + suffixes[suff].append(file) + keys = suffixes.keys() + keys.sort() + for suff in keys: + print `suff`, len(suffixes[suff]) + +def getsuffix(file): + suff = '' + for i in range(len(file)): + if file[i] = '.': + suff = file[i:] + return suff + +main() diff --git a/demo/scripts/xxci.py b/demo/scripts/xxci.py new file mode 100755 index 0000000..43ea316 --- /dev/null +++ b/demo/scripts/xxci.py @@ -0,0 +1,77 @@ +#! /ufs/guido/bin/sgi/python + +# xxci +# +# check in files for which rcsdiff returns nonzero exit status + +import sys +import posix +import stat +import path +import commands + +MAXSIZE = 200*1024 # Files this big must be binaries and are skipped. + +def getargs(): + args = sys.argv[1:] + if args: + return args + print 'No arguments, checking almost *' + for file in posix.listdir('.'): + if not skipfile(file): + args.append(file) + if not args: + print 'Nothing to do -- exit 1' + sys.exit(1) + args.sort() + return args + +badnames = ['tags', 'xyzzy'] +badprefixes = ['.', ',', '@', '#', 'o.'] +badsuffixes = \ + ['~', '.a', '.o', '.old', '.bak', '.orig', '.new', '.prev', '.not'] +# XXX Should generalize even more to use fnmatch! + +def skipfile(file): + if file in badnames or \ + badprefix(file) or badsuffix(file) or \ + path.islink(file) or path.isdir(file): + return 1 + # Skip huge files -- probably binaries. + try: + st = posix.stat(file) + except posix.error: + return 1 # Doesn't exist -- skip it + return st[stat.ST_SIZE] >= MAXSIZE + +def badprefix(file): + for bad in badprefixes: + if file[:len(bad)] = bad: return 1 + return 0 + +def badsuffix(file): + for bad in badsuffixes: + if file[-len(bad):] = bad: return 1 + return 0 + +def go(args): + for file in args: + print file + ':' + if run('rcsdiff -c', file): + if askyesno('Check in ' + file + ' ? '): + sts = run('rcs -l', file) # ignored + # can't use run() here because it's interactive + sts = posix.system('ci -l ' + file) + +def run(cmd, file): + sts, output = commands.getstatusoutput(cmd + commands.mkarg(file)) + if sts: + print output + print 'Exit status', sts + return sts + +def askyesno(prompt): + s = raw_input(prompt) + return s in ['y', 'yes'] + +go(getargs()) diff --git a/demo/sgi/README b/demo/sgi/README new file mode 100644 index 0000000..5740c22 --- /dev/null +++ b/demo/sgi/README @@ -0,0 +1,15 @@ +Demonstrations of Python that use various features of the Silicon +Graphics IRIS machines. + +audio Demonstrations of the audio capabilities of the 4D/25. + Require the built-in module 'audio'. + +audio_stdwin Window-based demonstrations the audio capabilities of + the 4D/25. Require the built-in modules 'stdwin' and + 'audio'. + +gl Demonstrations of the Graphics Library (GL). + Require the built-in module 'gl'. + +gl_panel Demonstrations of the Panel Library by NASA Ames. + Require the built-in modules 'gl' and 'pnl'. diff --git a/demo/sgi/audio/README b/demo/sgi/audio/README new file mode 100644 index 0000000..17dc9b2 --- /dev/null +++ b/demo/sgi/audio/README @@ -0,0 +1,5 @@ +Programs that demonstrate the use of the audio device on the SGI 4D/25. +These require the built-in module 'audio'. + +play Read a sound sample from a file and play it through the + speaker. Options to set volume, sampling rate etc. diff --git a/demo/sgi/audio/play.py b/demo/sgi/audio/play.py new file mode 100755 index 0000000..8f6a802 --- /dev/null +++ b/demo/sgi/audio/play.py @@ -0,0 +1,75 @@ +#!/ufs/guido/bin/sgi/python + +import sys +import audio + +import string +import getopt +import auds + +debug = [] + +DEF_RATE = 3 + +def main(): + # + gain = 100 + rate = 0 + starter = audio.write + stopper = 0 + # + optlist, args = getopt.getopt(sys.argv[1:], 'adg:r:') + # + for optname, optarg in optlist: + if 0: + pass + elif optname = '-d': + debug.append(1) + elif optname = '-g': + gain = string.atoi(optarg) + if not (0 < gain < 256): + raise optarg.error, '-g gain out of range' + elif optname = '-r': + rate = string.atoi(optarg) + if not (1 <= rate <= 3): + raise optarg.error, '-r rate out of range' + elif optname = '-a': + starter = audio.start_playing + stopper = audio.wait_playing + # + audio.setoutgain(gain) + audio.setrate(rate) + # + if not args: + play(starter, rate, auds.loadfp(sys.stdin)) + else: + real_stopper = 0 + for file in args: + if real_stopper: + real_stopper() + play(starter, rate, auds.load(file)) + real_stopper = stopper + +def play(starter, rate, data): + magic = data[:4] + if magic = '0008': + mrate = 3 + elif magic = '0016': + mrate = 2 + elif magic = '0032': + mrate = 1 + else: + mrate = 0 + if mrate: + data = data[4:] + else: + mrate = DEF_RATE + if not rate: rate = mrate + audio.setrate(rate) + starter(data) + +try: + main() +finally: + audio.setoutgain(0) + audio.done() diff --git a/demo/sgi/audio_stdwin/README b/demo/sgi/audio_stdwin/README new file mode 100644 index 0000000..3074715 --- /dev/null +++ b/demo/sgi/audio_stdwin/README @@ -0,0 +1,16 @@ +Three programs that provide a user interface based upon STDWIN to the +audio device of the SGI 4D/25. These scripts also demonstrate the power +of a set of window interface classes implemented in Python that simplify +the construction of all sorts of buttons, etc. + +jukebox Browses a directory full of sound samples and lets you + play selected ones. (Probably not fully functional, it + requires a conversion program.) + +rec A tape recorder that lets you record a sound sample, + play it back, and save it to a file. Various options to + set sampling rate, volume etc. When idle it doubles + as a VU meter. + +vumeter A VU meter that displays a history of the volume of + sound recently sampled from the microphone. diff --git a/demo/sgi/audio_stdwin/jukebox.py b/demo/sgi/audio_stdwin/jukebox.py new file mode 100755 index 0000000..5267d73 --- /dev/null +++ b/demo/sgi/audio_stdwin/jukebox.py @@ -0,0 +1,321 @@ +#! /ufs/guido/bin/sgi/python + +# JUKEBOX: browse directories full of sampled sound files. +# +# One or more "list windows" display the files and subdirectories of +# the arguments. Double-clicking on a subdirectory opens a new window +# displaying its contents (and so on recursively). Double clicking +# on a file plays it as a sound file (assuming it is one). +# +# Playing is asynchronous: the application keeps listening to events +# while the sample is playing, so you can change the volume (gain) +# during playing, cancel playing or start a new sample right away. +# +# The control window displays the current output gain and a primitive +# "stop button" to cancel the current play request. +# +# Sound files must currently be in Dik Winter's compressed Mac format. +# Since decompression is costly, decompressed samples are saved in +# /usr/tmp/@j* until the application is left. The files are read +# afresh each time, though. + +import audio +import sunaudio +import commands +import getopt +import path +import posix +import rand +import stdwin +from stdwinevents import * +import string +import sys + +from WindowParent import WindowParent +from HVSplit import VSplit +from Buttons import PushButton +from Sliders import ComplexSlider + +# Pathnames + +HOME_BIN_SGI = '/ufs/guido/bin/sgi/' # Directory where macsound2sgi lives +DEF_DB = '/ufs/dik/sounds/Mac/HCOM' # Default directory of sounds + + +# Global variables + +class struct(): pass # Class to define featureless structures + +G = struct() # Holds writable global variables + + +# Main program + +def main(): + G.synchronous = 0 # If set, use synchronous audio.write() + G.debug = 0 # If set, print debug messages + G.gain = 75 # Output gain + G.rate = 3 # Sampling rate + G.busy = 0 # Set while asynchronous playing is active + G.windows = [] # List of open windows (except control) + G.mode = 'mac' # Macintosh mode + G.tempprefix = '/usr/tmp/@j' + `rand.rand()` + '-' + # + optlist, args = getopt.getopt(sys.argv[1:], 'dg:r:sSa') + for optname, optarg in optlist: + if optname = '-d': + G.debug = 1 + elif optname = '-g': + G.gain = string.atoi(optarg) + if not (0 < G.gain < 256): + raise optarg.error, '-g gain out of range' + elif optname = '-r': + G.rate = string.atoi(optarg) + if not (1 <= G.rate <= 3): + raise optarg.error, '-r rate out of range' + elif optname = '-s': + G.synchronous = 1 + elif optname = '-S': + G.mode = 'sgi' + elif optname = '-a': + G.mode = 'sun' + # + if not args: + args = [DEF_DB] + # + G.cw = opencontrolwindow() + for dirname in args: + G.windows.append(openlistwindow(dirname)) + # + # + savegain = audio.getoutgain() + try: + # Initialize stdaudio + audio.setoutgain(0) + audio.start_playing('') + dummy = audio.wait_playing() + audio.setoutgain(0) + maineventloop() + finally: + audio.setoutgain(savegain) + audio.done() + clearcache() + +def maineventloop(): + mouse_events = WE_MOUSE_DOWN, WE_MOUSE_MOVE, WE_MOUSE_UP + while G.windows: + type, w, detail = event = stdwin.getevent() + if w = G.cw.win: + if type = WE_CLOSE: + return + G.cw.dispatch(event) + else: + if type = WE_DRAW: + w.drawproc(w, detail) + elif type in mouse_events: + w.mouse(w, type, detail) + elif type = WE_CLOSE: + w.close(w) + del w, event + else: + if G.debug: print type, w, detail + +# Control window -- to set gain and cancel play operations in progress + +def opencontrolwindow(): + cw = WindowParent().create('Jukebox', (0, 0)) + v = VSplit().create(cw) + # + gain = ComplexSlider().define(v) + gain.setminvalmax(0, G.gain, 255) + gain.settexts(' ', ' ') + gain.sethook(gain_setval_hook) + # + stop = PushButton().definetext(v, 'Stop') + stop.hook = stop_hook + # + cw.realize() + return cw + +def gain_setval_hook(self): + G.gain = self.val + if G.busy: audio.setoutgain(G.gain) + +def stop_hook(self): + if G.busy: + audio.setoutgain(0) + dummy = audio.stop_playing() + G.busy = 0 + + +# List windows -- to display list of files and subdirectories + +def openlistwindow(dirname): + list = posix.listdir(dirname) + list.sort() + i = 0 + while i < len(list): + if list[i] = '.' or list[i] = '..': + del list[i] + else: + i = i+1 + for i in range(len(list)): + name = list[i] + if path.isdir(path.cat(dirname, name)): + list[i] = list[i] + '/' + width = maxwidth(list) + width = width + stdwin.textwidth(' ') # XXX X11 stdwin bug workaround + height = len(list) * stdwin.lineheight() + stdwin.setdefwinsize(width, min(height, 500)) + w = stdwin.open(dirname) + stdwin.setdefwinsize(0, 0) + w.setdocsize(width, height) + w.drawproc = drawlistwindow + w.mouse = mouselistwindow + w.close = closelistwindow + w.dirname = dirname + w.list = list + w.selected = -1 + return w + +def maxwidth(list): + width = 1 + for name in list: + w = stdwin.textwidth(name) + if w > width: width = w + return width + +def drawlistwindow(w, area): + d = w.begindrawing() + d.erase((0, 0), (1000, 10000)) + lh = d.lineheight() + h, v = 0, 0 + for name in w.list: + d.text((h, v), name) + v = v + lh + showselection(w, d) + +def hideselection(w, d): + if w.selected >= 0: + invertselection(w, d) + +def showselection(w, d): + if w.selected >= 0: + invertselection(w, d) + +def invertselection(w, d): + lh = d.lineheight() + h1, v1 = p1 = 0, w.selected*lh + h2, v2 = p2 = 1000, v1 + lh + d.invert(p1, p2) + +def mouselistwindow(w, type, detail): + (h, v), clicks, button = detail[:3] + d = w.begindrawing() + lh = d.lineheight() + if 0 <= v < lh*len(w.list): + i = v / lh + else: + i = -1 + if w.selected <> i: + hideselection(w, d) + w.selected = i + showselection(w, d) + if type = WE_MOUSE_DOWN and clicks >= 2 and i >= 0: + name = path.cat(w.dirname, w.list[i]) + if name[-1:] = '/': + if clicks = 2: + G.windows.append(openlistwindow(name[:-1])) + else: + playfile(name) + +def closelistwindow(w): + remove(G.windows, w) + +def remove(list, item): + for i in range(len(list)): + if list[i] = item: + del list[i] + break + + +# Playing tools + +cache = {} + +def clearcache(): + for x in cache.keys(): + try: + sts = posix.system('rm -f ' + cache[x]) + if sts: + print cmd + print 'Exit status', sts + except: + print cmd + print 'Exception?!' + del cache[x] + +def playfile(name): + if G.mode <> 'mac': + tempname = name + elif cache.has_key(name): + tempname = cache[name] + else: + tempname = G.tempprefix + `rand.rand()` + cmd = HOME_BIN_SGI + 'macsound2sgi' + cmd = cmd + ' ' + commands.mkarg(name) + cmd = cmd + ' >' + tempname + if G.debug: print cmd + sts = posix.system(cmd) + if sts: + print cmd + print 'Exit status', sts + stdwin.fleep() + return + cache[name] = tempname + fp = open(tempname, 'r') + try: + hdr = sunaudio.gethdr(fp) + except sunaudio.error, msg: + hdr = () + if hdr: + data_size = hdr[0] + data = fp.read(data_size) + # XXX this doesn't work yet, need to convert from uLAW!!! + del fp + else: + del fp + data = readfile(tempname) + if G.debug: print len(data), 'bytes read from', tempname + if G.busy: + G.busy = 0 + dummy = audio.stop_playing() + # + # Completely reset the audio device + audio.setrate(G.rate) + audio.setduration(0) + audio.setoutgain(G.gain) + # + if G.synchronous: + audio.write(data) + audio.setoutgain(0) + else: + try: + audio.start_playing(data) + G.busy = 1 + except: + stdwin.fleep() + del data + +def readfile(filename): + return readfp(open(filename, 'r')) + +def readfp(fp): + data = '' + while 1: + buf = fp.read(102400) # Reads most samples in one fell swoop + if not buf: + return data + data = data + buf + +main() diff --git a/demo/sgi/audio_stdwin/rec.py b/demo/sgi/audio_stdwin/rec.py new file mode 100755 index 0000000..3ab3aea --- /dev/null +++ b/demo/sgi/audio_stdwin/rec.py @@ -0,0 +1,271 @@ +#! /ufs/guido/bin/sgi/python + +import sys +import audio +import stdwin + +import string +import getopt + +from stdwinevents import * +from Buttons import * +from Sliders import * +#from Soundogram import Soundogram +from VUMeter import VUMeter +from WindowParent import WindowParent +from HVSplit import HSplit, VSplit + +class TimeOutToggleButton() = ToggleButton(): + def define(self, parent): + self = ToggleButton.define(self, parent) + self.parent.need_timer(self) + self.timer_hook = 0 + return self + def timer(self): + if self.timer_hook: + self.timer_hook(self) + +K = 1024 +BUFSIZE = 30*8*K +Rates = [0, 32*K, 16*K, 8*K] +Magics = ['', '0032', '0016', '0008'] + +class Struct(): pass +G = Struct() + +def main(): + # + # Set default state + # + G.gain = 60 + G.rate = 3 + G.nomuting = 0 + G.savefile = '@rec' + # + # Set default values + # + G.data = '' + G.playing = 0 + G.recording = 0 + G.sogram = 0 + # + # Parse options + # + optlist, args = getopt.getopt(sys.argv[1:], 'mdg:r:') + # + for optname, optarg in optlist: + if 0: # (So all cases start with elif) + pass + elif optname = '-d': + G.debug = 1 + elif optname = '-g': + G.gain = string.atoi(optarg) + if not (0 < G.gain < 256): + raise optarg.error, '-g gain out of range' + elif optname = '-m': + G.nomuting = (not G.nomuting) + elif optname = '-r': + G.rate = string.atoi(optarg) + if not (1 <= G.rate <= 3): + raise optarg.error, '-r rate out of range' + # + if args: + G.savefile = args[0] + # + # Initialize the sound package + # + audio.setoutgain(G.nomuting * G.gain) # Silence the speaker + audio.setrate(G.rate) + # + # Create the WindowParent and VSplit + # + G.window = WindowParent().create('Recorder', (0, 0)) + w = G.vsplit = VSplit().create(G.window) + # + # VU-meter + # + G.vubtn = VUMeter().define(w) + # + # Radiobuttons for rates + # + r1btn = RadioButton().definetext(w, '32 K/sec') + r1btn.on_hook = rate_hook + r1btn.rate = 1 + # + r2btn = RadioButton().definetext(w, '16 K/sec') + r2btn.on_hook = rate_hook + r2btn.rate = 2 + # + r3btn = RadioButton().definetext(w, '8 K/sec') + r3btn.on_hook = rate_hook + r3btn.rate = 3 + # + radios = [r1btn, r2btn, r3btn] + r1btn.group = r2btn.group = r3btn.group = radios + for r in radios: + if r.rate = G.rate: r.select(1) + # + # Other controls + # + G.recbtn = TimeOutToggleButton().definetext(w, 'Record') + G.recbtn.on_hook = record_on_hook + G.recbtn.timer_hook = record_timer_hook + G.recbtn.off_hook = record_off_hook + # + G.mutebtn = CheckButton().definetext(w, 'Mute') + G.mutebtn.select(not G.nomuting) + G.mutebtn.hook = mute_hook + # + G.playbtn = TimeOutToggleButton().definetext(w, 'Playback') + G.playbtn.on_hook = play_on_hook + G.playbtn.timer_hook = play_timer_hook + G.playbtn.off_hook = play_off_hook + # + G.gainbtn = ComplexSlider().define(w) + G.gainbtn.settexts(' Volume: ', ' ') + G.gainbtn.setminvalmax(0, G.gain, 255) + G.gainbtn.sethook(gain_hook) + # + G.sizebtn = Label().definetext(w, `len(G.data)` + ' bytes') + # + #G.showbtn = PushButton().definetext(w, 'Sound-o-gram...') + #G.showbtn.hook = show_hook + # + G.savebtn = PushButton().definetext(w, 'Save...') + G.savebtn.hook = save_hook + # + G.quitbtn = PushButton().definetext(w, 'Quit') + G.quitbtn.hook = quit_hook + G.playbtn.enable(0) + G.savebtn.enable(0) + #G.showbtn.enable(0) + start_vu() + G.window.realize() + # + # Event loop + # + while 1: + e = stdwin.getevent() + G.window.dispatch(e) + +# XXX Disabled... +def show_hook(self): + savetext = self.text + self.settext('Be patient...') + close_sogram() + stdwin.setdefwinsize(400, 300) + win = stdwin.open('Sound-o-gram') + G.sogram = Soundogram().define(win, G.data) + win.buttons = [G.sogram] + self.settext(savetext) + +def close_sogram(): + if G.sogram: + # Break circular references + G.sogram.win.buttons[:] = [] + del G.sogram.win + G.sogram = 0 + +def mute_hook(self): + G.nomuting = (not self.selected) + audio.setoutgain(G.nomuting * G.gain) + +def rate_hook(self): + G.rate = self.rate + audio.setrate(G.rate) + +def record_on_hook(self): + stop_vu() + close_sogram() + audio.setrate(G.rate) + audio.setoutgain(G.nomuting * G.gain) + audio.start_recording(BUFSIZE) + G.recording = 1 + G.playbtn.enable(0) + G.window.settimer(10 * BUFSIZE / Rates[G.rate]) + +def record_timer_hook(self): + if G.recording: + if audio.poll_recording(): + self.hilite(0) + record_off_hook(self) + else: + self.parent.settimer(5) + +def record_off_hook(self): + if not G.recording: + return + G.data = audio.stop_recording() + G.recording = 0 + G.sizebtn.settext(`len(G.data)` + ' bytes') + audio.setoutgain(G.nomuting * G.gain) + G.playbtn.enable((len(G.data) > 0)) + G.savebtn.enable((len(G.data) > 0)) + #G.showbtn.enable((len(G.data) > 0)) + G.window.settimer(0) + start_vu() + +def play_on_hook(self): + stop_vu() + audio.setrate(G.rate) + audio.setoutgain(G.gain) + audio.start_playing(G.data) + G.playing = 1 + G.recbtn.enable(0) + G.window.settimer(max(10 * len(G.data) / Rates[G.rate], 1)) + +def play_timer_hook(self): + if G.playing: + if audio.poll_playing(): + self.hilite(0) + play_off_hook(self) + else: + self.parent.settimer(5) + +def play_off_hook(self): + if not G.playing: + return + x = audio.stop_playing() + G.playing = 0 + audio.setoutgain(G.nomuting * G.gain) + G.recbtn.enable(1) + G.window.settimer(0) + start_vu() + +def gain_hook(self): + G.gain = self.val + if G.playing or G.nomuting: audio.setoutgain(G.gain) + +def save_hook(self): + if not G.data: + stdwin.fleep() + else: + prompt = 'Store sampled data on file: ' + try: + G.savefile = stdwin.askfile(prompt, G.savefile, 1) + except KeyboardInterrupt: + return + try: + fp = open(G.savefile, 'w') + fp.write(Magics[G.rate] + G.data) + except: + stdwin.message('Cannot create ' + file) + +def stop_vu(): + G.vubtn.stop() + +def start_vu(): + G.vubtn.start() + +Exit = 'exit' # exception + +def quit_hook(self): + raise Exit, 0 + +try: + try: + main() + finally: + audio.setoutgain(0) +except Exit, sts: + sys.exit(sts) diff --git a/demo/sgi/audio_stdwin/vumeter.py b/demo/sgi/audio_stdwin/vumeter.py new file mode 100755 index 0000000..1685ba2 --- /dev/null +++ b/demo/sgi/audio_stdwin/vumeter.py @@ -0,0 +1,35 @@ +#! /ufs/guido/bin/sgi/python + +import audio +import stdwin + +from VUMeter import VUMeter +from WindowParent import WindowParent +import MainLoop + +NBUFS=20 +BUFSIZE = NBUFS*48 +SCALE=128 + +class MyVUMeter() = VUMeter(): + def init_reactivity(self): + self.parent.need_mouse(self) + def mouse_down(self, detail): + if self.enabled: + self.stop() + else: + self.start() + def mouse_move(self, detail): pass + def mouse_up(self, detail): pass + +def main(): + audio.setrate(3) + audio.setoutgain(0) + w = WindowParent().create('VU Meter', (200, 100)) + v = MyVUMeter().define(w) + v.start() + w.realize() + while 1: + w.dispatch(stdwin.getevent()) + +main() diff --git a/demo/sgi/gl/README b/demo/sgi/gl/README new file mode 100644 index 0000000..f191cf5 --- /dev/null +++ b/demo/sgi/gl/README @@ -0,0 +1,22 @@ +These demos run only on SGI machines and require the 'gl' built-in module. +The demonstrate the abilities of SGI's GL library as well as the ease of +GL programming in Python. Most demos require the Z-buffer (aka +24-bitplane) option. + +backface Demonstrates the 'backface' GL function. + +kites Show 3 flying kites. Demonstrates the rendering speed + obtainable by Python programs. + +mclock A colorful clock with more options than you can + remember. Works on 8-bit machines (but allows more + colors on 24-bit machines). + +mixing Demonstrates the effect of color mixing: through + frequent color switching it gives the effect of white + light. + +nurbs A simple demonstration of the 'nurbs' GL functions. + +zrgb Displays a 3-D Gouraud-shaded figure which can be moved + around with the mouse. diff --git a/demo/sgi/gl/backface.py b/demo/sgi/gl/backface.py new file mode 100755 index 0000000..5936f75 --- /dev/null +++ b/demo/sgi/gl/backface.py @@ -0,0 +1,140 @@ +#! /ufs/guido/bin/sgi/python + +# backface +# +# draw a cube that can run with backface() turned on or off. +# cube is moved when LEFTMOUSE is pressed and mouse itself is moved. + +from gl import * +from DEVICE import * +from GL import * + +CUBE_SIZE = 200.0 +CUBE_OBJ = 1 + +def main () : + # + x = 0 + y = 0 + moveit = 0 + # + initialize() + # + while (1) : + # + while (qtest()) : + dev, val = qread() + # + if dev = ESCKEY : + backface(0) + return + # + elif dev = REDRAW : + reshapeviewport() + drawcube(x,y) + # + elif dev = LEFTMOUSE : + # + # LEFTMOUSE down + moveit = val + # + elif dev = BKEY : + backface(1) + drawcube(x,y) + # + elif dev = FKEY : + backface(0) + drawcube(x,y) + # + if moveit : + x = getvaluator(MOUSEX) + y = getvaluator(MOUSEY) + drawcube(x,y) + + +def initialize () : + foreground () + keepaspect (1, 1) + gid = winopen('backface') + winset(gid) + winconstraints() + # + doublebuffer() + gconfig() + shademodel(FLAT) + # + ortho(-1024.0, 1024.0, -1024.0, 1024.0, -1024.0, 1024.0) + # + qdevice(ESCKEY) + qdevice(REDRAW) + qdevice(LEFTMOUSE) + qdevice(BKEY) + qdevice(FKEY) + qenter(REDRAW,gid) + # + backface(1) + +# +# define a cube +def cube () : + # + # front face + pushmatrix() + translate(0.0,0.0,CUBE_SIZE) + color(RED) + rectf(-CUBE_SIZE,-CUBE_SIZE,CUBE_SIZE,CUBE_SIZE) + popmatrix() + # + # right face + pushmatrix() + translate(CUBE_SIZE, 0.0, 0.0) + rotate(900, 'y') + color(GREEN) + rectf(-CUBE_SIZE,-CUBE_SIZE,CUBE_SIZE,CUBE_SIZE) + popmatrix() + # + # back face + pushmatrix() + translate(0.0, 0.0, -CUBE_SIZE) + rotate(1800, 'y') + color(BLUE) + rectf(-CUBE_SIZE,-CUBE_SIZE,CUBE_SIZE,CUBE_SIZE) + popmatrix() + # + # left face + pushmatrix() + translate(-CUBE_SIZE, 0.0, 0.0) + rotate(-900, 'y') + color(CYAN) + rectf(-CUBE_SIZE,-CUBE_SIZE,CUBE_SIZE,CUBE_SIZE) + popmatrix() + # + # top face + pushmatrix() + translate(0.0, CUBE_SIZE, 0.0) + rotate(-900, 'x') + color(MAGENTA) + rectf(-CUBE_SIZE,-CUBE_SIZE,CUBE_SIZE,CUBE_SIZE) + popmatrix() + # + # bottom face + pushmatrix() + translate(0.0, -CUBE_SIZE, 0.0) + rotate(900, 'x') + color(YELLOW) + rectf(-CUBE_SIZE,-CUBE_SIZE,CUBE_SIZE,CUBE_SIZE) + popmatrix() + +def drawcube(x,y) : + # + pushmatrix() + rotate(2*x, 'x') + rotate(2*y, 'y') + color(BLACK) + clear() + cube() + popmatrix() + swapbuffers() + + +main () diff --git a/demo/sgi/gl/kites.py b/demo/sgi/gl/kites.py new file mode 100755 index 0000000..764ad2c --- /dev/null +++ b/demo/sgi/gl/kites.py @@ -0,0 +1,194 @@ +#! /ufs/guido/bin/sgi/python + +# *** This only works correctly on a 24 bit-plane machine. *** +# +# A simple Python program that tests the some parts of the +# GL library. It shows the speed that can be obtained when +# doing simple graphics. +# +# The bottleneck in this program is NOT Python but the graphics +# engine; i.e Python can feed the graphics pipeline fast enough +# on the 4D/25G. +# +# This program show 3 kites flying around the screen. It uses +# +# * bgnpolygon, endpolygon +# * v3, n3 +# * lmdef, lmbind +# +# Usage : +# +# ESC -> exit program +# MOUSE3 -> freeze toggle +# MOUSE2 -> one step (use this in freeze state) + +from GL import * +from gl import * +import DEVICE +from math import * + +# +# viewobj : sets the rotation, translation and scaling +# set appropiate material, call drawobject() +# +def viewobj (r, s, t, mat) : + pushmatrix() + rot (r * 10.0, 'X') + rot (r * 10.0, 'Y') + rot (r * 10.0, 'Z') + scale (s[0], s[1], s[2]) + translate (t[0], t[1], t[2]) + lmbind(MATERIAL, mat) + drawobject() + popmatrix() + +# +# makeobj : the contructor of the object +# +def mkobj () : + v0 = (-5.0 ,0.0, 0.0) + v1 = (0.0 ,5.0, 0.0) + v2 = (5.0 ,0.0, 0.0) + v3 = (0.0 ,2.0, 0.0) + n0 = (sqrt(2.0)/2.0, sqrt(2.0)/2.0, 0.0) + vn = ((v0, n0), (v1, n0), (v2, n0), (v3, n0)) + # + return vn + +# +# the object itself as an array of vertices and normals +# +kite = mkobj () + +# +# drawobject : draw a triangle. with bgnpolygon +# +def drawobject () : + # + bgnpolygon() + vnarray (kite) + endpolygon() + +# +# identity matrix +# +idmat=[1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0] + +# +# the rgb-value of light-blue +# +LightBlue = (43,169,255) + +# +# the different materials. +# +m1=[SPECULAR,0.0,0.0,0.6,DIFFUSE,0.0,0.0,0.8,SHININESS,20.0,LMNULL] +m2=[SPECULAR,0.8,0.0,0.1,DIFFUSE,0.8,0.0,0.3,SHININESS,120.0,LMNULL] +m3=[SPECULAR,0.0,1.0,0.0,DIFFUSE,0.0,0.6,0.0,SHININESS,120.0,LMNULL] + +# +# lightsources +# +light1 = [LCOLOR,1.0,1.0,1.0,POSITION,15.0,15.0,0.0,1.0,LMNULL] +light2 = [LCOLOR,1.0,1.0,1.0,POSITION,-15.0,15.0,0.0,1.0,LMNULL] + +# +# the lightmodel +# +model = [AMBIENT,0.2,0.2,0.2,LMNULL] + +# +# initgl : opens the window, configures the pipeline to 2buf and zbuf, +# sets the viewing, defines and binds the materials +# +def initgl () : + # + # open window + # + foreground () + keepaspect (1, 1) + prefposition (100, 500, 100, 500) + w = winopen ('PYTHON lights') + keepaspect (1, 1) + winconstraints() + # + # configure pipeline (zbuf, 2buf, GOURAUD and RGBmode) + # + zbuffer (1) + doublebuffer () + shademodel (GOURAUD) + RGBmode () + gconfig () + # + # define and bind materials (set perspective BEFORE loadmat !) + # + mmode(MVIEWING) + perspective (900, 1.0, 1.0, 20.0) + loadmatrix(idmat) + lmdef(DEFMATERIAL, 1, m1) + lmdef(DEFMATERIAL, 2, m2) + lmdef(DEFMATERIAL, 3, m3) + lmdef(DEFLIGHT, 1, light1) + lmdef(DEFLIGHT, 2, light2) + lmdef(DEFLMODEL, 1, model) + lmbind(LIGHT0,1) + lmbind(LIGHT1,2) + lmbind(LMODEL,1) + # + # set viewing + # + lookat (0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0) + # + # ask for the REDRAW and ESCKEY events + # + qdevice(DEVICE.MOUSE3) + qdevice(DEVICE.MOUSE2) + qdevice(DEVICE.REDRAW) + qdevice(DEVICE.ESCKEY) + +# +# GoForIT : use 2buf to redraw the object 2n times. index i is used as +# the (smoothly changing) rotation angle +# +def GoForIt(i) : + freeze = 1 + while 1 : + if freeze <> 0 : + i = i + 1 + # + # clear z-buffer and clear background to light-blue + # + zclear() + c3i (LightBlue) + clear() + # + # draw the 3 traiangles scaled above each other. + # + viewobj(float(i),[1.0,1.0,1.0],[1.0,1.0,1.0],1) + viewobj(float(i),[0.75,0.75,0.75],[0.0,2.0,2.0],2) + viewobj(float(i),[0.5,0.5,0.5],[0.0,4.0,4.0],3) + # + swapbuffers() + # + if qtest() <> 0 : + dev, val = qread() + if dev = DEVICE.ESCKEY : + break + elif dev = DEVICE.REDRAW : + reshapeviewport () + elif dev = DEVICE.MOUSE3 and val <> 0 : + freeze = 1 - freeze + elif dev = DEVICE.MOUSE2 and val <> 0 : + i = i + 1 + + +# the main program +# +def main () : + initgl () + GoForIt (0) + +# +# exec main +# +main () diff --git a/demo/sgi/gl/mclock.doc b/demo/sgi/gl/mclock.doc new file mode 100644 index 0000000..610e9ab --- /dev/null +++ b/demo/sgi/gl/mclock.doc @@ -0,0 +1,60 @@ +Newsgroups: cwi.sgi +Subject: Re: new clock +Distribution: cwi.sgi +References: <[email protected]> + +Last week I wrote: + +>For your enjoyment I have implemented a colorful clock. + +The clock has now been extended with some new facilities: a menu, an +alarm and a gong. These may require some explanation beyond what's in +the usage message. + +Menu +---- +The right mouse button now pops up a menu that allows you to turn the +seconds hand on or off and to switch the alarm off. + +Alarm +----- + +The left and middle buttons set the alarm. When it is on, the alarm +time is displayed as a time on a 24 hour clock in the bottom left +corner. It is also indicated by two red triangles, corresponding to the +little (hours) and big (minutes) hand. These hands can be moved around: +the left mouse button moves the minutes hand, the middle button moves +the hourds hand. Watch out for differences of twelve hours (always +check the digital display); these can be corrected by dragging the hours +hand once around the dial. + +When the alarm goes off, two things happen: a shell command specified on +the command line with the -a option is executed (in the background), and +the clock's colors change every two seconds, for five minutes. You can +also turn the alarm off by using the menu accessible through the right +mouse button. + +There is no default command for the -a option; if it is not specified, +only the changing of the colors happens. If you have an 8 ohm speaker +connected to the audio output of your Personal Iris, a suitable command +would be: + + mclock -a '/ufs/guido/bin/sgi/play /ufs/guido/lib/sounds/alarm' + +Gong +---- + +Some people like a clock that makes noises every hour, or even more +often. This is supported by the -g and -G options. With -g you specify +a shell command to be executed to sound the gong; with -G you can +specify the interval between gong calls, in seconds (default is one hour). +The shell command is executed in the background. It is given two +arguments: the hours (on a 24 hour clock!) and the minutes. The +executable Python script /ufs/guido/bin/sgi/chime is a suitable example. +Again, this only works if you have installed a speaker (I bet 8 ohm +speakers are going to be in demand!) + +-- +Guido van Rossum, Centre for Mathematics and Computer Science (CWI), Amsterdam [email protected] or ..!hp4nl!cwi.nl!guido or guido%[email protected] +"A thing of beauty is a joy till sunrise" diff --git a/demo/sgi/gl/mclock.py b/demo/sgi/gl/mclock.py new file mode 100755 index 0000000..806511c --- /dev/null +++ b/demo/sgi/gl/mclock.py @@ -0,0 +1,729 @@ +#! /ufs/guido/bin/sgi/python + +############################################################################# +# NOTA BENE: Before installing, fix TZDIFF to reflect your local time zone! # +############################################################################# + +# "M Clock" +# +# An implementation in software of an original design by Rob Juda. +# Clock implementation: Guido van Rossum. +# Alarm and Gong features: Sape Mullender. +# +# XXX TO DO: +# find out local time zone difference automatically +# add a date indicator +# allow multiple alarms +# allow the menu to change more parameters + +import sys + +from gl import * +from GL import * +from DEVICE import * +import time +import getopt +import string +import path +from math import pi +import math +import posix + +FULLC = 3600 # Full circle in 1/10-ths of a degree +MIDN = 900 # Angle of the 12 o'clock position +R, G, B = 0, 1, 2 # Indices of colors in RGB list + +HOUR = 3600 # Number of seconds per hour +MINUTE = 60 # Number of seconds per minute + +class struct(): pass # Class to define featureless structures +Gl = struct() # Object to hold writable global variables + +# Default constants (used in multiple places) + +SCREENBG = 127, 156, 191 +NPARTS = 9 +TITLE = 'M Clock' +TZDIFF = -1*HOUR # <--- change this to reflect your local time zone + +# Default parameters + +Gl.foreground = 0 # If set, run in the foreground +Gl.fullscreen = 0 # If set, run on full screen +Gl.tzdiff = TZDIFF # Seconds west of Greenwich (winter time) +Gl.nparts = NPARTS # Number of parts each circle is divided in (>= 2) +Gl.debug = 0 # If set, print debug output +Gl.doublebuffer = 1 # If set, use double buffering +Gl.update = 0 # Update interval; seconds hand is suppressed if > 1 +Gl.colorsubset = 0 # If set, display only a subset of the colors +Gl.cyan = 0 # If set, display cyan overlay (big hand) +Gl.magenta = 0 # If set, display magenta overlay (little hand) +Gl.yellow = 0 # If set, display yellow overlay (fixed background) +Gl.black = 0 # If set, display black overlay (hands) +Gl.colormap = 0 # If set, use colormap mode instead of RGB mode +Gl.warnings = 0 # If set, print warnings +Gl.title = '- - ' # Window title (default set later) +Gl.border = 1 # If set, use a window border (and title) +Gl.bg = 0, 0, 0 # Background color R, G, B value +Gl.iconic = 0 # Set in iconic state +Gl.fg = 255, 0, 0 # Alarm background RGB (either normal or alarm) +Gl.ox,Gl.oy = 0,0 # Window origin +Gl.cx,Gl.cy = 0,0 # Window size +Gl.alarm_set = 0 # Alarm on or off +Gl.alarm_on = 0 # Alarm is ringing +Gl.alarm_time = 0 # Alarm time in seconds after midnight +Gl.alarm_hours = 0 # Alarm hour setting, 24 hour clock +Gl.alarm_minutes = 0 # Alarm minutes setting +Gl.alarm_rgb = 0,0,0 # Alarm display RGB colors +Gl.alarm_cmd = '' # Command to execute when alarm goes off +Gl.mouse2down = 0 # Mouse button state +Gl.mouse3down = 0 # Mouse button state +Gl.gong_cmd = '' # Command to execute when chimes go off +Gl.gong_int = 3600 # Gong interval +Gl.indices = R, G, B # Colors (permuted when alarm is on) + +def main(): + # + sys.stdout = sys.stderr # All output is errors/warnings etc. + # + try: + args = getoptions() + except string.atoi_error, value: + usage(string.atoi_error, value) + except getopt.error, msg: + usage(getopt.error, msg) + # + if args: + realtime = 0 + hours = string.atoi(args[0]) + minutes = seconds = 0 + if args[1:]: minutes = string.atoi(args[1]) + if args[2:]: seconds = string.atoi(args[2]) + localtime = ((hours*60)+minutes)*60+seconds + else: + realtime = 1 + # + if Gl.title = '- - ': + if realtime: + Gl.title = TITLE + else: + title = '' + for arg in args: title = title + ' ' + arg + Gl.title = title[1:] + del title + # + wid = makewindow() + Gl.ox,Gl.oy = getorigin() + Gl.cx,Gl.cy = getsize() + initmenu() + clearall() + # + if not Gl.update: + Gl.update = 60 + # + if Gl.update <= 1: + Gl.timernoise = 6 + else: + Gl.timernoise = 60 + noise(TIMER0, Gl.timernoise) + # + qdevice(WINSHUT) + qdevice(WINQUIT) + qdevice(ESCKEY) + if realtime: + qdevice(TIMER0) + qdevice(REDRAW) + qdevice(WINFREEZE) + qdevice(WINTHAW) + qdevice(MENUBUTTON) # MOUSE1 + qdevice(MOUSE3) # Left button + qdevice(MOUSE2) # Middle button + unqdevice(INPUTCHANGE) + # + lasttime = 0 + Gl.change = 1 + while 1: + if realtime: + localtime = time.time() - Gl.tzdiff + if Gl.alarm_set: + if localtime%(24*HOUR) = Gl.alarm_time: + # Ring the alarm! + if Gl.debug: + print 'Rrrringg!' + Gl.alarm_on = 1 + if Gl.alarm_cmd <> '': + d = posix.system(Gl.alarm_cmd+' '+`Gl.alarm_time/3600`+' '+`(Gl.alarm_time/60)%60` + ' &') + Gl.change = 1 + clearall() + if Gl.alarm_on: + if (localtime - Gl.alarm_time) % (24*HOUR) > 300: + # More than 5 minutes away from alarm + Gl.alarm_on = 0 + if Gl.debug: + print 'Alarm turned off' + Gl.change = 1 + clearall() + Gl.indices = R, G, B + else: + if localtime % 2 = 0: + # Permute color indices + Gl.indices = Gl.indices[2:] + Gl.indices[:2] + Gl.change = 1 + if Gl.gong_cmd <> '' and localtime%Gl.gong_int = 0: + d = posix.system(Gl.gong_cmd+' '+`(localtime/3600)%24`+' '+`(localtime/60)%60` + ' &') + if localtime/Gl.update <> lasttime/Gl.update: + if Gl.debug: print 'new time' + Gl.change = 1 + if Gl.change: + if Gl.debug: print 'drawing' + doit(localtime) + lasttime = localtime + Gl.change = 0 + dev, data = qread() + if Gl.debug and dev <> TIMER0: + print dev, data + if dev = TIMER0: + if Gl.debug > 1: + print dev, data + elif dev = MOUSE3: + mousex = getvaluator(MOUSEX) + mousey = getvaluator(MOUSEY) + if mouseclick(3, data, mousex, mousey): + Gl.change = 1 + elif dev = MOUSE2: + mousex = getvaluator(MOUSEX) + mousey = getvaluator(MOUSEY) + if mouseclick(2, data, mousex, mousey): + Gl.change = 1 + elif dev = MOUSEX: + mousex = data + if Gl.mouse2down: + mouse2track(mousex, mousey) + if Gl.mouse3down: + mouse3track(mousex, mousey) + elif dev = MOUSEY: + mousey = data + if Gl.mouse2down: + mouse2track(mousex, mousey) + if Gl.mouse3down: + mouse3track(mousex, mousey) + elif dev = REDRAW or dev = REDRAWICONIC: + if Gl.debug: + if dev = REDRAW: print 'REDRAW' + else: print 'REDRAWICONIC' + reshapeviewport() + Gl.ox,Gl.oy = getorigin() + Gl.cx,Gl.cy = getsize() + Gl.change = 1 + clearall() + elif dev = MENUBUTTON: + if Gl.debug: print 'MENUBUTTON' + handlemenu() + elif dev = WINFREEZE: + if Gl.debug: print 'WINFREEZE' + Gl.iconic = 1 + noise(TIMER0, 60*60) # Redraw every 60 seconds only + elif dev = WINTHAW: + if Gl.debug: print 'WINTHAW' + Gl.iconic = 0 + noise(TIMER0, Gl.timernoise) + Gl.change = 1 + elif dev = ESCKEY or dev = WINSHUT or dev = WINQUIT: + if Gl.debug: print 'Exit' + sys.exit(0) + +def getoptions(): + optlist, args = getopt.getopt(sys.argv[1:], 'A:a:B:bc:dFfG:g:n:sT:t:u:wCMYK') + for optname, optarg in optlist: + if optname = '-A': + Gl.fg = eval(optarg) # Should be (r,g,b) + elif optname = '-a': + Gl.alarm_cmd = optarg + elif optname = '-B': + Gl.bg = eval(optarg) # Should be (r,g,b) + elif optname = '-b': + Gl.border = 0 + elif optname = '-c': + Gl.colormap = string.atoi(optarg) + elif optname = '-d': + Gl.debug = Gl.debug + 1 + Gl.warnings = 1 + elif optname = '-F': + Gl.foreground = 1 + elif optname = '-f': + Gl.fullscreen = 1 + elif optname = '-G': + Gl.gong_int = 60*string.atoi(optarg) + elif optname = '-g': + Gl.gong_cmd = optarg + elif optname = '-n': + Gl.nparts = string.atoi(optarg) + elif optname = '-s': + Gl.doublebuffer = 0 + elif optname = '-T': + Gl.title = optarg + elif optname = '-t': + Gl.tzdiff = string.atoi(optarg) + elif optname = '-u': + Gl.update = string.atoi(optarg) + elif optname = '-w': + Gl.warnings = 1 + elif optname = '-C': + Gl.cyan = Gl.colorsubset = 1 + elif optname = '-M': + Gl.magenta = Gl.colorsubset = 1 + elif optname = '-Y': + Gl.yellow = Gl.colorsubset = 1 + elif optname = '-K': + Gl.black = Gl.colorsubset = 1 + else: + print 'Unsupported option', optname + return args + +def usage(exc, msg): + if sys.argv: + progname = path.basename(sys.argv[0]) + else: + progname = 'mclock' + # + print progname + ':', + if exc = string.atoi_error: + print 'non-numeric argument:', + print msg + # + print 'usage:', progname, '[options] [hh [mm [ss]]]' + # + print '-A r,g,b : alarm background red,green,blue [255,0,0]' + print '-a cmd : shell command executed when alarm goes off' + print '-B r,g,b : background red,green,blue [0,0,0]' + print ' (-B SCREENBG uses the default screen background)' + print '-b : suppress window border and title' + print '-c cmapid : select explicit colormap' + print '-d : more debug output (implies -F, -w)' + print '-F : run in foreground' + print '-f : use full screen' + print '-G intrvl : interval between chimes in minutes [60]' + print '-g cmd : shell command executed when chimes go off' + print '-s : single buffer mode' + print '-w : print various warnings' + print '-n nparts : number of parts [' + `NPARTS` + ']' + print '-T title : alternate window title [\'' + TITLE + '\']' + print '-t tzdiff : time zone difference [' + `TZDIFF` + ']' + print '-u update : update interval [60]' + print '-CMYK : Cyan, Magenta, Yellow or blacK overlay only' + print 'if hh [mm [ss]] is specified, display that time statically' + print 'on machines with < 12 bitplanes, -c and -s are forced on' + # + sys.exit(2) + +def doit(localtime): + hands = makehands(localtime) + list = makelist(hands) + render(list, hands) + +def makehands(localtime): + localtime = localtime % (12*HOUR) + seconds_hand = MIDN + FULLC - (localtime*60) % FULLC + big_hand = (MIDN + FULLC - (localtime%HOUR)) % FULLC + little_hand = (MIDN + FULLC - ((localtime/12) % HOUR)) % FULLC + return little_hand, big_hand, seconds_hand + +def makelist(little_hand, big_hand, seconds_hand): + total = [] + if Gl.cyan or not Gl.colorsubset: + total = total + makesublist(big_hand, Gl.indices[0]) + if Gl.magenta or not Gl.colorsubset: + total = total + makesublist(little_hand, Gl.indices[1]) + if Gl.yellow or not Gl.colorsubset: + total = total + makesublist(MIDN, Gl.indices[2]) + total.sort() + return total + +def makesublist(first, icolor): + list = [] + alpha = FULLC/Gl.nparts + a = first - alpha/2 + for i in range(Gl.nparts): + angle = (a + i*alpha + FULLC) % FULLC + value = 255*(Gl.nparts-1-i)/(Gl.nparts-1) + list.append(angle, icolor, value) + list.sort() + a, icolor, value = list[0] + if a <> 0: + a, icolor, value = list[len(list)-1] + t = 0, icolor, value + list.insert(0, t) + return list + +def rgb_fg(): + return Gl.fg + # Obsolete code: + if Gl.alarm_on: + return Gl.bg + else: + return Gl.fg + +def rgb_bg(): + return Gl.bg + # Obsolete code: + if Gl.alarm_on: + return Gl.fg + else: + return Gl.bg + +def clearall(): + Gl.c3i(rgb_bg()) + clear() + if Gl.doublebuffer: + swapbuffers() + clear() + +def draw_alarm(color): + frontbuffer(TRUE) + Gl.c3i(color) + pushmatrix() + rotate(-((Gl.alarm_time/12)%3600), 'z') + bgnpolygon() + v2f( 0.00,1.00) + v2f( 0.04,1.05) + v2f(-0.04,1.05) + endpolygon() + popmatrix() + # + pushmatrix() + rotate(-((Gl.alarm_time)%3600), 'z') + bgnpolygon() + v2f( 0.00,1.05) + v2f( 0.07,1.10) + v2f(-0.07,1.10) + endpolygon() + popmatrix() + # + cmov2(-1.06, -1.06) + charstr(string.rjust(`Gl.alarm_time/3600`,2)) + charstr(':') + charstr(string.zfill((Gl.alarm_time/60)%60,2)) + frontbuffer(FALSE) + +def render(list, (little_hand, big_hand, seconds_hand)): + # + if Gl.colormap: + resetindex() + # + if not list: + Gl.c3i(255, 255, 255) # White + circf(0.0, 0.0, 1.0) + else: + list.append(3600, 0, 255) # Sentinel + # + rgb = [255, 255, 255] + a_prev = 0 + for a, icolor, value in list: + if a <> a_prev: + [r, g, b] = rgb + if Gl.debug > 1: + print rgb, a_prev, a + Gl.c3i(r, g, b) + arcf(0.0, 0.0, 1.0, a_prev, a) + rgb[icolor] = value + a_prev = a + # + if Gl.black or not Gl.colorsubset: + # + # Draw the hands -- in black + # + Gl.c3i(0, 0, 0) + # + if Gl.update = 1 and not Gl.iconic: + # Seconds hand is only drawn if we update every second + pushmatrix() + rotate(seconds_hand, 'z') + bgnline() + v2f(0.0, 0.0) + v2f(1.0, 0.0) + endline() + popmatrix() + # + pushmatrix() + rotate(big_hand, 'z') + rectf(0.0, -0.01, 0.97, 0.01) + circf(0.0, 0.0, 0.01) + circf(0.97, 0.0, 0.01) + popmatrix() + # + pushmatrix() + rotate(little_hand, 'z') + rectf(0.04, -0.02, 0.63, 0.02) + circf(0.04, 0.0, 0.02) + circf(0.63, 0.0, 0.02) + popmatrix() + # + # Draw the alarm time, if set or being set + # + if Gl.alarm_set: + draw_alarm(rgb_fg()) + # + if Gl.doublebuffer: swapbuffers() + +def makewindow(): + # + if Gl.debug or Gl.foreground: + foreground() + # + if Gl.fullscreen: + # XXX Should find out true screen size using getgdesc() + prefposition(0, 1279, 0, 1023) + else: + keepaspect(1, 1) + minsize(64, 64) + # + if not Gl.border: + noborder() + wid = winopen(Gl.title) + # + if not Gl.fullscreen: + keepaspect(1, 1) + minsize(10, 10) + maxsize(2000, 2000) + iconsize(66, 66) + winconstraints() + # + nplanes = getplanes() + nmaps = getgdesc(GD_NMMAPS) + if Gl.warnings: + print nplanes, 'color planes,', nmaps, 'color maps' + # + if nplanes < 12 or Gl.colormap: + if not Gl.colormap: + Gl.colormap = nmaps - 1 + if Gl.warnings: + print 'not enough color planes available', + print 'for RGB mode; forcing colormap mode' + print 'using color map number', Gl.colormap + if not Gl.colorsubset: + needed = 3 + else: + needed = Gl.cyan + Gl.magenta + Gl.yellow + needed = needed*Gl.nparts + if Gl.bg <> (0, 0, 0): + needed = needed+1 + if Gl.fg <> (0, 0, 0): + needed = needed+1 + if Gl.doublebuffer: + if needed > available(nplanes/2): + Gl.doublebuffer = 0 + if Gl.warnings: + print 'not enough colors available', + print 'for double buffer mode;', + print 'forcing single buffer mode' + else: + nplanes = nplanes/2 + if needed > available(nplanes): + # Do this warning always + print 'still not enough colors available;', + print 'parts will be left white' + print '(needed', needed, 'but have only', + print available(nplanes), 'colors available)' + # + if Gl.doublebuffer: + doublebuffer() + gconfig() + # + if Gl.colormap: + Gl.c3i = pseudo_c3i + fixcolormap() + else: + Gl.c3i = c3i + RGBmode() + gconfig() + # + if Gl.fullscreen: + # XXX Should find out true screen size using getgdesc() + ortho2(-1.1*1.280, 1.1*1.280, -1.1*1.024, 1.1*1.024) + else: + ortho2(-1.1, 1.1, -1.1, 1.1) + # + return wid + +def available(nplanes): + return pow(2, nplanes) - 1 # Reserve one pixel for black + +def fixcolormap(): + multimap() + gconfig() + nplanes = getplanes() + if Gl.warnings: + print 'multimap mode has', nplanes, 'color planes' + imap = Gl.colormap + Gl.startindex = pow(2, nplanes) - 1 + Gl.stopindex = 1 + setmap(imap) + mapcolor(0, 0, 0, 0) # Fixed entry for black + if Gl.bg <> (0, 0, 0): + r, g, b = Gl.bg + mapcolor(1, r, g, b) # Fixed entry for Gl.bg + Gl.stopindex = 2 + if Gl.fg <> (0, 0, 0): + r, g, b = Gl.fg + mapcolor(2, r, g, b) # Fixed entry for Gl.fg + Gl.stopindex = 3 + Gl.overflow_seen = 0 + resetindex() + +def resetindex(): + Gl.index = Gl.startindex + +r0g0b0 = (0, 0, 0) + +def pseudo_c3i(rgb): + if rgb = r0g0b0: + index = 0 + elif rgb = Gl.bg: + index = 1 + elif rgb = Gl.fg: + index = 2 + else: + index = definecolor(rgb) + color(index) + +def definecolor(rgb): + index = Gl.index + if index < Gl.stopindex: + if Gl.debug: print 'definecolor hard case', rgb + # First see if we already have this one... + for index in range(Gl.stopindex, Gl.startindex+1): + if rgb = getmcolor(index): + if Gl.debug: print 'return', index + return index + # Don't clobber reserverd colormap entries + if not Gl.overflow_seen: + # Shouldn't happen any more, hence no Gl.warnings test + print 'mclock: out of colormap entries' + Gl.overflow_seen = 1 + return Gl.stopindex + r, g, b = rgb + if Gl.debug > 1: print 'mapcolor', (index, r, g, b) + mapcolor(index, r, g, b) + Gl.index = index - 1 + return index + +# Compute n**i +def pow(n, i): + x = 1 + for j in range(i): x = x*n + return x + +def mouseclick(mouse, updown, x, y): + if updown = 1: + # mouse button came down, start tracking + if Gl.debug: + print 'mouse', mouse, 'down at', x, y + if mouse = 2: + Gl.mouse2down = 1 + mouse2track(x, y) + elif mouse = 3: + Gl.mouse3down = 1 + mouse3track(x, y) + else: + print 'fatal error' + qdevice(MOUSEX) + qdevice(MOUSEY) + return 0 + else: + # mouse button came up, stop tracking + if Gl.debug: + print 'mouse', mouse, 'up at', x, y + unqdevice(MOUSEX) + unqdevice(MOUSEY) + if mouse = 2: + mouse2track(x, y) + Gl.mouse2down = 0 + elif mouse = 3: + mouse3track(x, y) + Gl.mouse3down = 0 + else: + print 'fatal error' + Gl.alarm_set = 1 + return 1 + +def mouse3track(x, y): + # first compute polar coordinates from x and y + cx, cy = Gl.ox + Gl.cx/2, Gl.oy + Gl.cy/2 + x, y = x - cx, y - cy + if (x, y) = (0, 0): return # would cause an exception + minutes = int(30.5 + 30.0*math.atan2(float(-x), float(-y))/pi) + if minutes = 60: minutes = 0 + a,b = Gl.alarm_minutes/15, minutes/15 + if (a,b) = (0,3): + # Moved backward through 12 o'clock: + Gl.alarm_hours = Gl.alarm_hours - 1 + if Gl.alarm_hours < 0: Gl.alarm_hours = Gl.alarm_hours + 24 + if (a,b) = (3,0): + # Moved forward through 12 o'clock: + Gl.alarm_hours = Gl.alarm_hours + 1 + if Gl.alarm_hours >= 24: Gl.alarm_hours = Gl.alarm_hours - 24 + Gl.alarm_minutes = minutes + seconds = Gl.alarm_hours * HOUR + Gl.alarm_minutes * MINUTE + if seconds <> Gl.alarm_time: + draw_alarm(rgb_bg()) + Gl.alarm_time = seconds + draw_alarm(rgb_fg()) + +def mouse2track(x, y): + # first compute polar coordinates from x and y + cx, cy = Gl.ox + Gl.cx/2, Gl.oy + Gl.cy/2 + x, y = x - cx, y - cy + if (x, y) = (0, 0): return # would cause an exception + hours = int(6.5 - float(Gl.alarm_minutes)/60.0 + 6.0*math.atan2(float(-x), float(-y))/pi) + if hours = 12: hours = 0 + if (Gl.alarm_hours,hours) = (0,11): + # Moved backward through midnight: + Gl.alarm_hours = 23 + elif (Gl.alarm_hours,hours) = (12,11): + # Moved backward through noon: + Gl.alarm_hours = 11 + elif (Gl.alarm_hours,hours) = (11,0): + # Moved forward through noon: + Gl.alarm_hours = 12 + elif (Gl.alarm_hours,hours) = (23,0): + # Moved forward through midnight: + Gl.alarm_hours = 0 + elif Gl.alarm_hours < 12: + Gl.alarm_hours = hours + else: + Gl.alarm_hours = hours + 12 + seconds = Gl.alarm_hours * HOUR + Gl.alarm_minutes * MINUTE + if seconds <> Gl.alarm_time: + draw_alarm(rgb_bg()) + Gl.alarm_time = seconds + draw_alarm(rgb_fg()) + +def initmenu(): + Gl.pup = pup = newpup() + addtopup(pup, 'M Clock%t|Alarm On/Off|Seconds Hand On/Off|Quit', 0) + +def handlemenu(): + item = dopup(Gl.pup) + if item = 1: + # Toggle alarm + if Gl.alarm_set: + Gl.alarm_set = 0 + Gl.alarm_on = 0 + else: + Gl.alarm_set = 1 + Gl.change = 1 + clearall() + elif item = 2: + # Toggle Seconds Hand + if Gl.update = 1: + Gl.update = 60 + Gl.timernoise = 60 + else: + Gl.update = 1 + Gl.timernoise = 6 + Gl.change = 1 + elif item = 3: + if Gl.debug: print 'Exit' + sys.exit(0) + +main() diff --git a/demo/sgi/gl/mixing.py b/demo/sgi/gl/mixing.py new file mode 100755 index 0000000..294e65f --- /dev/null +++ b/demo/sgi/gl/mixing.py @@ -0,0 +1,116 @@ +#! /ufs/guido/bin/sgi/python + +# Use Gouraud shading to mix colors. Requires Z-buffer. +# It changes the color assignments so fast that you see white. +# Left button pauses, middle rotates the square. ESC to quit. +# Experiment with a larger window (too slow) or smaller window (really white). + +from GL import * +from gl import * +import DEVICE +from math import * + +# +# tekenvlak : draw a square. with bgnpolygon +# +def tekenvlak (vc) : + bgnpolygon() + #vcarray (vc) + for i in vc : + c3f (i[1]) + v3f (i[0]) + endpolygon() + +# +# tekendoos : draw a box +# +def tekendoos (col) : + v = [(-5.0,0.0,0.0),(0.0,5.0,0.0),(5.0,0.0,0.0),(0.0,-5.0,0.0)] + vc = [(v[0],col[0]),(v[1],col[1]),(v[2],col[2]),(v[3],col[1])] + tekenvlak (vc) + +# +# initialize gl +# +def initgl () : + # + # open window + # + foreground () + keepaspect (1, 1) + prefposition (100, 500, 100, 500) + w = winopen ('PYTHON RGB') + keepaspect (1, 1) + winconstraints() + # + # configure pipeline (2buf, GOURAUD and RGBmode) + # + doublebuffer () + zbuffer (1) + shademodel (GOURAUD) + RGBmode () + gconfig () + # + # set viewing + # + perspective (900, 1, 1.0, 10.0) + polarview (10.0, 0, 0, 0) + # + # ask for the REDRAW and ESCKEY events + # + qdevice(DEVICE.MOUSE2) + qdevice(DEVICE.MOUSE3) + qdevice(DEVICE.REDRAW) + qdevice(DEVICE.ESCKEY) + + +# +# the color black +# +black = 0 +# +# GoForIT : use 2buf to redraw the object 2n times. index i is used as +# the (smoothly changing) rotation angle +# +def GoForIt(i) : + col = [(255.0,0.0,0.0), (0.0,255.0,0.0), (0.0,0.0,255.0)] + twist = 0 + freeze = 1 + while 1 : + if freeze <> 0 : + col[0],col[1],col[2] = col[1],col[2],col[0] + # + # clear z-buffer and clear background to light-blue + # + zclear() + cpack (black) + clear() + # + tekendoos (col) + # + swapbuffers() + # + if qtest() <> 0 : + dev, val = qread() + if dev = DEVICE.ESCKEY : + break + elif dev = DEVICE.REDRAW : + reshapeviewport () + elif dev = DEVICE.MOUSE2 and val <> 0 : + twist = twist + 30 + perspective (900, 1, 1.0, 10.0) + polarview (10.0, 0, 0, twist) + elif dev = DEVICE.MOUSE3 and val <> 0 : + freeze = 1 - freeze + + +# the main program +# +def main () : + initgl () + GoForIt (0) + +# +# exec main +# +main () diff --git a/demo/sgi/gl/nurbs.py b/demo/sgi/gl/nurbs.py new file mode 100755 index 0000000..ee48e23 --- /dev/null +++ b/demo/sgi/gl/nurbs.py @@ -0,0 +1,171 @@ +#! /ufs/guido/bin/sgi/python + +# Rotate a 3D surface created using NURBS. +# +# Press left mouse button to toggle surface trimming. +# Press ESC to quit. +# +# See the GL manual for an explanation of NURBS. + +from gl import * +from GL import * +from DEVICE import * + +TRUE = 1 +FALSE = 0 +ORDER = 4 + +idmat = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1] + +surfknots = [-1, -1, -1, -1, 1, 1, 1, 1] + +def make_ctlpoints(): + c = [] + # + ci = [] + ci.append(-2.5, -3.7, 1.0) + ci.append(-1.5, -3.7, 3.0) + ci.append(1.5, -3.7, -2.5) + ci.append(2.5, -3.7, -0.75) + c.append(ci) + # + ci = [] + ci.append(-2.5, -2.0, 3.0) + ci.append(-1.5, -2.0, 4.0) + ci.append(1.5, -2.0, -3.0) + ci.append(2.5, -2.0, 0.0) + c.append(ci) + # + ci = [] + ci.append(-2.5, 2.0, 1.0) + ci.append(-1.5, 2.0, 0.0) + ci.append(1.5, 2.0, -1.0) + ci.append(2.5, 2.0, 2.0) + c.append(ci) + # + ci = [] + ci.append(-2.5, 2.7, 1.25) + ci.append(-1.5, 2.7, 0.1) + ci.append(1.5, 2.7, -0.6) + ci.append(2.5, 2.7, 0.2) + c.append(ci) + # + return c + +ctlpoints = make_ctlpoints() + +trimknots = [0., 0., 0., 1., 1., 2., 2., 3., 3., 4., 4., 4.] + +def make_trimpoints(): + c = [] + c.append(1.0, 0.0, 1.0) + c.append(1.0, 1.0, 1.0) + c.append(0.0, 2.0, 2.0) + c.append(-1.0, 1.0, 1.0) + c.append(-1.0, 0.0, 1.0) + c.append(-1.0, -1.0, 1.0) + c.append(0.0, -2.0, 2.0) + c.append(1.0, -1.0, 1.0) + c.append(1.0, 0.0, 1.0) + return c + +trimpoints = make_trimpoints() + +def main(): + init_windows() + setup_queue() + make_lights() + init_view() + # + set_scene() + setnurbsproperty( N_ERRORCHECKING, 1.0 ) + setnurbsproperty( N_PIXEL_TOLERANCE, 50.0 ) + trim_flag = 0 + draw_trim_surface(trim_flag) + # + while 1: + while qtest(): + dev, val = qread() + if dev = ESCKEY: + return + elif dev = WINQUIT: + dglclose(-1) # this for DGL only + return + elif dev = REDRAW: + reshapeviewport() + set_scene() + draw_trim_surface(trim_flag) + elif dev = LEFTMOUSE: + if val: + trim_flag = (not trim_flag) + set_scene() + draw_trim_surface(trim_flag) + +def init_windows(): + foreground() + #prefposition(0, 500, 0, 500) + wid = winopen('nurbs') + wintitle('NURBS Surface') + doublebuffer() + RGBmode() + gconfig() + lsetdepth(0x000, 0x7fffff) + zbuffer( TRUE ) + +def setup_queue(): + qdevice(ESCKEY) + qdevice(REDRAW) + qdevice(RIGHTMOUSE) + qdevice(WINQUIT) + qdevice(LEFTMOUSE) #trimming + +def init_view(): + mmode(MPROJECTION) + ortho( -4., 4., -4., 4., -4., 4. ) + # + mmode(MVIEWING) + loadmatrix(idmat) + # + lmbind(MATERIAL, 1) + +def set_scene(): + lmbind(MATERIAL, 0) + RGBcolor(150,150,150) + lmbind(MATERIAL, 1) + clear() + zclear() + # + rotate( 100, 'y' ) + rotate( 100, 'z' ) + +def draw_trim_surface(trim_flag): + bgnsurface() + nurbssurface(surfknots, surfknots, ctlpoints, ORDER, ORDER, N_XYZ) + if trim_flag: + bgntrim() + nurbscurve(trimknots, trimpoints, ORDER-1, N_STW) + endtrim() + endsurface() + swapbuffers() + +def make_lights(): + lmdef(DEFLMODEL,1,[]) + lmdef(DEFLIGHT,1,[]) + # + # define material #1 + # + a = [] + a = a + [EMISSION, 0.0, 0.0, 0.0] + a = a + [AMBIENT, 0.1, 0.1, 0.1] + a = a + [DIFFUSE, 0.6, 0.3, 0.3] + a = a + [SPECULAR, 0.0, 0.6, 0.0] + a = a + [SHININESS, 2.0] + a = a + [LMNULL] + lmdef(DEFMATERIAL, 1, a) + # + # turn on lighting + # + lmbind(LIGHT0, 1) + lmbind(LMODEL, 1) + +main() diff --git a/demo/sgi/gl/zrgb.py b/demo/sgi/gl/zrgb.py new file mode 100755 index 0000000..c3f934a --- /dev/null +++ b/demo/sgi/gl/zrgb.py @@ -0,0 +1,169 @@ +#! /ufs/guido/bin/sgi/python + +# zrgb (Requires Z buffer.) +# +# This program demostrates zbuffering 3 intersecting RGB polygons while +# in doublebuffer mode where, movement of the mouse with the LEFTMOUSE +# button depressed will, rotate the 3 polygons. This is done by compound +# rotations allowing continuous screen-oriented rotations. +# +# Press the "Esc" key to exit. + +from gl import * +from GL import * +from DEVICE import * + + +objmat=[1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0] + +idmat=[1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0] + +def main() : + # + # old and new mouse position + # + # + mode = 0 + omx = 0 + mx = 0 + omy = 0 + my = 0 + # + initialize () + # + draw_scene (objmat) + # + while (1) : + # + dev, val = qread() + # + if dev = ESCKEY : + if val : + break + # exit when key is going up, not down + # this avoids the scenario where a window + # underneath this program's window + # would otherwise "eat up" the up- + # event of the Esc key being released + return + # + elif dev = REDRAW : + reshapeviewport() + draw_scene(objmat) + # + elif dev = LEFTMOUSE: + omx = mx + omy = my + if val : + mode = 1 + else : + mode = 0 + elif dev = MOUSEX : + omx = mx + mx = val + #print omx, mx + objmat = update_scene(objmat,mx,my,omx,omy,mode) + # + elif dev = MOUSEY : + omy = my + my = val + #print omy, my + objmat = update_scene(objmat,mx,my,omx,omy,mode) + # + + +def initialize () : + # + foreground () + keepaspect(5, 4) + w = winopen('Zbuffered RGB') + # + doublebuffer() + RGBmode() + gconfig() + zbuffer(1) + lsetdepth(0x0, 0x7FFFFF) + # + qdevice(ESCKEY) + qdevice(LEFTMOUSE) + qdevice(MOUSEX) + qdevice(MOUSEY) + +def update_scene (mat, mx, my, omx, omy, mode) : + # + if mode = 1 : + mat = orient(mat, mx, my, omx, omy) + draw_scene(mat) + return mat + +def orient (mat, mx, my, omx, omy) : + # + # + pushmatrix() + loadmatrix(idmat) + # + if mx - omx : rot (float (mx - omx), 'y') + if omy - my : rot (float (omy - my), 'x') + # + multmatrix(mat) + mat = getmatrix() + # + # + popmatrix() + # + return mat + +def draw_scene (mat) : + RGBcolor(40, 100, 200) + clear() + zclear() + # + perspective(400, 1.25, 30.0, 60.0) + translate(0.0, 0.0, -40.0) + multmatrix(mat) + # + # skews original view to show all polygons + # + rotate(-580, 'y') + draw_polys() + # + swapbuffers() + +polygon1 = [(-10.0,-10.0,0.0),(10.0,-10.0,0.0),(-10.0,10.0,0.0)] + +polygon2 = [(0.0,-10.0,-10.0),(0.0,-10.0,10.0),(0.0,5.0,-10.0)] + +polygon3 = [(-10.0,6.0,4.0),(-10.0,3.0,4.0),(4.0,-9.0,-10.0),(4.0,-6.0,-10.0)] + +def draw_polys(): + bgnpolygon() + cpack(0x0) + v3f(polygon1[0]) + cpack(0x007F7F7F) + v3f(polygon1[1]) + cpack(0x00FFFFFF) + v3f(polygon1[2]) + endpolygon() + # + bgnpolygon() + cpack(0x0000FFFF) + v3f(polygon2[0]) + cpack(0x007FFF00) + v3f(polygon2[1]) + cpack(0x00FF0000) + v3f(polygon2[2]) + endpolygon() + # + bgnpolygon() + cpack(0x0000FFFF) + v3f(polygon3[0]) + cpack(0x00FF00FF) + v3f(polygon3[1]) + cpack(0x00FF0000) + v3f(polygon3[2]) + cpack(0x00FF00FF) + v3f(polygon3[3]) + endpolygon() + + +main () diff --git a/demo/sgi/gl_panel/README b/demo/sgi/gl_panel/README new file mode 100644 index 0000000..889a2cf --- /dev/null +++ b/demo/sgi/gl_panel/README @@ -0,0 +1,23 @@ +This directory contains demos that use the Panel Library by NASA Ames. +They only run on SGI machines and require the 'pnl' and 'gl' built-in +modules. Each subdirectory contains one demo. + +apanel A trivial user interface to the audio capabilities of + the 4D/25 (Personal IRIS). Lets you record a sample and + play it back at different volumes. Requires the 'audio' + built-in module. + +flying A large demonstration that can display several + differently shaped objects through space. Control + panels let you manipulate light sources, material + properties and drawing modes. + +nurbs A demo of the capabilities of the GL 'nurbs' functions + that can display the control points. (It was intended + to let you move these as well, but there was a problem + with the mapping of mouse movements in a 3-D world.) + +twoview A demo of GL's transformation primitives. Two views on + a scene are given, and the position and orientation of a + viewer in one of the views can be changed through + various buttons and dials in a control panel. diff --git a/demo/sgi/gl_panel/apanel/apanel.py b/demo/sgi/gl_panel/apanel/apanel.py new file mode 100755 index 0000000..de9a710 --- /dev/null +++ b/demo/sgi/gl_panel/apanel/apanel.py @@ -0,0 +1,63 @@ +#! /ufs/guido/bin/sgi/python + +# A (too) trivial control panel to record a sound sample and play it back. +# Requires the audio built-in module. +# Requires the NASA AMES Panel Library. + +import sys + +import gl +import panel + +panel.block(1) + +import audio + +def main(): + gl.foreground() + gl.noport() + #gl.prefposition(700, 850, 950, 970) + wid = gl.winopen('audio demo') + # + panels = panel.defpanellist('apanel.s') # XXX + p = panels[0] + p.playbackbutton.back = p + p.recordbutton.back = p + p.sample = '' + # + def quit(a): + sys.exit(0) + # + p.quitbutton.downfunc = quit + # + def playback(a): + p = a.back + gain = int(255.0*p.outputgain.val) + a.val = 1.0 + a.fixact() + panel.drawpanel() + audio.setoutgain(gain) + audio.write(p.sample) + audio.setoutgain(0) + a.val = 0.0 + a.fixact() + # + p.playbackbutton.downfunc = playback + # + def record(a): + p = a.back + size = int(10.0 * 8192.0 * p.recordsize.val) + a.val = 1.0 + a.fixact() + panel.drawpanel() + audio.setoutgain(0) + p.sample = audio.read(size) + a.val = 0.0 + a.fixact() + # + p.recordbutton.downfunc = record + # + while 1: + act = panel.dopanel() + +main() diff --git a/demo/sgi/gl_panel/apanel/apanel.s b/demo/sgi/gl_panel/apanel/apanel.s new file mode 100644 index 0000000..7c94da2 --- /dev/null +++ b/demo/sgi/gl_panel/apanel/apanel.s @@ -0,0 +1,76 @@ +;;; This file was automatically generated by the panel editor. +;;; If you read it into gnu emacs, it will automagically format itself. + +(panel (prop help creator:user-panel-help) +(prop user-panel #t) +(label "Audio Control Panel") +(x 395) +(y 69) +(al (pnl_filled_vslider (name "outputgain") +(prop help creator:user-act-help) +(label "output gain") +(x 6.5) +(y 0.75) +(w 0.4) +(h 4.35) +(val 0.329) +(labeltype 13) +(downfunc move-then-resize) +) +(pnl_frame (prop help creator:user-frame-help) +(x 0.25) +(y 2.75) +(w 5.1) +(h 2.3) +(downfunc move-then-resize) +(al (pnl_filled_hslider (name "recordsize") +(prop help creator:user-act-help) +(label "recording length") +(x -0.75) +(w 3.3) +(h 0.4) +(val 0.1) +(labeltype 11) +(downfunc move-then-resize) +) +(pnl_label (prop help creator:user-act-help) +(label "(max 10 seconds)") +(x -0.75) +(y -0.75) +(downfunc move-then-resize) +) +(pnl_wide_button (name "recordbutton") +(prop help creator:user-act-help) +(label "record from microphone...") +(x -0.75) +(y 0.75) +(w 4.7) +(downfunc move-then-resize) +) +) +) +(pnl_wide_button (name "playbackbutton") +(prop help creator:user-act-help) +(label "playback to speaker") +(x 0.25) +(y 2) +(w 5.15) +(downfunc move-then-resize) +) +(pnl_wide_button (name "quitbutton") +(prop help creator:user-act-help) +(label "quit") +(x 0.25) +(y 0.25) +(w 1.75) +(downfunc move-then-resize) +) +) +) +;;; Local Variables: +;;; mode: scheme +;;; eval: (save-excursion (goto-char (point-min)) (kill-line 3)) +;;; eval: (save-excursion (goto-char (point-min)) (replace-regexp "[ \n]*)" ")")) +;;; eval: (indent-region (point-min) (point-max) nil) +;;; eval: (progn (kill-line -3) (delete-backward-char 1) (save-buffer)) +;;; End: diff --git a/demo/sgi/gl_panel/flying/data.py b/demo/sgi/gl_panel/flying/data.py new file mode 100644 index 0000000..bfc934a --- /dev/null +++ b/demo/sgi/gl_panel/flying/data.py @@ -0,0 +1,42 @@ + +# two string constants +ARROW = '-> ' +NULL = '' +ZERO = 0 +ONE = 1 + +# +# the color light-blue +# +lightblue = (43,169,255) + + +# +# a couple of rotation, translation, scaling vectors +# +rts1 = [[3.0,3.1,2.0],[2.2, 1.2, 2.0], [0.8,0.8,0.8]] +rts2 = [[3.2,2.6,1.8],[-1.9, 1.2, 1.6], [0.3,0.3,1.0]] +rts3 = [[2.2,3.3,1.4], [-1.0, 1.2,-1.5], [0.6,0.6, 0.6]] +rts4 = [[4.2,2.1,3.2],[1.2, 1.3, 1.0],[0.5,0.5,0.8]] +rts5 = [[1.2,3.3,2.4], [-2.0, 1.4,-2.1], [0.8, 0.8, 0.2]] +rts6 = [[3.2,3.6,2.4], [1.1, 1.6, 2.5], [0.8,0.3,0.1]] +rts7 = [[2.3,2.7,3.3], [1.1, 2.3, 1.7], [0.6,0.6,0.5]] +rts8 = [[4.2,2.1,3.2], [1.2, 1.3, 0.0], [0.5,0.5,0.5]] +# +rts90 = [[4.2,2.1,3.2], [2.0, 0.0, 0.9], [0.3,0.3,1.0]] +rts91 = [[4.2,2.1,3.2], [-2.0, 0.0, 0.9], [0.3,0.3,1.0]] +rts92 = [[4.2,2.1,3.2], [0.0, 2.0, 0.9], [0.3,0.3,1.0]] +rts93 = [[4.2,2.1,3.2], [0.0, -2.0, 0.9], [0.3,0.3,1.0]] +rts10 = [[4.2,2.1,3.2], [0.0, 0.0, 0.0], [2.2,2.2,0.2]] + +# +# (composite) object definitions +# +o1 = [['sphere',rts1, 1]] +o2 = [['cylinder', rts2, 4]] +o3 = [['cube', rts3, 3]] +o4 = [['cone', rts4, 2], ['sphere', rts8, 9]] +o5 = [['sphere', rts5, 5]] +o6 = [['cube', rts6, 6]] +o7 = [['pyramid', rts7, 8]] +o8 = [['cube', rts10, 9], ['cylinder', rts90, 2], ['cylinder', rts91, 2], ['cylinder', rts92, 2], ['cylinder', rts93, 2]] diff --git a/demo/sgi/gl_panel/flying/flying.py b/demo/sgi/gl_panel/flying/flying.py new file mode 100755 index 0000000..e6fd823 --- /dev/null +++ b/demo/sgi/gl_panel/flying/flying.py @@ -0,0 +1,375 @@ +#! /ufs/guido/bin/sgi/python + +from gl import * +from objdict import * +from GL import * +import DEVICE, time +import objectdef, light, panel, material + +def fixmatact (p) : + p.diffR.fixact () + p.diffG.fixact () + p.diffB.fixact () + p.specR.fixact () + p.specG.fixact () + p.specB.fixact () + p.shine.fixact () + +def fixlichtact (p) : + p.R.fixact () + p.G.fixact () + p.B.fixact () + p.X.fixact () + p.Y.fixact () + p.Z.fixact () + p.local.fixact () + +def cbsetlight (a) : + p = a.back + setlight (p, a.label) + +def cbsetmaterial (a) : + p = a.back + setmaterial (p, a.label) + +mater = [0] +licht = [0] + +def setmaterial (p, mname) : + # + mater [0:1] = [material.materdict [mname]] + # + p.diffR.val = mater [0][1] + p.diffG.val = mater [0][2] + p.diffB.val = mater [0][3] + # + p.specR.val = mater [0][5] + p.specG.val = mater [0][6] + p.specB.val = mater [0][7] + # + p.shine.val = mater [0][9] / 128.0 + fixmatact (p) + +def setlight (p, mname) : + # + licht [0:1] = [material.lichtdict [mname]] + # + p.R.val = licht [0][1] + p.G.val = licht [0][2] + p.B.val = licht [0][3] + # + p.X.val = (licht [0][5] + 10.0) / 20.0 + p.Y.val = (licht [0][6] + 10.0) / 20.0 + p.Z.val = (licht [0][7] + 10.0) / 20.0 + # + p.local.val = licht [0][8] + # + fixlichtact (p) + +def cbmaterial (a) : + # + if mater[0] = 0 : return + # + p = a.back + mater [0][5:8] = [p.diffR.val, p.diffG.val, p.diffB.val] + mater [0][1:4] = [p.specR.val, p.specG.val, p.specB.val] + mater [0][9:10] = [128.0 * p.shine.val] + light.bindlight (0) + +def cblight (a) : + # + if licht[0] = 0 : return + # + p = a.back + licht [0][1:4] = [p.R.val, p.G.val, p.B.val] + licht [0][5:8] = [20.0 * p.X.val - 10.0, 20.0 * p.Y.val - 10.0, 20.0 * p.Z.val - 10.0] + if p.local.val = 0.0 : + licht [0][8:9] = [0.0] + else: + licht [0][8:9] = [1.0] + # + light.bindlight (0) + +# +# initgl : initialize window, pipeline, light, viewing +# +def initgl () : + # + # init window + # + foreground () + keepaspect (1, 1) + prefposition (100, 500, 100, 500) + w = winopen ('flying objects') + keepaspect (1, 1) + winconstraints () + # + # configure pipline + # + doublebuffer () + shademodel (GOURAUD) + zbuffer (1) + RGBmode () + gconfig () + # + # init lighting + # + light.bindlight (1) + # + # set viewing + # + lookat (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0) + # + +# +# drawit : draws the object with the given attributes. +# +# rfac : the rotation factor. +# mat : the material identification +# attr : a list of attributes : +# +# [[rotate vector ], [tranlate vector], [scale vector]] +# i.e : +# [[rX, rY, rZ], [tX, tY, tZ], [sX, sY, sZ]] +# +def drawit(object, rfac, attr, mat) : + pushmatrix() + rot (attr[0][0] * float (rfac), 'X') + rot (attr[0][1] * float (rfac), 'Y') + rot (attr[0][2] * float (rfac), 'Z') + translate(attr[1][0], attr[1][1], attr[1][2]) + scale(attr[2][0], attr[2][1], attr[2][2]) + lmbind(MATERIAL, mat) + objectdef.drawobject(object) + popmatrix() + +def callbacksphere (a) : + putDict (objects, 'sphere', int (a.val)) + +def callbackcylinder (a) : + putDict (objects, 'cylinder', int (a.val)) + +def callbackcube (a) : + putDict (objects, 'cube', int (a.val)) + +def callbackicecream (a) : + putDict (objects, 'icecream', int (a.val)) + +def callbackdisk (a) : + putDict (objects, 'disk', int (a.val)) + +def callbackdiamond (a) : + putDict (objects, 'diamond', int (a.val)) + +def callbackglass (a) : + putDict (objects, 'glass', int (a.val)) + +def callbackpyramid (a) : + putDict (objects, 'pyramid', int (a.val)) + +def callbacktable (a) : + putDict (objects, 'table', int (a.val)) + +def callbackflat (a) : + shademodel(FLAT) + +def callbackgouraud (a) : + shademodel(GOURAUD) + +def callbackwire (a) : + objectdef.putFunc ([bgnclosedline, endclosedline]) + +def callbackfilled (a) : + objectdef.putFunc ([bgnpolygon, endpolygon]) + +def callbackquit (a) : + import sys + sys.exit (-1) + +def allObjects(p, val) : + p.sphere.val = val + p.sphere.fixact () + p.cube.val = val + p.cube.fixact () + p.cylinder.val = val + p.cylinder.fixact () + p.pyramid.val = val + p.pyramid.fixact () + p.disk.val = val + p.disk.fixact () + p.diamond.val = val + p.diamond.fixact () + p.icecream.val = val + p.icecream.fixact () + p.table.val = val + p.table.fixact () + p.fixpanel() + + +def callbackshowall (a) : + #print objects + for key in objects.keys () : + #print key + putDict (objects, key, 1) + allObjects (a.back, 1.0) + +def callbackshownone (a) : + for key in objects.keys () : + putDict (objects, key, 0) + allObjects (a.back, 0.0) + +# +# main : makeobjects, initialze graphics, and loop continuously. +# +def main () : + # + # iter keeps track of the iterations. It is used as the + # (x, y, z) rotation increments to which the objects rotate. + iter = 0 + # + # make the objects. the objects are put in the odict dictionary + # + od = objectdef.makeobjects () + # + # initialize gl + # + initgl () + # + # initialize time and iterations per second + # + time0 = time.time () # epoch-time of previous second + fps = 0 # frames per second + # + # initialize panels + # + panel.needredraw() + panels = panel.defpanellist('flying.s') #XXX + p = panels[0] + p.sphere.upfunc = callbacksphere + p.cylinder.upfunc = callbackcylinder + p.cube.upfunc = callbackcube + p.icecream.upfunc = callbackicecream + p.disk.upfunc = callbackdisk + p.diamond.upfunc = callbackdiamond + # NOT YET IMPLEMENTED p.glass.upfunc = callbackglass + p.pyramid.upfunc = callbackpyramid + p.table.upfunc = callbacktable + p.wire.upfunc = callbackwire + p.filled.upfunc = callbackfilled + p.flat.upfunc = callbackflat + p.gouraud.upfunc = callbackgouraud + p.quit.upfunc = callbackquit + p.showall.upfunc = callbackshowall + p.shownone.upfunc = callbackshownone + p.showall.back = p + p.shownone.back = p + # + qanels = panel.defpanellist('freeze.s') #XXX + q = qanels[0] + # + ranels = panel.defpanellist('materials.s') #XXX + r = ranels[0] + r.m9.upfunc = cbsetmaterial + r.m8.upfunc = cbsetmaterial + r.m7.upfunc = cbsetmaterial + r.m6.upfunc = cbsetmaterial + r.m5.upfunc = cbsetmaterial + r.m4.upfunc = cbsetmaterial + r.m3.upfunc = cbsetmaterial + r.m2.upfunc = cbsetmaterial + r.m1.upfunc = cbsetmaterial + r.specR.activefunc = cbmaterial + r.specG.activefunc = cbmaterial + r.specB.activefunc = cbmaterial + r.diffR.activefunc = cbmaterial + r.diffG.activefunc = cbmaterial + r.diffB.activefunc = cbmaterial + r.shine.activefunc = cbmaterial + r.m9.back = r + r.m8.back = r + r.m7.back = r + r.m6.back = r + r.m5.back = r + r.m4.back = r + r.m3.back = r + r.m2.back = r + r.m1.back = r + r.diffR.back = r + r.diffG.back = r + r.diffB.back = r + r.specR.back = r + r.specG.back = r + r.specB.back = r + r.shine.back = r + # + sanels = panel.defpanellist('light.s') #XXX + s = sanels[0] + s.X.back = s + s.Y.back = s + s.Z.back = s + s.R.back = s + s.G.back = s + s.B.back = s + s.light1.back = s + s.light2.back = s + s.local.back = s + s.light1.upfunc = cbsetlight + s.light2.upfunc = cbsetlight + s.R.activefunc = cblight + s.G.activefunc = cblight + s.B.activefunc = cblight + s.X.activefunc = cblight + s.Y.activefunc = cblight + s.Z.activefunc = cblight + # + while 1 : + # + act = panel.dopanel() + # + wid = panel.userredraw () + if wid : + winset (wid) + reshapeviewport() + # + # increment iter + # + if int (q.freeze.val) = 0 : + iter = iter + 1 + fps = fps + 1 + if time.time() - time0 >= 1 : + f = float(fps)/float(time.time()-time0) + q.mystrip.val = f + q.mystrip.fixact () + q.fixpanel() + time0 = time.time() + fps = 0 + # + # clear the zbuffer and make the background light blue + # + zclear() + c3i (LightBlue) + clear() + # + # for each object in the objects dictionary + # + for key in objects.keys() : + # + # if the object should be displayed + # + if getDict (objects, key, 0) = ONE : + loo = getDict (objects, key, 1) + for o in loo : + # + # get attributes and materail + # + attr = o [1] + mat = o [2] + # + # display the object + # + drawit(od[o[0]],iter,attr,mat) + # + swapbuffers() + # + +main() diff --git a/demo/sgi/gl_panel/flying/flying.s b/demo/sgi/gl_panel/flying/flying.s new file mode 100644 index 0000000..a39fdaa --- /dev/null +++ b/demo/sgi/gl_panel/flying/flying.s @@ -0,0 +1,140 @@ +;;; This file was automatically generated by the panel editor. +;;; If you read it into gnu emacs, it will automagically format itself. + +(panel (prop help creator:user-panel-help) +(prop user-panel #t) +(label "flying objects") +(al (pnl_toggle_button (name "table") +(prop help creator:user-act-help) +(label "table") +(x 4.75) +(y 0.25) +(downfunc move-then-resize) +) +(pnl_toggle_button (name "pyramid") +(prop help creator:user-act-help) +(label "pyramid") +(x 4.75) +(y 0.75) +(downfunc move-then-resize) +) +(pnl_toggle_button (name "glass") +(prop help creator:user-act-help) +(label "glass") +(x 4.75) +(y 1.25) +(downfunc move-then-resize) +) +(pnl_toggle_button (name "diamond") +(prop help creator:user-act-help) +(label "diamond") +(x 4.75) +(y 1.75) +(downfunc move-then-resize) +) +(pnl_toggle_button (name "disk") +(prop help creator:user-act-help) +(label "disk") +(x 4.75) +(y 2.25) +(downfunc move-then-resize) +) +(pnl_toggle_button (name "icecream") +(prop help creator:user-act-help) +(label "ice cream") +(x 4.75) +(y 2.75) +(downfunc move-then-resize) +) +(pnl_toggle_button (name "cube") +(prop help creator:user-act-help) +(label "cube") +(x 4.75) +(y 3.25) +(val 1) +(downfunc move-then-resize) +) +(pnl_toggle_button (name "cylinder") +(prop help creator:user-act-help) +(label "cylinder") +(x 4.75) +(y 3.75) +(downfunc move-then-resize) +) +(pnl_toggle_button (name "sphere") +(prop help creator:user-act-help) +(label "sphere") +(x 4.75) +(y 4.25) +(downfunc move-then-resize) +) +(pnl_button (name "quit") +(prop help creator:user-act-help) +(label "quit") +(x 0.25) +(y 2.25) +(w 1.3) +(h 0.65) +(labeltype 16) +(downfunc move-then-resize) +) +(pnl_button (name "showall") +(prop help creator:user-act-help) +(label "show all") +(x 3.75) +(y 3.75) +(labeltype 8) +(downfunc move-then-resize) +) +(pnl_button (name "shownone") +(prop help creator:user-act-help) +(label "show none") +(x 3.75) +(y 3.25) +(labeltype 8) +(downfunc move-then-resize) +) +(pnl_radio_button (name "wire") +(prop end-of-group #t) +(prop help creator:user-act-help) +(label "wire frame") +(x 0.25) +(y 4.5) +(h 0.36) +(downfunc move-then-resize) +) +(pnl_radio_button (name "filled") +(prop help creator:user-act-help) +(label "filled") +(x 0.25) +(y 4) +(h 0.36) +(val 1) +(downfunc move-then-resize) +) +(pnl_radio_button (name "flat") +(prop end-of-group #t) +(prop help creator:user-act-help) +(label "flat shaded") +(x 0.25) +(y 0.5) +(h 0.36) +(downfunc move-then-resize) +) +(pnl_radio_button (name "gouraud") +(prop help creator:user-act-help) +(label "gouraud shaded") +(x 0.25) +(h 0.36) +(val 1) +(downfunc move-then-resize) +) +) +) +;;; Local Variables: +;;; mode: scheme +;;; eval: (save-excursion (goto-char (point-min)) (kill-line 3)) +;;; eval: (save-excursion (goto-char (point-min)) (replace-regexp "[ \n]*)" ")")) +;;; eval: (indent-region (point-min) (point-max) nil) +;;; eval: (progn (kill-line -3) (delete-backward-char 1) (save-buffer)) +;;; End: diff --git a/demo/sgi/gl_panel/flying/freeze.s b/demo/sgi/gl_panel/flying/freeze.s new file mode 100644 index 0000000..4bfa88c --- /dev/null +++ b/demo/sgi/gl_panel/flying/freeze.s @@ -0,0 +1,31 @@ +;;; This file was automatically generated by the panel editor. +;;; If you read it into gnu emacs, it will automagically format itself. + +(panel (prop help creator:user-panel-help) +(prop user-panel #t) +(label "frames per second") +(al (pnl_toggle_button (name "freeze") +(prop help creator:user-act-help) +(label "freeze") +(x 0.25) +(y 4.3) +(w 1.45) +(h 0.6) +(labeltype 16) +(downfunc move-then-resize) +) +(pnl_scale_chart (name "mystrip") +(prop help creator:user-act-help) +(x 0.25) +(y 0.25) +(downfunc move-then-resize) +) +) +) +;;; Local Variables: +;;; mode: scheme +;;; eval: (save-excursion (goto-char (point-min)) (kill-line 3)) +;;; eval: (save-excursion (goto-char (point-min)) (replace-regexp "[ \n]*)" ")")) +;;; eval: (indent-region (point-min) (point-max) nil) +;;; eval: (progn (kill-line -3) (delete-backward-char 1) (save-buffer)) +;;; End: diff --git a/demo/sgi/gl_panel/flying/light.py b/demo/sgi/gl_panel/flying/light.py new file mode 100644 index 0000000..f6bf379 --- /dev/null +++ b/demo/sgi/gl_panel/flying/light.py @@ -0,0 +1,46 @@ +from GL import * +from gl import * + +# identity matrix +idmat=[1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0] + +# the different materials. +m1=[SPECULAR,0.8,0.0,0.0,DIFFUSE,0.4,0.0,0.0,SHININESS,40.0,LMNULL] +m2=[SPECULAR,1.0,0.4,0.0,DIFFUSE,1.0,0.4,0.0,SHININESS,80.0,LMNULL] +m3=[SPECULAR,0.0,0.0,0.6,DIFFUSE,0.0,0.0,0.8,SHININESS,60.0,LMNULL] +m4=[SPECULAR,0.0,1.0,0.0,DIFFUSE,0.0,0.6,0.0,SHININESS,120.0,LMNULL] +m5=[SPECULAR,1.0,1.0,0.0,DIFFUSE,0.6,0.6,0.0,SHININESS,100.0,LMNULL] +m6=[SPECULAR,1.0,0.0,1.0,DIFFUSE,0.6,0.0,0.6,SHININESS,120.0,LMNULL] +m7=[SPECULAR,0.9,0.9,0.9,DIFFUSE,0.6,0.6,0.6,SHININESS,120.0,LMNULL] +m8=[SPECULAR,0.4,0.7,0.4,DIFFUSE,0.5,1.0,0.5,SHININESS,50.0,LMNULL] +m9=[SPECULAR,0.2,0.0,0.1,DIFFUSE,0.8,0.0,0.3,SHININESS,10.0,LMNULL] + +#the lightsources. +light1 = [LCOLOR,1.0,1.0,1.0,POSITION,10.0,10.0,5.0,0.0,LMNULL] +light2 = [LCOLOR,1.0,1.0,1.0,POSITION,-10.0,10.0,5.0,0.0,LMNULL] + +# the lightmodel. +model = [AMBIENT,0.4,0.4,0.4,LMNULL] + +def bindlight (bool) : + # Initializes all settings for a window. + if bool <> 0 : + mmode(MVIEWING) + perspective (900, 1.0, 1.0, 35.0) + loadmatrix(idmat) + # define materials and lights + lmdef(DEFMATERIAL, 1, m1) + lmdef(DEFMATERIAL, 2, m2) + lmdef(DEFMATERIAL, 3, m3) + lmdef(DEFMATERIAL, 4, m4) + lmdef(DEFMATERIAL, 5, m5) + lmdef(DEFMATERIAL, 6, m6) + lmdef(DEFMATERIAL, 7, m7) + lmdef(DEFMATERIAL, 8, m8) + lmdef(DEFMATERIAL, 9, m9) + lmdef(DEFLIGHT, 1, light1) + lmdef(DEFLIGHT, 2, light2) + lmdef(DEFLMODEL, 1, model) + lmbind(LIGHT0,1) + lmbind(LIGHT1,2) + lmbind(LMODEL,1) diff --git a/demo/sgi/gl_panel/flying/light.s b/demo/sgi/gl_panel/flying/light.s new file mode 100644 index 0000000..ad56861 --- /dev/null +++ b/demo/sgi/gl_panel/flying/light.s @@ -0,0 +1,94 @@ +;;; This file was automatically generated by the panel editor. +;;; If you read it into gnu emacs, it will automagically format itself. + +(panel (prop help creator:user-panel-help) +(prop user-panel #t) +(label "Light Sources") +(al (pnl_hslider (name "X") +(prop help creator:user-act-help) +(label "x") +(y 4) +(w 3.3) +(h 0.4) +(val 0.50) +(labeltype 0) +(downfunc move-then-resize) +) +(pnl_hslider (name "Y") +(prop help creator:user-act-help) +(label "y") +(y 3.5) +(w 3.3) +(h 0.4) +(val 0.50) +(labeltype 0) +(downfunc move-then-resize) +) +(pnl_hslider (name "Z") +(prop help creator:user-act-help) +(label "z") +(y 3) +(w 3.3) +(h 0.4) +(val 0.50) +(labeltype 0) +(downfunc move-then-resize) +) +(pnl_radio_button (name "light2") +(prop help creator:user-act-help) +(label "light 2") +(x 5) +(y 4) +(h 0.36) +(downfunc move-then-resize) +) +(pnl_radio_button (name "light1") +(prop help creator:user-act-help) +(label "light 1") +(x 5) +(y 4.5) +(h 0.36) +(downfunc move-then-resize) +) +(pnl_toggle_button (name "local") +(prop help creator:user-act-help) +(label "local") +(x 5) +(y 2.75) +(downfunc move-then-resize) +) +(pnl_filled_hslider (name "B") +(prop help creator:user-act-help) +(label "B") +(w 3.3) +(h 0.4) +(labeltype 0) +(downfunc move-then-resize) +) +(pnl_filled_hslider (name "G") +(prop help creator:user-act-help) +(label "G") +(y 0.5) +(w 3.3) +(h 0.4) +(labeltype 0) +(downfunc move-then-resize) +) +(pnl_filled_hslider (name "R") +(prop help creator:user-act-help) +(label "R") +(y 1) +(w 3.3) +(h 0.4) +(labeltype 0) +(downfunc move-then-resize) +) +) +) +;;; Local Variables: +;;; mode: scheme +;;; eval: (save-excursion (goto-char (point-min)) (kill-line 3)) +;;; eval: (save-excursion (goto-char (point-min)) (replace-regexp "[ \n]*)" ")")) +;;; eval: (indent-region (point-min) (point-max) nil) +;;; eval: (progn (kill-line -3) (delete-backward-char 1) (save-buffer)) +;;; End: diff --git a/demo/sgi/gl_panel/flying/material.py b/demo/sgi/gl_panel/flying/material.py new file mode 100644 index 0000000..f9137ea --- /dev/null +++ b/demo/sgi/gl_panel/flying/material.py @@ -0,0 +1,26 @@ +import light + +def mkmatdict () : + m = {} + m['material 1'] = light.m1 + m['material 2'] = light.m2 + m['material 3'] = light.m3 + m['material 4'] = light.m4 + m['material 5'] = light.m5 + m['material 6'] = light.m6 + m['material 7'] = light.m7 + m['material 8'] = light.m8 + m['material 9'] = light.m9 + # + return m + +materdict = mkmatdict () + +def mklichtdict () : + m = {} + m['light 1'] = light.light1 + m['light 2'] = light.light2 + # + return m + +lichtdict = mklichtdict () diff --git a/demo/sgi/gl_panel/flying/materials.s b/demo/sgi/gl_panel/flying/materials.s new file mode 100644 index 0000000..ae45ca9 --- /dev/null +++ b/demo/sgi/gl_panel/flying/materials.s @@ -0,0 +1,161 @@ +;;; This file was automatically generated by the panel editor. +;;; If you read it into gnu emacs, it will automagically format itself. + +(panel (prop help creator:user-panel-help) +(prop user-panel #t) +(label "Materials") +(al (pnl_label (prop help creator:user-act-help) +(label "specular") +(x 4) +(y 0.5) +(downfunc move-then-resize) +) +(pnl_label (prop help creator:user-act-help) +(label "diffuse") +(x 4) +(y 4) +(downfunc move-then-resize) +) +(pnl_radio_button (name "m7") +(prop help creator:user-act-help) +(label "material 7") +(x 6.5) +(y 1.5) +(h 0.36) +(downfunc move-then-resize) +) +(pnl_radio_button (name "m9") +(prop help creator:user-act-help) +(label "material 9") +(x 6.5) +(y 0.5) +(h 0.36) +(downfunc move-then-resize) +) +(pnl_radio_button (name "m8") +(prop help creator:user-act-help) +(label "material 8") +(x 6.5) +(y 1) +(h 0.36) +(downfunc move-then-resize) +) +(pnl_radio_button (name "m6") +(prop help creator:user-act-help) +(label "material 6") +(x 6.5) +(y 2) +(h 0.36) +(downfunc move-then-resize) +) +(pnl_radio_button (name "m5") +(prop help creator:user-act-help) +(label "material 5") +(x 6.5) +(y 2.5) +(h 0.36) +(downfunc move-then-resize) +) +(pnl_radio_button (name "m4") +(prop help creator:user-act-help) +(label "material 4") +(x 6.5) +(y 3) +(h 0.36) +(downfunc move-then-resize) +) +(pnl_radio_button (name "m3") +(prop help creator:user-act-help) +(label "material 3") +(x 6.5) +(y 3.5) +(h 0.36) +(downfunc move-then-resize) +) +(pnl_radio_button (name "m2") +(prop help creator:user-act-help) +(label "material 2") +(x 6.5) +(y 4) +(h 0.36) +(downfunc move-then-resize) +) +(pnl_radio_button (name "m1") +(prop help creator:user-act-help) +(label "material 1") +(x 6.5) +(y 4.5) +(h 0.36) +(downfunc move-then-resize) +) +(pnl_filled_hslider (name "diffB") +(prop help creator:user-act-help) +(label "B") +(y 3.5) +(w 3.3) +(h 0.4) +(labeltype 0) +(downfunc move-then-resize) +) +(pnl_filled_hslider (name "diffG") +(prop help creator:user-act-help) +(label "G") +(y 4) +(w 3.3) +(h 0.4) +(labeltype 0) +(downfunc move-then-resize) +) +(pnl_filled_hslider (name "diffR") +(prop help creator:user-act-help) +(label "R") +(y 4.5) +(w 3.3) +(h 0.4) +(labeltype 0) +(downfunc move-then-resize) +) +(pnl_filled_hslider (name "specB") +(prop help creator:user-act-help) +(label "B") +(w 3.3) +(h 0.4) +(labeltype 0) +(downfunc move-then-resize) +) +(pnl_filled_hslider (name "specG") +(prop help creator:user-act-help) +(label "G") +(y 0.5) +(w 3.3) +(h 0.4) +(labeltype 0) +(downfunc move-then-resize) +) +(pnl_filled_hslider (name "specR") +(prop help creator:user-act-help) +(label "R") +(y 1) +(w 3.3) +(h 0.4) +(labeltype 0) +(downfunc move-then-resize) +) +(pnl_filled_hslider (name "shine") +(prop help creator:user-act-help) +(label "shininess") +(y 2.25) +(w 3.3) +(h 0.4) +(labeltype 0) +(downfunc move-then-resize) +) +) +) +;;; Local Variables: +;;; mode: scheme +;;; eval: (save-excursion (goto-char (point-min)) (kill-line 3)) +;;; eval: (save-excursion (goto-char (point-min)) (replace-regexp "[ \n]*)" ")")) +;;; eval: (indent-region (point-min) (point-max) nil) +;;; eval: (progn (kill-line -3) (delete-backward-char 1) (save-buffer)) +;;; End: diff --git a/demo/sgi/gl_panel/flying/objdict.py b/demo/sgi/gl_panel/flying/objdict.py new file mode 100644 index 0000000..a5d5371 --- /dev/null +++ b/demo/sgi/gl_panel/flying/objdict.py @@ -0,0 +1,41 @@ + +from data import * + +# +#the color light-blue +# +LightBlue = lightblue + +# the 'object' dictionary contains the strings of the menu items +# that denote the objects +objects = {} + +# object dictionary initialization +objects['sphere'] = [ZERO, o1] +objects['cylinder'] = [ZERO, o2] +objects['cube'] = [ONE, o3] +objects['icecream'] = [ZERO, o4] +objects['disk'] = [ZERO, o5] +objects['diamond'] = [ZERO, o6] +#objects['glass'] = [ZERO] +objects['pyramid'] = [ZERO, o7] +objects['table'] = [ZERO, o8] + +# 'putDict' sets the value of entry 'key' of dictionary 'dict' +def putDict(dict, key, val) : + dict[key][0] = val + +# +# 'getDict' get the contents of entry i of key 'key' +# of dictionary 'dict' +# +def getDict(dict, key, i) : + return dict[key][i] + +# the 'options' dictionary contains the strings of the menu items +# that denote the options +options = {} + +# option dictionary initialization +options['wire'] = [ZERO] +options['filled'] = [ONE] diff --git a/demo/sgi/gl_panel/flying/objectdef.py b/demo/sgi/gl_panel/flying/objectdef.py new file mode 100644 index 0000000..3e96113 --- /dev/null +++ b/demo/sgi/gl_panel/flying/objectdef.py @@ -0,0 +1,147 @@ +from math import * +from objdict import * +from gl import * + +FUZZY = 0.00001 + +# first try - brute force method (ala M.Overmars...) + +def makespinobject (smooth,rot,n,x1,z1,nx1,nz1,x2,z2,nx2,nz2) : + object = [] + dth = 2.0 * pi / float (rot) + for i in range (0, n) : + for j in range (0, rot) : + th = dth * float (j) + # + if smooth = 1: + a1 = th + a2 =th+dth + else : + a1 = th + dth / 2.0 + a2 = th + dth / 2.0 + # + v0 = (x1[i]*sin(th),x1[i]*cos(th),z1[i]) + n0 = (nx1[i]*sin(a1),nx1[i]*cos(a1),nz1[i]) + # + v1 = (x1[i]*sin(th+dth),x1[i]*cos(th+dth),z1[i]) + n1 = (nx1[i]*sin(a2), nx1[i]*cos(a2), nz1[i]) + # + v2 = (x2[i]*sin(th+dth),x2[i]*cos(th+dth),z2[i]) + n2 = (nx2[i]*sin(a2), nx2[i]*cos(a2), nz2[i]) + # + v3 = (x2[i]*sin(th), x2[i]*cos(th), z2[i]) + n3 = (nx2[i]*sin(a1), nx2[i]*cos(a1), nz2[i]) + # + patch = ((v0,n0), (v1,n1), (v2,n2), (v3,n3)) + #patch = ((n0,v0), (n1,v1), (n2,v2), (n3,v3)) + # + if x1[i] < FUZZY : + patch = patch[1:] + # + object.append (patch) + # + return object + +def makesphere (n): + asin = [] + acos = [] + for i in range (0, n-1): + asin.append (sin((pi/float (n))*(1.0+float (i)))) + acos.append(cos((pi/float (n))*(1.0+float (i)))) + # + x1 = [0.0] + asin + z1 = [1.0] + acos + nx1 = [0.0] + asin + nz1 = [1.0] + acos + # + x2 = asin + [0.0] + z2 = acos + [-1.0] + nx2 = asin + [0.0] + nz2 = acos + [-1.0] + # + return makespinobject (1,2*n,n,x1,z1,nx1,nz1,x2,z2,nx2,nz2) + +def makecylinder(n) : + x1 = [0.0, 1.0, 1.0] + nx1 = [0.0, 1.0, 0.0] + z1 = [1.0, 1.0, -1.0] + nz1 = [1.0, 0.0, -1.0] + # + z2 = [1.0, -1.0, -1.0] + nz2 = [1.0, 0.0, -1.0] + x2 = [1.0, 1.0, 0.0] + nx2 = [0.0, 1.0, 0.0] + # + return makespinobject(1,2*n,3,x1,z1,nx1,nz1,x2,z2,nx2,nz2) + +def makecone(n) : + x1 = [0.0, 1.0, 1.0] + nx1 = [2.0/sqrt(5.0), 0.0, 0.0] + z1 = [1.0, -1.0, -1.0] + nz1 = [1.0/sqrt(5.0), -1.0, -1.0] + # + x2 = [1.0, 0.0, 0.0] + nx2 = [2.0/sqrt(5.0), 0.0, 0.0] + nz2 = [1.0/sqrt(5.0), -1.0, -1.0] + z2 = [-1.0, -1.0, -1.0] + # + return makespinobject(1,2*n,2,x1,z1,nx1,nz1,x2,z2,nx2,nz2) + +def makecube() : + x1 = [0.0, sqrt(2.0), sqrt (2.0)] + nx1 = [0.0, 1.0, 0.0] + z1 = [1.0, 1.0, -1.0] + nz1 = [1.0, 0.0, -1.0] + # + x2 = [sqrt(2.0), sqrt(2.0), 0.0] + nx2 = [0.0, 1.0, 0.0] + z2 = [1.0, -1.0, -1.0] + nz2 = [1.0, 0.0, -1.0] + # + return makespinobject(0,4,3,x1,z1,nx1,nz1,x2,z2,nx2,nz2) + + +def makepyramid() : + x1 = [0.0, sqrt(2.0), 0.0] + nx1 = [2.0 / sqrt(5.0), 0.0, 0.0] + z1 = [1.0, -1.0, 0.0] + nz1 = [1.0 / sqrt(5.0), -1.0, 0.0] + # + x2 = [sqrt(2.0), 0.0, 0.0] + nx2 = [2.0 / sqrt(5.0), 0.0, 0.0] + z2 = [-1.0, -1.0, -1.0] + nz2 = [1.0/sqrt(5.0), -1.0, 0.0] + # + return makespinobject(0,4,3,x1,z1,nx1,nz1,x2,z2,nx2,nz2) + +def makeobjects () : + cube = makecube() + sphere = makesphere (6) + cylinder = makecylinder (6) + cone = makecone (6) + pyramid = makepyramid () + # + odict = {} + odict ['cube'] = cube + odict ['pyramid'] = pyramid + odict ['sphere'] = sphere + odict ['cylinder'] = cylinder + odict ['cone'] = cone + odict ['diamond'] = cube + odict ['disk'] = sphere + # + return odict + + +renderfuncs = [bgnpolygon, endpolygon] + +def putFunc (funcs) : + renderfuncs [:] = funcs + +def drawobject (obj) : + # + for patch in obj : + renderfuncs[0] () + vnarray (patch) + renderfuncs[1] () + diff --git a/demo/sgi/gl_panel/flying/panel.s b/demo/sgi/gl_panel/flying/panel.s new file mode 100644 index 0000000..2365a76 --- /dev/null +++ b/demo/sgi/gl_panel/flying/panel.s @@ -0,0 +1,76 @@ +;;; This file was automatically generated by the panel editor. +;;; If you read it into gnu emacs, it will automagically format itself. + +(panel (prop help creator:user-panel-help) +(prop user-panel #t) +(label "Panel Control") +(x 394) +(y 622) +(al (pnl_radio_button (name "button4") +(prop help creator:user-act-help) +(y 2.5) +(h 0.36) +(downfunc move-then-resize) +) +(pnl_radio_button (name "button3") +(prop help creator:user-act-help) +(y 3) +(h 0.36) +(downfunc move-then-resize) +) +(pnl_radio_button (name "button2") +(prop help creator:user-act-help) +(y 3.5) +(h 0.36) +(downfunc move-then-resize) +) +(pnl_radio_button (name "button1") +(prop help creator:user-act-help) +(y 4) +(h 0.36) +(downfunc move-then-resize) +) +(pnl_wide_button (name "title1") +(prop help creator:user-act-help) +(x 0.75) +(y 4.75) +(w 2.44) +(downfunc move-then-resize) +) +(pnl_wide_button (name "title2") +(prop help creator:user-act-help) +(x 3.5) +(y 4.75) +(w 2.44) +(downfunc move-then-resize) +) +(pnl_wide_button (name "title3") +(prop help creator:user-act-help) +(x 6.25) +(y 4.75) +(w 2.44) +(downfunc move-then-resize) +) +(pnl_wide_button (name "title4") +(prop help creator:user-act-help) +(x 9) +(y 4.75) +(w 2.44) +(downfunc move-then-resize) +) +(pnl_button (name "root") +(prop help creator:user-act-help) +(label "R") +(y 4.75) +(labeltype 16) +(downfunc move-then-resize) +) +) +) +;;; Local Variables: +;;; mode: scheme +;;; eval: (save-excursion (goto-char (point-min)) (kill-line 3)) +;;; eval: (save-excursion (goto-char (point-min)) (replace-regexp "[ \n]*)" ")")) +;;; eval: (indent-region (point-min) (point-max) nil) +;;; eval: (progn (kill-line -3) (delete-backward-char 1) (save-buffer)) +;;; End: diff --git a/demo/sgi/gl_panel/nurbs/nurbs.py b/demo/sgi/gl_panel/nurbs/nurbs.py new file mode 100755 index 0000000..686c3bd --- /dev/null +++ b/demo/sgi/gl_panel/nurbs/nurbs.py @@ -0,0 +1,196 @@ +#! /ufs/guido/bin/sgi/python + +# Fancy NURBS demo. Require Z buffer and Panel Library. + +from gl import * +from GL import * +from DEVICE import * +from nurbsdata import * +import panel + +# +# flags = trim_f, invis_f, cpvis_f, tpvis_f, axvis_f, freeze_f +# +TRIM = 0 +VIS = 1 +CPVIS = 2 +TPVIS = 3 +AXVIS = 4 +FREEZE = 5 +flags = [0, 1, 0, 0, 0, 0] + +def draw_axis () : + cpack (0x0) + zero = (0.0, 0.0, 0.0) + # + one = (1.0, 0.0, 0.0) + smallline (zero, one) + cmov (1.0, 0.0, 0.0) + charstr ('x') + # + one = (0.0, 1.0, 0.0) + smallline (zero, one) + cmov (0.0, 1.0, 0.0) + charstr ('y') + # + one = (0.0, 0.0, 1.0) + smallline (zero, one) + cmov (0.0, 0.0, 1.0) + charstr ('z') + +DELTA = 0.1 + +def cross (p) : + p0 = [p[0], p[1], p[2]] + p1 = [p[0], p[1], p[2]] + for i in range (0, 3) : + p0[i] = p0[i] + DELTA + p1[i] = p1[i] - DELTA + smallline (p0, p1) + p0[i] = p0[i] - DELTA + p1[i] = p1[i] + DELTA + +def smallline (p0, p1) : + bgnline () + v3f (p0) + v3f (p1) + endline () + +def draw_pts (pnts, color) : + linewidth (2) + cpack (color) + for i in pnts : + cross (i) + +def init_windows(): + foreground() + wid = winopen('nurbs') + wintitle('NURBS Surface') + doublebuffer() + RGBmode() + gconfig() + lsetdepth(0x000, 0x7fffff) + zbuffer( TRUE ) + +def init_view(): + mmode(MPROJECTION) + ortho( -5., 5., -5., 5., -5., 5. ) + # + mmode(MVIEWING) + loadmatrix(idmat) + # + lmbind(MATERIAL, 1) + +def set_scene(flags): + # + lmbind(MATERIAL, 0) + RGBcolor(150,150,150) + lmbind(MATERIAL, 1) + clear() + zclear() + # + if not flags[FREEZE] : + rotate( 100, 'y' ) + rotate( 100, 'z' ) + +def draw_trim_surface(flags): + pnts = ctlpoints + if flags[VIS] : + bgnsurface() + nurbssurface(surfknots,surfknots,pnts,ORDER,ORDER,N_XYZ) + if flags[TRIM]: + bgntrim() + nurbscurve(trimknots,trimpoints,ORDER-1,N_STW) + endtrim() + endsurface() + # + if flags[CPVIS] : + for i in pnts : + draw_pts (i, RED) + # + if flags[TPVIS] : + tpts = trimpoints + draw_pts (tpts, YELLOW) + # + if flags[AXVIS] : + draw_axis () + # + swapbuffers() + +def make_lights(): + lmdef(DEFLMODEL,1,[]) + lmdef(DEFLIGHT,1,[]) + # + # define material #1 + # + a = [] + a = a + [EMISSION, 0.0, 0.0, 0.0] + a = a + [AMBIENT, 0.1, 0.1, 0.1] + a = a + [DIFFUSE, 0.6, 0.3, 0.3] + a = a + [SPECULAR, 0.0, 0.6, 0.0] + a = a + [SHININESS, 2.0] + a = a + [LMNULL] + lmdef(DEFMATERIAL, 1, a) + # + # turn on lighting + # + lmbind(LIGHT0, 1) + lmbind(LMODEL, 1) + +def main(): + init_windows() + make_lights() + init_view() + # + panel.needredraw() + panels = panel.defpanellist('nurbs.s') + p = panels[0] + # + def cbtrim (a) : + flags[TRIM:TRIM+1] = [int (a.val)] + p.trim.upfunc = cbtrim + # + def cbquit (a) : + import sys + sys.exit (1) + p.quit.upfunc = cbquit + # + def cbmotion (a) : + flags[FREEZE:FREEZE+1] = [int (a.val)] + p.motion.upfunc = cbmotion + # + def cbxyzaxis (a) : + flags[AXVIS:AXVIS+1] = [int (a.val)] + p.xyzaxis.upfunc = cbxyzaxis + # + def cbtrimpnts (a) : + flags[TPVIS:TPVIS+1] = [int (a.val)] + p.trimpnts.upfunc = cbtrimpnts + # + def cbcntlpnts (a) : + flags[CPVIS:CPVIS+1] = [int (a.val)] + p.cntlpnts.upfunc = cbcntlpnts + # + def cbnurb (a) : + flags[VIS:VIS+1] = [int (a.val)] + p.nurb.upfunc = cbnurb + # + set_scene(flags) + setnurbsproperty( N_ERRORCHECKING, 1.0 ) + setnurbsproperty( N_PIXEL_TOLERANCE, 50.0 ) + draw_trim_surface(flags) + # + while 1: + act = panel.dopanel() + # + wid = panel.userredraw () + if wid : + winset (wid) + reshapeviewport() + set_scene(flags) + draw_trim_surface(flags) + # + set_scene(flags) + draw_trim_surface(flags) + +main() diff --git a/demo/sgi/gl_panel/nurbs/nurbs.s b/demo/sgi/gl_panel/nurbs/nurbs.s new file mode 100644 index 0000000..05fb514 --- /dev/null +++ b/demo/sgi/gl_panel/nurbs/nurbs.s @@ -0,0 +1,81 @@ +;;; This file was automatically generated by the panel editor. +;;; If you read it into gnu emacs, it will automagically format itself. + +(panel (prop help creator:user-panel-help) +(prop user-panel #t) +(label "NURB controls") +(x 815) +(y 22) +(al (pnl_toggle_button (name "trim") +(prop help creator:user-act-help) +(label "trim on/off") +(x 4) +(y 4.5) +(w 0.45) +(h 0.4) +(downfunc move-then-resize) +) +(pnl_toggle_button (name "motion") +(prop help creator:user-act-help) +(label "motion on/off") +(y 1) +(downfunc move-then-resize) +) +(pnl_toggle_button (name "xyzaxis") +(prop help creator:user-act-help) +(label "xyz-axis") +(y 3) +(downfunc move-then-resize) +) +(pnl_toggle_button (name "trimpnts") +(prop help creator:user-act-help) +(label "trimming pnts") +(y 3.5) +(downfunc move-then-resize) +) +(pnl_toggle_button (name "cntlpnts") +(prop help creator:user-act-help) +(label "control pnts") +(y 4) +(downfunc move-then-resize) +) +(pnl_toggle_button (name "nurb") +(prop help creator:user-act-help) +(label "nurb") +(y 4.5) +(val 1) +(downfunc move-then-resize) +) +(pnl_button (name "quit") +(prop help creator:user-act-help) +(label "quit") +(x 4) +(y 1) +(labeltype 1) +(downfunc move-then-resize) +) +(pnl_label (prop help creator:user-act-help) +(label "TRIMMING") +(x 4) +(y 5) +(downfunc move-then-resize) +) +(pnl_label (prop help creator:user-act-help) +(label "MOTION") +(y 1.5) +(downfunc move-then-resize) +) +(pnl_label (prop help creator:user-act-help) +(label "VISIBILITY") +(y 5) +(downfunc move-then-resize) +) +) +) +;;; Local Variables: +;;; mode: scheme +;;; eval: (save-excursion (goto-char (point-min)) (kill-line 3)) +;;; eval: (save-excursion (goto-char (point-min)) (replace-regexp "[ \n]*)" ")")) +;;; eval: (indent-region (point-min) (point-max) nil) +;;; eval: (progn (kill-line -3) (delete-backward-char 1) (save-buffer)) +;;; End: diff --git a/demo/sgi/gl_panel/nurbs/nurbsdata.py b/demo/sgi/gl_panel/nurbs/nurbsdata.py new file mode 100644 index 0000000..ed7e705 --- /dev/null +++ b/demo/sgi/gl_panel/nurbs/nurbsdata.py @@ -0,0 +1,82 @@ +# Data used by fancy nurbs demo. + +TRUE = 1 +FALSE = 0 + +RED = 0xff +YELLOW = 0xffff + +# +# nurb order +# +ORDER = 4 + +# +# identity matrix +# +idmat = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1] + +# +# s and t knots +# +surfknots = [-1, -1, -1, -1, 1, 1, 1, 1] + +# +# list of list of control points +# +def make_ctlpoints(): + c = [] + # + ci = [] + ci.append(-2.5, -3.7, 1.0) + ci.append(-1.5, -3.7, 3.0) + ci.append(1.5, -3.7, -2.5) + ci.append(2.5, -3.7, -0.75) + c.append(ci) + # + ci = [] + ci.append(-2.5, -2.0, 3.0) + ci.append(-1.5, -2.0, 4.0) + ci.append(1.5, -2.0, -3.0) + ci.append(2.5, -2.0, 0.0) + c.append(ci) + # + ci = [] + ci.append(-2.5, 2.0, 1.0) + ci.append(-1.5, 2.0, 0.0) + ci.append(1.5, 2.0, -1.0) + ci.append(2.5, 2.0, 2.0) + c.append(ci) + # + ci = [] + ci.append(-2.5, 2.7, 1.25) + ci.append(-1.5, 2.7, 0.1) + ci.append(1.5, 2.7, -0.6) + ci.append(2.5, 2.7, 0.2) + c.append(ci) + # + return c + +ctlpoints = make_ctlpoints () + +# +# trim knots +# +trimknots = [0., 0., 0., 1., 1., 2., 2., 3., 3., 4., 4., 4.] + +def make_trimpoints(): + c = [] + # + c.append(1.0, 0.0, 1.0) + c.append(1.0, 1.0, 1.0) + c.append(0.0, 2.0, 2.0) + c.append(-1.0, 1.0, 1.0) + c.append(-1.0, 0.0, 1.0) + c.append(-1.0, -1.0, 1.0) + c.append(0.0, -2.0, 2.0) + c.append(1.0, -1.0, 1.0) + c.append(1.0, 0.0, 1.0) + # + return c + +trimpoints = make_trimpoints() diff --git a/demo/sgi/gl_panel/twoview/block.py b/demo/sgi/gl_panel/twoview/block.py new file mode 100644 index 0000000..9ac518d --- /dev/null +++ b/demo/sgi/gl_panel/twoview/block.py @@ -0,0 +1,73 @@ +# module 'block' imported by twoview demo. + +from gl import n3f, bgnpolygon, varray, endpolygon, lmbind +from GL import MATERIAL + +# Draw a single 2x2x2 block with its center at (0, 0, 0) +# Arguments are the material indices (0 = don't call lmbind) +# +def block(m_front, m_back, m_left, m_right, m_top, m_bottom): + # + # Distances defining the sides + # + x_left = -1.0 + x_right = 1.0 + y_top = 1.0 + y_bottom = -1.0 + z_front = 1.0 + z_back = -1.0 + # + # Top surface points: A, B, C, D + # + A = x_right, y_top, z_front + B = x_right, y_top, z_back + C = x_left, y_top, z_back + D = x_left, y_top, z_front + # + # Bottom surface points: E, F, G, H + # + E = x_right, y_bottom, z_front + F = x_right, y_bottom, z_back + G = x_left, y_bottom, z_back + H = x_left, y_bottom, z_front + # + # Draw front face + # + if m_front: lmbind(MATERIAL, m_front) + n3f(0.0, 0.0, 1.0) + face(H, E, A, D) + # + # Draw back face + # + if m_back: lmbind(MATERIAL, m_back) + n3f(0.0, 0.0, -1.0) + face(G, F, B, C) + # + # Draw left face + # + if m_left: lmbind(MATERIAL, m_left) + n3f(-1.0, 0.0, 0.0) + face(G, H, D, C) + # + # Draw right face + # + if m_right: lmbind(MATERIAL, m_right) + n3f(1.0, 0.0, 0.0) + face(F, E, A, B) + # + # Draw top face + # + if m_top: lmbind(MATERIAL, m_top) + n3f(0.0, 1.0, 0.0) + face(A, B, C, D) + # + # Draw bottom face + # + if m_bottom: lmbind(MATERIAL, m_bottom) + n3f(0.0, -1.0, 0.0) + face(E, F, G, H) + +def face(points): + bgnpolygon() + varray(points) + endpolygon() diff --git a/demo/sgi/gl_panel/twoview/camera.s b/demo/sgi/gl_panel/twoview/camera.s new file mode 100644 index 0000000..f61a58e --- /dev/null +++ b/demo/sgi/gl_panel/twoview/camera.s @@ -0,0 +1,55 @@ +;;; This file was automatically generated by the panel editor. +;;; If you read it into gnu emacs, it will automagically format itself. + +(panel (prop help creator:user-panel-help) +(prop user-panel #t) +(label "Camera Control") +(x 1010) +(y 589) +(al (pnl_wide_button (name "quitbutton") +(prop help creator:user-act-help) +(label "quit") +(x 3.5) +(y 1) +(w 0.94) +(downfunc move-then-resize) +) +(pnl_filled_hslider (name "farclip") +(prop help creator:user-act-help) +(label "far clipping plane") +(x 1.25) +(y 3.5) +(w 3.3) +(h 0.4) +(val 0.752) +(downfunc move-then-resize) +) +(pnl_filled_hslider (name "nearclip") +(prop help creator:user-act-help) +(label "near clipping plane") +(x 1.25) +(y 4.5) +(w 3.3) +(h 0.4) +(val 0.17) +(downfunc move-then-resize) +) +(pnl_filled_vslider (name "zoom") +(prop help creator:user-act-help) +(label "zoom") +(x 0.2) +(y 1.25) +(w 0.4) +(h 3.9) +(val 0.344) +(downfunc move-then-resize) +) +) +) +;;; Local Variables: +;;; mode: scheme +;;; eval: (save-excursion (goto-char (point-min)) (kill-line 3)) +;;; eval: (save-excursion (goto-char (point-min)) (replace-regexp "[ \n]*)" ")")) +;;; eval: (indent-region (point-min) (point-max) nil) +;;; eval: (progn (kill-line -3) (delete-backward-char 1) (save-buffer)) +;;; End: diff --git a/demo/sgi/gl_panel/twoview/observer.s b/demo/sgi/gl_panel/twoview/observer.s new file mode 100644 index 0000000..ddcfe7a --- /dev/null +++ b/demo/sgi/gl_panel/twoview/observer.s @@ -0,0 +1,98 @@ +;;; This file was automatically generated by the panel editor. +;;; If you read it into gnu emacs, it will automagically format itself. + +(panel (prop help creator:user-panel-help) +(prop user-panel #t) +(label "Observer Control") +(x 876) +(y 10) +(al (pnl_right_arrow_button (name "right") +(prop help creator:user-act-help) +(x 3.2) +(y 2.09) +(downfunc move-then-resize) +) +(pnl_up_double_arrow_button (name "fast_forward") +(prop help creator:user-act-help) +(label "step forward") +(x 2.66) +(y 3.13) +(h 0.45) +(labeltype 4) +(downfunc move-then-resize) +) +(pnl_up_arrow_button (name "forward") +(prop help creator:user-act-help) +(x 2.66) +(y 2.64) +(downfunc move-then-resize) +) +(pnl_down_arrow_button (name "reverse") +(prop help creator:user-act-help) +(x 2.66) +(y 1.49) +(h 0.45) +(labeltype 12) +(downfunc move-then-resize) +) +(pnl_down_double_arrow_button (name "fast_reverse") +(prop help creator:user-act-help) +(label "step back") +(x 2.66) +(y 1) +(labeltype 12) +(downfunc move-then-resize) +) +(pnl_left_arrow_button (name "left") +(prop help creator:user-act-help) +(x 2.11) +(y 2.09) +(downfunc move-then-resize) +) +(pnl_right_double_arrow_button (name "fast_right") +(prop help creator:user-act-help) +(label "turn right") +(x 3.75) +(y 2.09) +(downfunc move-then-resize) +) +(pnl_left_double_arrow_button (name "fast_left") +(prop help creator:user-act-help) +(label "turn left") +(x 1.57) +(y 2.09) +(labeltype 8) +(downfunc move-then-resize) +) +(pnl_vslider (name "ypos") +(prop help creator:user-act-help) +(x 6.25) +(y 1) +(w 0.4) +(h 2.9) +(val 0.0758) +(downfunc move-then-resize) +) +(pnl_down_arrow_button (name "down") +(prop help creator:user-act-help) +(label "eye height") +(x 6.25) +(y 0.5) +(labeltype 12) +(downfunc move-then-resize) +) +(pnl_up_arrow_button (name "up") +(prop help creator:user-act-help) +(x 6.25) +(y 4) +(downfunc move-then-resize) +) +) +) +;;; Local Variables: +;;; mode: scheme +;;; eval: (save-excursion (goto-char (point-min)) (kill-line 3)) +;;; eval: (save-excursion (goto-char (point-min)) (replace-regexp "[ \n]*)" ")")) +;;; eval: (indent-region (point-min) (point-max) nil) +;;; eval: (progn (kill-line -3) (delete-backward-char 1) (save-buffer)) +;;; End: diff --git a/demo/sgi/gl_panel/twoview/topview.s b/demo/sgi/gl_panel/twoview/topview.s new file mode 100644 index 0000000..0e380cc --- /dev/null +++ b/demo/sgi/gl_panel/twoview/topview.s @@ -0,0 +1,47 @@ +;;; This file was automatically generated by the panel editor. +;;; If you read it into gnu emacs, it will automagically format itself. + +(panel (prop help creator:user-panel-help) +(prop user-panel #t) +(label "Top View Control") +(x 1020) +(y 287) +(al (pnl_hslider (name "xpos") +(prop help creator:user-act-help) +(label "X") +(x 2) +(y 0.5) +(w 3.85) +(h 0.4) +(val 0.5) +(downfunc move-then-resize) +) +(pnl_vslider (name "zpos") +(prop help creator:user-act-help) +(label "Z") +(x 1.25) +(y 1.3) +(w 0.4) +(h 3.6) +(val 0.5) +(downfunc move-then-resize) +) +(pnl_dial (name "direction") +(prop help creator:user-act-help) +(label "looking direction") +(x 2.15) +(y 1.4) +(w 3.5) +(h 3.45) +(val 0.5) +(downfunc move-then-resize) +) +) +) +;;; Local Variables: +;;; mode: scheme +;;; eval: (save-excursion (goto-char (point-min)) (kill-line 3)) +;;; eval: (save-excursion (goto-char (point-min)) (replace-regexp "[ \n]*)" ")")) +;;; eval: (indent-region (point-min) (point-max) nil) +;;; eval: (progn (kill-line -3) (delete-backward-char 1) (save-buffer)) +;;; End: diff --git a/demo/sgi/gl_panel/twoview/twoview.py b/demo/sgi/gl_panel/twoview/twoview.py new file mode 100755 index 0000000..eea7c75 --- /dev/null +++ b/demo/sgi/gl_panel/twoview/twoview.py @@ -0,0 +1,395 @@ +#! /ufs/guido/bin/sgi/python + +# A demo of GL's viewing transformations, showing two views on one scene. +# Requires the NASA AMES Panel Library. Requires Z buffer. + +from gl import * +from GL import * +import panel +from math import sin, cos, pi + +inf = 1000000.0 +far = 1000.0 +near = 100.0 + +def main(): + foreground() + # + keepaspect(1, 1) + prefposition(10, 610, 10, 610) + obswid = winopen('Observer View') + doublebuffer() + RGBmode() + gconfig() + # + keepaspect(1, 1) + prefposition(10, 310, 650, 950) + topwid = winopen('Top View') + doublebuffer() + RGBmode() + gconfig() + # + panels = panel.defpanellist('observer.s') + panels = panels + panel.defpanellist('camera.s') + panels = panels + panel.defpanellist('topview.s') + # + p = panels[0] + q = panels[1] + r = panels[2] + # + p.farclip = q.farclip + p.nearclip = q.nearclip + p.zoom = q.zoom + p.quitbutton = q.quitbutton + # + p.xpos = r.xpos + p.zpos = r.zpos + p.direction = r.direction + # + p.direction.winds = 1.0 # allow full rotation + # + def quit(act): + import sys + sys.exit(0) + p.quitbutton.downfunc = quit + # + p.left.back = p + p.fast_left.back = p + p.right.back = p + p.fast_right.back = p + p.forward.back = p + p.fast_forward.back = p + p.reverse.back = p + p.fast_reverse.back = p + p.up.back = p + p.down.back = p + # + p.left.activefunc = left + p.fast_left.activefunc = fast_left + p.right.activefunc = right + p.fast_right.activefunc = fast_right + p.forward.activefunc = forward + p.fast_forward.activefunc = fast_forward + p.reverse.activefunc = reverse + p.fast_reverse.activefunc = fast_reverse + p.up.activefunc = up + p.down.activefunc = down + # + makeobjects() + # + drawall(p, obswid, topwid) + panel.needredraw() + while 1: + act = panel.dopanel() + if panel.userredraw() or act: + drawall(p, obswid, topwid) + +def left(a): + doturn(a.back, 0.01) + +def fast_left(a): + doturn(a.back, 0.1) + +def right(a): + doturn(a.back, -0.01) + +def fast_right(a): + doturn(a.back, -0.1) + +def doturn(p, angle): + alpha = lookangle(p) + angle + # Reverse the following assignment: + # alpha = pi*1.5 - p.direction.val*2.0*pi + val = (pi*1.5 - alpha) / 2.0 / pi + while val < 0.0: val = val + 1.0 + while val > 1.0: val = val - 1.0 + p.direction.val = val + p.direction.fixact() + +def forward(a): + dostep(a.back, 1.0) + +def fast_forward(a): + dostep(a.back, 10.0) + +def reverse(a): + dostep(a.back, -1.0) + +def fast_reverse(a): + dostep(a.back, -10.0) + +def dostep(p, step): + x, y, z = observerpos(p) + alpha = lookangle(p) + x = x + step*cos(alpha) + z = z - step*sin(alpha) + # Reverse the following assignments: + # x = 2.0 * p.xpos.val * near - near + # z = near - 2.0 * p.zpos.val * near + p.xpos.val = (x + near) / 2.0 / near + p.zpos.val = - (z - near) / 2.0 / near + p.xpos.fixact() + p.zpos.fixact() + +def up(a): + doup(a.back, 0.2) + +def down(a): + doup(a.back, -0.2) + +def doup(p, step): + x, y, z = observerpos(p) + y = y + step + # Reverse: + # y = p.ypos.val * near + p.ypos.val = y/near + p.ypos.fixact() + +def drawall(p, obswid, topwid): + # + winset(obswid) + obsview(p) + drawscene() + swapbuffers() + # + winset(topwid) + topview(p) + drawscene() + drawobserver(p) + swapbuffers() + +def drawobserver(p): + x, y, z = observerpos(p) + alpha = lookangle(p) + fov = 2.0 + 1798.0 * p.zoom.val + beta = fov*pi/3600.0 # Half fov, expressed in radians + # + c3i(0, 255, 0) + # + move(x, y, z) + x1 = x + inf*cos(alpha+beta) + y1 = y + z1 = z - inf*sin(alpha+beta) + draw(x1, y1, z1) + # + move(x, y, z) + x1 = x + inf*cos(alpha-beta) + y1 = y + z1 = z - inf*sin(alpha-beta) + draw(x1, y1, z1) + +def observerlookat(p): + x, y, z = observerpos(p) + alpha = lookangle(p) + return x, y, z, x+near*cos(alpha), y, z-near*sin(alpha), 0 + +def observerpos(p): + x = 2.0 * p.xpos.val * near - near + y = p.ypos.val * near + z = near - 2.0 * p.zpos.val * near + return x, y, z + +def lookangle(p): + return pi*1.5 - p.direction.val*2.0*pi + +idmat = 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 + +def topview(p): + mmode(MVIEWING) + ortho(-far, far, -far, far, far, -far) + loadmatrix(idmat) + rotate(900, 'x') + +def obsview(p): + fov = 2.0 + 1798.0 * p.zoom.val + nearclip = p.nearclip.val * 10.0 + farclip = p.farclip.val * 10.0*far + aspectratio = 1.0 + mmode(MVIEWING) + perspective(int(fov), aspectratio, nearclip, farclip) + loadmatrix(idmat) + lookat(observerlookat(p)) + +def drawscene(): + # + # clear window + # + c3i(0, 0, 0) + clear() + # + # turn on z buffering and clear it + # + zbuffer(TRUE) + zclear() + # + # dark blue sky (depending on your gamma value!) + # + c3i(0, 0, 150) + callobj(41) + # + # bright red near and far units circle + # (use rotate since circ() always draws in x-y plane) + # + c3i(255, 0, 0) + pushmatrix() + rotate(900, 'x') + circ(0.0, 0.0, near) + circ(0.0, 0.0, far) + popmatrix() + # + # bright white striping + # + c3i(255, 255, 200) + callobj(42) + # + # building (does its own colors) + # + building() + # + # some other objects + # + dice() + +def makeobjects(): + # + # sky object + # + makeobj(41) + pmv(-inf, 0.0, -far) + pdr(inf, 0.0, -far) + pdr(inf, inf, -far) + pdr(-inf, inf, -far) + pclos() + closeobj() + # + # road stripes object + # + makeobj(42) + stripes() + closeobj() + # + # lighting model definitions + # + deflight() + +def stripes(): + # + # left line + # + botrect(-11, -10, far, -far) + # + # right line + # + botrect(10, 11, far, -far) + # + # center lines + # + z = far + while z > -far: + botrect(-0.5, 0.5, z, z - 4.0) + z = z - 10.0 + +def dice(): + from block import block + uselight() + pushmatrix() + translate(0.0, 1.0, -20.0) + rotate(200, 'y') + block(1, 0, 0, 0, 0, 0) + translate(1.0, 0.0, 3.0) + rotate(500, 'y') + block(2, 0, 0, 0, 0, 0) + popmatrix() + +def deflight(): + # Material for first die (red) + lmdef(DEFMATERIAL, 1, (DIFFUSE, 1.0, 0.0, 0.0)) + # Material for second die (green) + lmdef(DEFMATERIAL, 2, (DIFFUSE, 0.0, 1.0, 0.0)) + # First light source (default: white, from front) + lmdef(DEFLIGHT, 1, ()) + # Second light source (red, from back) + lmdef(DEFLIGHT, 2, (POSITION, 0.0, 1.0, -1.0, 0.0)) + lmdef(DEFLIGHT, 2, (LCOLOR, 1.0, 0.0, 0.0)) + # Lighting model + lmdef(DEFLMODEL, 1, (AMBIENT, 0.0, 0.0, 1.0)) + +def uselight(): + lmbind(LIGHT0, 1) + lmbind(LIGHT1, 2) + lmbind(LMODEL, 1) + # (materials are bound later) + +def building(): + # + c3i(0, 255, 255) + # + # house bounding coordinates + # + x1 = 20.0 + x1a = 25.0 + x2 = 30.0 + y1 = 0.0 + y2 = 15.0 + y2a = 20.0 + z1 = -40.0 + z2 = -55.0 + # + # door y and z coordinates + # + dy1 = 0.0 + dy2 = 4.0 + dz1 = -45.0 + dz2 = -47.0 + # + # front side (seen from origin) + # + A1 = (x1, y1, z1) + B1 = (x2, y1, z1) + C1 = (x2, y2, z1) + D1 = (x1a, y2a, z1) + E1 = (x1, y2, z1) + # + # back size + # + A2 = (x1, y1, z2) + B2 = (x2, y1, z2) + C2 = (x2, y2, z2) + D2 = (x1a, y2a, z2) + E2 = (x1, y2, z2) + # + # door in the left side + # + P = x1, dy1, dz2 + Q = x1, dy2, dz2 + R = x1, dy2, dz1 + S = x1, dy1, dz1 + # + # draw it + # + concave(TRUE) + c3i(255, 0, 0) + face(A1, B1, C1, D1, E1) + c3i(127, 127, 0) + face(A1, E1, E2, A2, P, Q, R, S) + c3i(0, 255, 0) + face(E1, D1, D2, E2) + c3i(0, 127, 127) + face(D1, C1, C2, D2) + c3i(0, 0, 255) + face(C1, B1, B2, C2) + c3i(127, 0, 127) + face(E2, D2, C2, B2, A2) + concave(FALSE) + +def face(points): + bgnpolygon() + varray(points) + endpolygon() + +# draw a rectangle at y=0.0 +# +def botrect(x1, x2, z1, z2): + polf(x1, 0.0, z1, x2, 0.0, z1, x2, 0.0, z2, x1, 0.0, z2) + +main() diff --git a/demo/stdwin/wdiff.py b/demo/stdwin/wdiff.py new file mode 100755 index 0000000..bc005f8 --- /dev/null +++ b/demo/stdwin/wdiff.py @@ -0,0 +1,480 @@ +#! /ufs/guido/bin/sgi/python + +# A window-oriented recursive diff utility. +# NB: This uses undocumented window classing modules. + +# TO DO: +# - faster update after moving/copying one file +# - diff flags (-b, etc.) should be global or maintained per window +# - use a few fixed windows instead of creating new ones all the time +# - ways to specify patterns to skip +# (best by pointing at a file and clicking a special menu entry!) +# - add rcsdiff menu commands +# - add a way to view status of selected files without opening them +# - add a way to diff two files with different names +# - add a way to rename files +# - keep backups of overwritten/deleted files +# - a way to mark specified files as uninteresting for dircmp + +import sys +import posix +import path +import rand +import commands +import dircache +import statcache +import cmp +import cmpcache +import stdwin +import gwin +import textwin +import filewin +import tablewin +import anywin + +mkarg = commands.mkarg +mk2arg = commands.mk2arg + +# List of names to ignore in dircmp() +# (Should be done with function, so we can specify patterns as well) +# +skiplist = ['RCS', '.Amake', 'tags', '.', '..'] + + +def anydiff(a, b, flags): # Display differences between any two objects + print 'diff', flags, a, b + if path.isdir(a) and path.isdir(b): + w = dirdiff(a, b, flags) + else: + w = filediff(a, b, flags) + addstatmenu(w, [a, b]) + w.original_close = w.close + w.close = close_dirwin + return w + +def close_dirwin(w): + close_subwindows(w, (), 0) + w.original_close(w) + +def filediff(a, b, flags): # Display differences between two text files + diffcmd = 'diff' + if flags: diffcmd = diffcmd + mkarg(flags) + diffcmd = diffcmd + mkarg(a) + mkarg(b) + difftext = commands.getoutput(diffcmd) + return textwin.open_readonly(mktitle(a, b), difftext) + +def dirdiff(a, b, flags): # Display differences between two directories + data = diffdata(a, b, flags) + w = tablewin.open(mktitle(a, b), data) + w.flags = flags + w.a = a + w.b = b + addviewmenu(w) + addactionmenu(w) + return w + +def diffdata(a, b, flags): # Compute directory differences. + # + a_only = [('A only:', header_action), ('', header_action)] + b_only = [('B only:', header_action), ('', header_action)] + ab_diff = [('A <> B:', header_action), ('', header_action)] + ab_same = [('A == B:', header_action), ('', header_action)] + data = [a_only, b_only, ab_diff, ab_same] + # + a_list = dircache.listdir(a)[:] + b_list = dircache.listdir(b)[:] + dircache.annotate(a, a_list) + dircache.annotate(b, b_list) + a_list.sort() + b_list.sort() + # + for x in a_list: + if x in ['./', '../']: + pass + elif x not in b_list: + a_only.append(x, a_only_action) + else: + ax = path.cat(a, x) + bx = path.cat(b, x) + if path.isdir(ax) and path.isdir(bx): + if flags = '-r': + same = dircmp(ax, bx) + else: + same = 0 + else: + try: + same = cmp.cmp(ax, bx) + except posix.error: + same = 0 + if same: + ab_same.append(x, ab_same_action) + else: + ab_diff.append(x, ab_diff_action) + # + for x in b_list: + if x in ['./', '../']: + pass + elif x not in a_list: + b_only.append(x, b_only_action) + # + return data + +# Re-read the directory. +# Attempt to find the selected item back. + +def update(w): + setbusy(w) + icol, irow = w.selection + if 0 <= icol < len(w.data) and 2 <= irow < len(w.data[icol]): + selname = w.data[icol][irow][0] + else: + selname = '' + statcache.forget_dir(w.a) + statcache.forget_dir(w.b) + tablewin.select(w, (-1, -1)) + tablewin.update(w, diffdata(w.a, w.b, w.flags)) + if selname: + for icol in range(len(w.data)): + for irow in range(2, len(w.data[icol])): + if w.data[icol][irow][0] = selname: + tablewin.select(w, (icol, irow)) + break + +# Action functions for table items in directory diff windows + +def header_action(w, string, (icol, irow), (pos, clicks, button, mask)): + tablewin.select(w, (-1, -1)) + +def a_only_action(w, string, (icol, irow), (pos, clicks, button, mask)): + tablewin.select(w, (icol, irow)) + if clicks = 2: + w2 = anyopen(path.cat(w.a, string)) + if w2: + w2.parent = w + +def b_only_action(w, string, (icol, irow), (pos, clicks, button, mask)): + tablewin.select(w, (icol, irow)) + if clicks = 2: + w2 = anyopen(path.cat(w.b, string)) + if w2: + w2.parent = w + +def ab_diff_action(w, string, (icol, irow), (pos, clicks, button, mask)): + tablewin.select(w, (icol, irow)) + if clicks = 2: + w2 = anydiff(path.cat(w.a, string), path.cat(w.b, string), '') + w2.parent = w + +def ab_same_action(w, string, sel, detail): + ax = path.cat(w.a, string) + if path.isdir(ax): + ab_diff_action(w, string, sel, detail) + else: + a_only_action(w, string, sel, detail) + +def anyopen(name): # Open any kind of document, ignore errors + try: + w = anywin.open(name) + except (RuntimeError, posix.error): + stdwin.message('Can\'t open ' + name) + return 0 + addstatmenu(w, [name]) + return w + +def dircmp(a, b): # Compare whether two directories are the same + # To make this as fast as possible, it uses the statcache + print ' dircmp', a, b + a_list = dircache.listdir(a) + b_list = dircache.listdir(b) + for x in a_list: + if x in skiplist: + pass + elif x not in b_list: + return 0 + else: + ax = path.cat(a, x) + bx = path.cat(b, x) + if statcache.isdir(ax) and statcache.isdir(bx): + if not dircmp(ax, bx): return 0 + else: + try: + if not cmpcache.cmp(ax, bx): return 0 + except posix.error: + return 0 + for x in b_list: + if x in skiplist: + pass + elif x not in a_list: + return 0 + return 1 + + +# View menu (for dir diff windows only) + +def addviewmenu(w): + w.viewmenu = m = w.menucreate('View') + m.action = [] + add(m, 'diff -r A B', diffr_ab) + add(m, 'diff A B', diff_ab) + add(m, 'diff -b A B', diffb_ab) + add(m, 'diff -c A B', diffc_ab) + add(m, 'gdiff A B', gdiff_ab) + add(m, ('Open A ', 'A'), open_a) + add(m, ('Open B ', 'B'), open_b) + add(m, 'Rescan', rescan) + add(m, 'Rescan -r', rescan_r) + +# Action menu (for dir diff windows only) + +def addactionmenu(w): + w.actionmenu = m = w.menucreate('Action') + m.action = [] + add(m, 'cp A B', cp_ab) + add(m, 'rm B', rm_b) + add(m, '', nop) + add(m, 'cp B A', cp_ba) + add(m, 'rm A', rm_a) + +# Main menu (global): + +def mainmenu(): + m = stdwin.menucreate('Wdiff') + m.action = [] + add(m, ('Quit wdiff', 'Q'), quit_wdiff) + add(m, 'Close subwindows', close_subwindows) + return m + +def add(m, text, action): + m.additem(text) + m.action.append(action) + +def quit_wdiff(w, m, item): + if askyesno('Really quit wdiff altogether?', 1): + sys.exit(0) + +def close_subwindows(w, m, item): + while 1: + for w2 in gwin.windows: + if w2.parent = w: + close_subwindows(w2, m, item) + w2.close(w2) + break # inner loop, continue outer loop + else: + break # outer loop + +def diffr_ab(w, m, item): + dodiff(w, '-r') + +def diff_ab(w, m, item): + dodiff(w, '') + +def diffb_ab(w, m, item): + dodiff(w, '-b') + +def diffc_ab(w, m, item): + dodiff(w, '-c') + +def gdiff_ab(w, m, item): # Call SGI's gdiff utility + x = getselection(w) + if x: + a, b = path.cat(w.a, x), path.cat(w.b, x) + if path.isdir(a) or path.isdir(b): + stdwin.fleep() # This is for files only + else: + diffcmd = 'gdiff' + diffcmd = diffcmd + mkarg(a) + mkarg(b) + ' &' + print diffcmd + sts = posix.system(diffcmd) + if sts: print 'Exit status', sts + +def dodiff(w, flags): + x = getselection(w) + if x: + w2 = anydiff(path.cat(w.a, x), path.cat(w.b, x), flags) + w2.parent = w + +def open_a(w, m, item): + x = getselection(w) + if x: + w2 = anyopen(path.cat(w.a, x)) + if w2: + w2.parent = w + +def open_b(w, m, item): + x = getselection(w) + if x: + w2 = anyopen(path.cat(w.b, x)) + if w2: + w2.parent = w + +def rescan(w, m, item): + w.flags = '' + update(w) + +def rescan_r(w, m, item): + w.flags = '-r' + update(w) + +def rm_a(w, m, item): + x = getselection(w) + if x: + if x[-1:] = '/': x = x[:-1] + x = path.cat(w.a, x) + if path.isdir(x): + if askyesno('Recursively remove A directory ' + x, 1): + runcmd('rm -rf' + mkarg(x)) + else: + runcmd('rm -f' + mkarg(x)) + update(w) + +def rm_b(w, m, item): + x = getselection(w) + if x: + if x[-1:] = '/': x = x[:-1] + x = path.cat(w.b, x) + if path.isdir(x): + if askyesno('Recursively remove B directory ' + x, 1): + runcmd('rm -rf' + mkarg(x)) + else: + runcmd('rm -f' + mkarg(x)) + update(w) + +def cp_ab(w, m, item): + x = getselection(w) + if x: + if x[-1:] = '/': x = x[:-1] + ax = path.cat(w.a, x) + bx = path.cat(w.b, x) + if path.isdir(ax): + if path.exists(bx): + m = 'Can\'t copy directory to existing target' + stdwin.message(m) + return + runcmd('cp -r' + mkarg(ax) + mkarg(w.b)) + else: + runcmd('cp' + mkarg(ax) + mk2arg(w.b, x)) + update(w) + +def cp_ba(w, m, item): + x = getselection(w) + if x: + if x[-1:] = '/': x = x[:-1] + ax = path.cat(w.a, x) + bx = path.cat(w.b, x) + if path.isdir(bx): + if path.exists(ax): + m = 'Can\'t copy directory to existing target' + stdwin.message(m) + return + runcmd('cp -r' + mkarg(bx) + mkarg(w.a)) + else: + runcmd('cp' + mk2arg(w.b, x) + mkarg(ax)) + update(w) + +def nop(args): + pass + +def getselection(w): + icol, irow = w.selection + if 0 <= icol < len(w.data): + if 0 <= irow < len(w.data[icol]): + return w.data[icol][irow][0] + stdwin.message('no selection') + return '' + +def runcmd(cmd): + print cmd + sts, output = commands.getstatusoutput(cmd) + if sts or output: + if not output: + output = 'Exit status ' + `sts` + stdwin.message(output) + + +# Status menu (for all kinds of windows) + +def addstatmenu(w, files): + w.statmenu = m = w.menucreate('Stat') + m.files = files + m.action = [] + for file in files: + m.additem(commands.getstatus(file)) + m.action.append(stataction) + +def stataction(w, m, item): # Menu item action for stat menu + file = m.files[item] + try: + m.setitem(item, commands.getstatus(file)) + except posix.error: + stdwin.message('Can\'t get status for ' + file) + + +# Compute a suitable window title from two paths + +def mktitle(a, b): + if a = b: return a + i = 1 + while a[-i:] = b[-i:]: i = i+1 + i = i-1 + if not i: + return a + ' ' + b + else: + return '{' + a[:-i] + ',' + b[:-i] + '}' + a[-i:] + + +# Ask a confirmation question + +def askyesno(prompt, default): + try: + return stdwin.askync(prompt, default) + except KeyboardInterrupt: + return 0 + + +# Display a message "busy" in a window, and mark it for updating + +def setbusy(w): + left, top = w.getorigin() + width, height = w.getwinsize() + right, bottom = left + width, top + height + d = w.begindrawing() + d.erase((0, 0), (10000, 10000)) + text = 'Busy...' + textwidth = d.textwidth(text) + textheight = d.lineheight() + h, v = left + (width-textwidth)/2, top + (height-textheight)/2 + d.text((h, v), text) + del d + w.change((0, 0), (10000, 10000)) + + +# Main function + +def main(): + print 'wdiff: warning: this version does NOT yet make backups' + argv = sys.argv + flags = '' + if len(argv) >= 2 and argv[1][:1] = '-': + flags = argv[1] + del argv[1] + m = mainmenu() # Create menu earlier than windows + if len(argv) = 2: # 1 argument + w = anyopen(argv[1]) + if not w: return + elif len(argv) = 3: # 2 arguments + w = anydiff(argv[1], argv[2], flags) + w.parent = () + else: + sys.stdout = sys.stderr + print 'usage:', argv[0], '[diff-flags] dir-1 [dir-2]' + sys.exit(2) + del w # It's preserved in gwin.windows + while 1: + try: + gwin.mainloop() + break + except KeyboardInterrupt: + pass # Just continue... + +# Start the main function (this is a script) +main() diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..f2a83bf --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,47 @@ +# Makefile for Python documentation. + +LATEX= latex +DVIPS= dvips +TEXPREVIEW= xdvi + +PRINT= lpr + +tut: tut.dvi + $(TEXPREVIEW) tut + +tut.dvi tut.ps: tut.toc tut.tex myformat.sty + +mod: mod.dvi + $(TEXPREVIEW) mod + +mod.dvi mod.ps: mod.toc mod.tex mod1.tex mod2.tex mod3.tex myformat.sty + +ALL= tut.ps mod.ps + +all: $(ALL) + +print: $(ALL) + $(PRINT) $(ALL) + +clean: + rm -f *.dvi *.aux *.toc *.log *.ps core [#@,]* *~ + +.SUFFIXES: # Remove default suffixes + +.SUFFIXES: .tex .aux .toc .dvi .ps + +.tex.aux: + $(LATEX) $* + +.tex.toc: + $(LATEX) $* + +.tex.dvi: + $(LATEX) $* + +.dvi.ps: + $(DVIPS) $* >$*.ps + +.tex.ps: + $(LATEX) $* + $(DVIPS) $* >$*.ps diff --git a/doc/README b/doc/README new file mode 100644 index 0000000..14c3de9 --- /dev/null +++ b/doc/README @@ -0,0 +1,24 @@ +This directory contains the LaTeX source to the Python documentation. +The documentation is not all finished, but good enough to get you +started. + +The following are the important latex source files: + + tut.tex A tutorial + mod.tex The library reference + +They both read the style option file "myformat.sty". + +You can use the Makefile to format, preview and print the documents. +Type "make tut" or "make mod" to preview either document with xdvi. +Type "make print" to print them both (this only works if your print +spooler is set up just like mine...), or "make all" to create postscript +files that you can you can print using your local printing commands. +Type "make clean" to get rid of all the intermediate files produced by +the latex process, and other junk files. + +You can just as well ignore the Makefile; all you really need is: + latex tut + latex tut + dvips tut | lpr +and similar for the "mod" document. diff --git a/doc/SetClass.py b/doc/SetClass.py new file mode 100644 index 0000000..8a5fb9e --- /dev/null +++ b/doc/SetClass.py @@ -0,0 +1,17 @@ +class Set(): + def new(self): + self.elements = [] + return self + def add(self, e): + if e not in self.elements: + self.elements.append(e) + def remove(self, e): + if e in self.elements: + for i in range(len(self.elements)): + if self.elements[i] = e: + del self.elements[i] + break + def is_element(self, e): + return e in self.elements + def size(self): + return len(self.elements) diff --git a/doc/fibo.py b/doc/fibo.py new file mode 100644 index 0000000..e8cafa8 --- /dev/null +++ b/doc/fibo.py @@ -0,0 +1,15 @@ +# Fibonacci numbers demo + +def fib(n): # write Fibonacci series up to n + a, b = 0, 1 + while b <= n: + print b, + a, b = b, a+b + +def fib2(n): # return Fibonacci series up to n + ret = [] + a, b = 0, 1 + while b <= n: + ret.append(b) + a, b = b, a+b + return ret diff --git a/doc/mod.tex b/doc/mod.tex new file mode 100644 index 0000000..c2d2355 --- /dev/null +++ b/doc/mod.tex @@ -0,0 +1,62 @@ +% Format this file with latex. + +%\documentstyle[garamond,11pt,myformat]{article} +\documentstyle[11pt,myformat]{article} + +% A command to force the text after an item to start on a new line +\newcommand{\itembreak}{ + \mbox{}\\*[0mm] +} + +% A command to define a function item +\newcommand{\funcitem}[2]{\item[#1(#2)]} + +% A command to define an exception item +\newcommand{\excitem}[2]{ +\item[#1 = {\tt '#2'}] +\itembreak +} + +\title{\bf + Python Library Reference \\ + (DRAFT) +} + +\author{ + Guido van Rossum \\ + Dept. CST, CWI, Kruislaan 413 \\ + 1098 SJ Amsterdam, The Netherlands \\ + E-mail: {\tt [email protected]} +} + +\begin{document} + +\pagenumbering{roman} + +\maketitle + +\begin{abstract} + +\noindent +This document describes the built-in types, exceptions and functions and +the standard modules that come with the {\Python} system. +It assumes basic knowledge about the {\Python} language. +For an informal introduction to the language, see the Tutorial document. +The Language Reference document (XXX not yet existing) +gives a more formal reference to the language. + +\end{abstract} + +\pagebreak + +\tableofcontents + +\pagebreak + +\pagenumbering{arabic} + +\input{mod1.tex} +\input{mod2.tex} +\input{mod3.tex} + +\end{document} diff --git a/doc/mod1.tex b/doc/mod1.tex new file mode 100644 index 0000000..2dac554 --- /dev/null +++ b/doc/mod1.tex @@ -0,0 +1,521 @@ +\section{Introduction} + +The {\Python} library consists of three parts, with different levels of +integration with the interpreter. +Closest to the interpreter are built-in types, exceptions and functions. +Next are built-in modules, which are written in C and linked statically +with the interpreter. +Finally there are standard modules that are implemented entirely in +{\Python}, but are always available. +For efficiency, some standard modules may become built-in modules in +future versions of the interpreter. + +\section{Built-in Types, Exceptions and Functions} + +Names for built-in exceptions and functions are found in a separate +read-only symbol table which cannot be modified. +This table is searched last, so local and global user-defined names can +override built-in names. +Built-in types have no names but are created by syntactic constructs +(such as constants) or built-in functions. +They are described together here for easy reference.% +\footnote{ +The descriptions sorely lack explanations of the exceptions that +may be raised---this will be fixed in a future version of this +document. +} + +\subsection{Built-in Types} + +The following sections describe the standard types that are built into the +interpreter. +\subsubsection{Numeric Types} + +There are two numeric types: integers and floating point numbers. +Integers are implemented using {\tt long} in C, so they have at least 32 +bits of precision. +Floating point numbers are implemented using {\tt double} in C. +All bets on precision are off. +Numbers are created by numeric constants or as the result of built-in +functions and operators. + +Numeric types support the following operations: + +\begin{center} +\begin{tabular}{|c|l|c|} +\hline +Operation & Result & Notes \\ +\hline +{\tt abs}({\em x}) & absolute value of {\em x} & \\ +{\tt int}({\em x}) & {\em x} converted to integer & (1) \\ +{\tt float}({\em x}) & {\em x} converted to floating point & \\ +{\tt -}{\em x} & {\em x} negated & \\ +{\tt +}{\em x} & {\em x} unchanged & \\ +{\em x}{\tt +}{\em y} & sum of {\em x} and {\em y} & \\ +{\em x}{\tt -}{\em y} & difference of {\em x} and {\em y} & \\ +{\em x}{\tt *}{\em y} & product of {\em x} and {\em y} & \\ +{\em x}{\tt /}{\em y} & quotient of {\em x} and {\em y} & (2) \\ +{\em x}{\tt \%}{\em y} & remainder of {\em x}{\tt /}{\em y} & (3) \\ +\hline +\end{tabular} +\end{center} + +\noindent +Notes: +\begin{description} +\item[(1)] +This may round or truncate as in C; see functions {\tt floor} and +{\tt ceil} in module {\tt math}. +\item[(2)] +Integer division is defined as in C: the result is an integer; with +positive operands, it truncates towards zero; with a negative operand, +the result is unspecified. +\item[(3)] +Only defined for integers. +\end{description} + +Mixed arithmetic is not supported; both operands must have the same type. +Mixed comparisons return the wrong result (floats always compare smaller +than integers).% +\footnote{ +These restrictions are bugs in the language definitions and will be +fixed in the future. +} +\subsubsection{Sequence Types} + +There are three sequence types: strings, lists and tuples. +Strings constants are written in single quotes: {\tt 'xyzzy'}. +Lists are constructed with square brackets: {\tt [a,~b,~c]}. +Tuples are constructed by the comma operator or with an empty set of +parentheses: {\tt a,~b,~c} or {\tt ()}. + +Sequence types support the following operations ({\em s} and {\em t} are +sequences of the same type; {\em n}, {\em i} and {\em j} are integers): + +\begin{center} +\begin{tabular}{|c|l|c|} +\hline +Operation & Result & Notes \\ +\hline +{\tt len}({\em s}) & length of {\em s} & \\ +{\tt min}({\em s}) & smallest item of {\em s} & \\ +{\tt max}({\em s}) & largest item of {\em s} & \\ +{\em x} {\tt in} {\em s} & + true if an item of {\em s} is equal to {\em x} & \\ +{\em x} {\tt not} {\tt in} {\em s} & + false if an item of {\em s} is equal to {\em x} & \\ +{\em s}{\tt +}{\em t} & the concatenation of {\em s} and {\em t} & \\ +{\em s}{\tt *}{\em n}, {\em n}*{\em s} & + {\em n} copies of {\em s} concatenated & (1) \\ +{\em s}[{\em i}] & {\em i}'th item of {\em s} & \\ +{\em s}[{\em i}:{\em j}] & + slice of {\em s} from {\em i} to {\em j} & (2) \\ +\hline +\end{tabular} +\end{center} + +\noindent +Notes: +\begin{description} +\item[(1)] +Sequence repetition is only supported for strings. +\item[(2)] +The slice of $s$ from $i$ to $j$ is defined as the sequence +of items with index $k$ such that $i \leq k < j$. +Special rules apply for negative and omitted indices; see the Tutorial +or the Reference Manual. +\end{description} + +\paragraph{Mutable Sequence Types.} + +List objects support additional operations that allow in-place +modification of the object. +These operations would be supported by other mutable sequence types +(when added to the language) as well. +Strings and tuples are immutable sequence types and such objects cannot +be modified once created. +The following operations are defined on mutable sequence types (where +{\em x} is an arbitrary object): + +\begin{center} +\begin{tabular}{|c|l|} +\hline +Operation & Result \\ +\hline +{\em s}[{\em i}] = {\em x} & + item {\em i} of {\em s} is replaced by {\em x} \\ +{\em s}[{\em i}:{\em j}] = {\em t} & + slice of {\em s} from {\em i} to {\em j} is replaced by {\em t} \\ +{\tt del} {\em s}[{\em i}:{\em j}] & + same as {\em s}[{\em i}:{\em j}] = [] \\ +{\em s}.{\tt append}({\em x}) & + same as {\em s}[{\tt len}({\em x}):{\tt len}({\em x})] = [{\em x}] \\ +{\em s}.{\tt insert}({\em i}, {\em x}) & + same as {\em s}[{\em i}:{\em i}] = [{\em x}] \\ +{\em s}.{\tt sort}() & + the items of {\em s} are permuted to satisfy \\ + & + $s[i] \leq s[j]$ for $i < j$\\ +\hline +\end{tabular} +\end{center} + +\subsubsection{Mapping Types} + +A +{\em mapping} +object maps values of one type (the key type) to arbitrary objects. +Mappings are mutable objects. +There is currently only one mapping type, the +{\em dictionary}. +A dictionary's keys are strings. +An empty dictionary is created by the expression \verb"{}". +An extension of this notation is used to display dictionaries when +written (see the example below). + +The following operations are defined on mappings (where {\em a} is a +mapping, {\em k} is a key and {\em x} is an arbitrary object): + +\begin{center} +\begin{tabular}{|c|l|c|} +\hline +Operation & Result & Notes\\ +\hline +{\tt len}({\em a}) & the number of elements in {\em a} & \\ +{\em a}[{\em k}] & the item of {\em a} with key {\em k} & \\ +{\em a}[{\em k}] = {\em x} & set {\em a}[{\em k}] to {\em x} & \\ +{\tt del} {\em a}[{\em k}] & remove {\em a}[{\em k}] from {\em a} & \\ +{\em a}.{\tt keys}() & a copy of {\em a}'s list of keys & (1) \\ +{\em a}.{\tt has\_key}({\em k}) & true if {\em a} has a key {\em k} & \\ +\hline +\end{tabular} +\end{center} + +\noindent +Notes: +\begin{description} +\item[(1)] +Keys are listed in random order. +\end{description} + +A small example using a dictionary: +\bcode\begin{verbatim} +>>> tel = {} +>>> tel['jack'] = 4098 +>>> tel['sape'] = 4139 +>>> tel['guido'] = 4127 +>>> tel['jack'] +4098 +>>> tel +{'sape': 4139; 'guido': 4127; 'jack': 4098} +>>> del tel['sape'] +>>> tel['irv'] = 4127 +>>> tel +{'guido': 4127; 'irv': 4127; 'jack': 4098} +>>> tel.keys() +['guido', 'irv', 'jack'] +>>> tel.has_key('guido') +1 +>>> +\end{verbatim}\ecode +\subsubsection{Other Built-in Types} + +The interpreter supports several other kinds of objects. +Most of these support only one or two operations. + +\paragraph{Modules.} + +The only operation on a module is member acces: {\em m}{\tt .}{\em name}, +where {\em m} is a module and {\em name} accesses a name defined in +{\em m}'s symbol table. +Module members can be assigned to. + +\paragraph{Classes and Class Objects.} + +XXX Classes will be explained at length in a later version of this +document. + +\paragraph{Functions.} + +Function objects are created by function definitions. +The only operation on a function object is to call it: +{\em func}({\em optional-arguments}). + +Built-in functions have a different type than user-defined functions, +but they support the same operation. + +\paragraph{Methods.} + +Methods are functions that are called using the member acces notation. +There are two flavors: built-in methods (such as {\tt append()} on +lists) and class member methods. +Built-in methods are described with the types that support them. +XXX Class member methods will be described in a later version of this +document. + +\paragraph{Type Objects.} + +Type objects represent the various object types. +An object's type is accessed by the built-in function +{\tt type()}. +There are no operations on type objects. + +\paragraph{The Null Object.} + +This object is returned by functions that don't explicitly return a +value. +It supports no operations. +There is exactly one null object, named {\tt None} +(a built-in name). + +\paragraph{File Objects.} + +File objects are implemented using C's +{\em stdio} +package and can be created with the built-in function +{\tt open()}. +They have the following methods: +\begin{description} +\funcitem{close}{} +Closes the file. +A closed file cannot be read or written anymore. +\funcitem{read}{size} +Reads at most +{\tt size} +bytes from the file (less if the read hits EOF). +The bytes are returned as a string object. +An empty string is returned when EOF is hit immediately. +(For certain files, like ttys, it makes sense to continue reading after +an EOF is hit.) +\funcitem{readline}{size} +Reads a line of at most +{\tt size} +bytes from the file. +A trailing newline character, if present, is kept in the string. +The size is optional and defaults to a large number (but not infinity). +EOF is reported as by +{\tt read().} +\funcitem{write}{str} +Writes a string to the file. +Returns no value. +\end{description} + +\subsection{Built-in Exceptions} + +The following exceptions can be generated by the interpreter or +built-in functions. +Except where mentioned, they have a string argument (also known as the +`associated value' of an exception) indicating the detailed cause of the +error. +The strings listed with the exception names are their values when used +in an expression or printed. +\begin{description} +\excitem{EOFError}{end-of-file read} +(No argument.) +Raised when a built-in function ({\tt input()} or {\tt raw\_input()}) +hits an end-of-file condition (EOF) without reading any data. +(N.B.: the {\tt read()} and {\tt readline()} methods of file objects +return an empty string when they hit EOF.) +\excitem{KeyboardInterrupt}{end-of-file read} +(No argument.) +Raised when the user hits the interrupt key (normally Control-C or DEL). +During execution, a check for interrupts is made regularly. +Interrupts typed when a built-in function ({\tt input()} or +{\tt raw\_input()}) is waiting for input also raise this exception. +\excitem{MemoryError}{out of memory} +%.br +Raised when an operation runs out of memory but the situation +may still be rescued (by deleting some objects). +\excitem{NameError}{undefined name} +%.br +Raised when a name is not found. +This applies to unqualified names, module names (on {\tt import}), +module members and object methods. +The string argument is the name that could not be found. +\excitem{RuntimeError}{run-time error} +%.br +Raised for a variety of reasons, e.g., division by zero or index out of +range. +\excitem{SystemError}{system error} +%.br +Raised when the interpreter finds an internal error, but the situation +does not look so serious to cause it to abandon all hope. +\excitem{TypeError}{type error} +%.br +Raised when an operation or built-in function is applied to an object of +inappropriate type. +\end{description} + +\subsection{Built-in Functions} + +The {\Python} interpreter has a small number of functions built into it that +are always available. +They are listed here in alphabetical order. +\begin{description} +\funcitem{abs}{x} +Returns the absolute value of a number. +The argument may be an integer or floating point number. +\funcitem{chr}{i} +Returns a string of one character +whose ASCII code is the integer {\tt i}, +e.g., {\tt chr(97)} returns the string {\tt 'a'}. +This is the inverse of {\tt ord()}. +\funcitem{dir}{} +Without arguments, this function returns the list of names in the +current local symbol table, sorted alphabetically. +With a module object as argument, it returns the sorted list of names in +that module's global symbol table. +For example: +\bcode\begin{verbatim} +>>> import sys +>>> dir() +['sys'] +>>> dir(sys) +['argv', 'exit', 'modules', 'path', 'stderr', 'stdin', 'stdout'] +>>> +\end{verbatim}\ecode +\funcitem{divmod}{a, b} +%.br +Takes two integers as arguments and returns a pair of integers +consisting of their quotient and remainder. +For +\bcode\begin{verbatim} +q, r = divmod(a, b) +\end{verbatim}\ecode +the invariants are: +\bcode\begin{verbatim} +a = q*b + r +abs(r) < abs(b) +r has the same sign as b +\end{verbatim}\ecode +For example: +\bcode\begin{verbatim} +>>> divmod(100, 7) +(14, 2) +>>> divmod(-100, 7) +(-15, 5) +>>> divmod(100, -7) +(-15, -5) +>>> divmod(-100, -7) +(14, -2) +>>> +\end{verbatim}\ecode +\funcitem{eval}{s} +Takes a string as argument and parses and evaluates it as a {\Python} +expression. +The expression is executed using the current local and global symbol +tables. +Syntax errors are reported as exceptions. +For example: +\bcode\begin{verbatim} +>>> x = 1 +>>> eval('x+1') +2 +>>> +\end{verbatim}\ecode +\funcitem{exec}{s} +Takes a string as argument and parses and evaluates it as a sequence of +{\Python} statements. +The string should end with a newline (\verb"'\n'"). +The statement is executed using the current local and global symbol +tables. +Syntax errors are reported as exceptions. +For example: +\bcode\begin{verbatim} +>>> x = 1 +>>> exec('x = x+1\n') +>>> x +2 +>>> +\end{verbatim}\ecode +\funcitem{float}{x} +Converts a number to floating point. +The argument may be an integer or floating point number. +\funcitem{input}{s} +Equivalent to +{\tt eval(raw\_input(s))}. +As for +{\tt raw\_input()}, +the argument is optional. +\funcitem{int}{x} +Converts a number to integer. +The argument may be an integer or floating point number. +\funcitem{len}{s} +Returns the length (the number of items) of an object. +The argument may be a sequence (string, tuple or list) or a mapping +(dictionary). +\funcitem{max}{s} +Returns the largest item of a non-empty sequence (string, tuple or list). +\funcitem{min}{s} +Returns the smallest item of a non-empty sequence (string, tuple or list). +\funcitem{open}{name, mode} +%.br +Returns a file object (described earlier under Built-in Types). +The string arguments are the same as for stdio's +{\tt fopen()}: +{\tt 'r'} +opens the file for reading, +{\tt 'w'} +opens it for writing (truncating an existing file), +{\tt 'a'} +opens it for appending.% +\footnote{ +This function should go into a built-in module +{\tt io}. +} +\funcitem{ord}{c} +Takes a string of one character and returns its +ASCII value, e.g., {\tt ord('a')} returns the integer {\tt 97}. +This is the inverse of {\tt chr()}. +\funcitem{range}{} +This is a versatile function to create lists containing arithmetic +progressions of integers. +With two integer arguments, it returns the ascending sequence of +integers starting at the first and ending one before the second +argument. +A single argument is used as the end point of the sequence, with 0 used +as the starting point. +A third argument specifies the step size; negative steps are allowed and +work as expected, but don't specify a zero step. +The resulting list may be empty. +For example: +\bcode\begin{verbatim} +>>> range(10) +[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +>>> range(1, 1+10) +[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +>>> range(0, 30, 5) +[0, 5, 10, 15, 20, 25] +>>> range(0, 10, 3) +[0, 3, 6, 9] +>>> range(0, -10, -1) +[0, -1, -2, -3, -4, -5, -6, -7, -8, -9] +>>> range(0) +[] +>>> range(1, 0) +[] +>>> +\end{verbatim}\ecode +\funcitem{raw\_input}{s} +%.br +The argument is optional; if present, it is written to standard output +without a trailing newline. +The function then reads a line from input, converts it to a string +(stripping a trailing newline), and returns that. +EOF is reported as an exception. +For example: +\bcode\begin{verbatim} +>>> raw_input('Type anything: ') +Type anything: Mutant Teenage Ninja Turtles +'Mutant Teenage Ninja Turtles' +>>> +\end{verbatim}\ecode +\funcitem{reload}{module} +Causes an already imported module to be re-parsed and re-initialized. +This is useful if you have edited the module source file and want to +try out the new version without leaving {\Python}. +\funcitem{type}{x} +Returns the type of an object. +Types are objects themselves: +the type of a type object is its own type. +\end{description} diff --git a/doc/mod2.tex b/doc/mod2.tex new file mode 100644 index 0000000..46f6d62 --- /dev/null +++ b/doc/mod2.tex @@ -0,0 +1,1083 @@ +\section{Built-in Modules} + +The modules described in this section are built into the interpreter. +They must be imported using +{\tt import}. +Some modules are not always available; it is a configuration option to +provide them. +Details are listed with the descriptions, but the best way to see if +a module exists in a particular implementation is to attempt to import +it. + +\subsection{Built-in Module {\tt sys}} + +This module provides access to some variables used or maintained by the +interpreter and to functions that interact strongly with the interpreter. +It is always available. +\begin{description} +\funcitem{argv} +The list of command line arguments passed to a {\Python} script. +{\tt sys.argv[0]} +is the script name. +If no script name was passed to the {\Python} interpreter, +{\tt sys.argv} +is empty. +\funcitem{exit}{n} +Exits from {\Python} with numeric exit status +{\tt n}. +This closes all open files and performs other cleanup-actions required by +the interpreter (but +{\em finally clauses} +of +{\tt try} +statements are not executed!). +\funcitem{modules} +Gives the list of modules that have already been loaded. +This can be manipulated to force reloading of modules and other tricks. +\funcitem{path} +A list of strings that specifies the search path for modules. +Initialized from the environment variable {\tt PYTHONPATH}, or an +installation-dependent default. +\funcitem{ps1,~ps2} +Strings specifying the primary and secondary prompt of the interpreter. +These are only defined if the interpreter is in interactive mode. +Their initial values in this case are +{\tt '>>> '} +and +{\tt '... '}. +\funcitem{stdin, stdout, stderr} +%.br +File objects corresponding to the interpreter's standard input, output +and error streams. +{\tt sys.stdin} +is used for all interpreter input except for scripts but including calls +to +{\tt input()} +and +{\tt raw\_input()}. +{\tt sys.stdout} +is used for the output of +{\tt print} and expression statements +and for the prompts of +{\tt input()} +and +{\tt raw\_input()}. +The interpreter's own prompts and its error messages are written to +stderr. +Assigning to +{\tt sys.stderr} +has no effect on the interpreter; it can be used to write error messages +to stderr using +{\tt print}. +\end{description} + +\subsection{Built-in Module {\tt math}} + +This module is always available. +It provides access to the mathematical functions defined by the C +standard. +They are: +{\tt acos(x)}, +{\tt asin(x)}, +{\tt atan(x)}, +{\tt atan2(x,y)}, +{\tt ceil(x)}, +{\tt cos(x)}, +{\tt cosh(x)}, +{\tt exp(x)}, +{\tt fabs(x)}, +{\tt floor(x)}, +%{\tt fmod(...)} XXX not yet +%{\tt frexp(...)} XXX not yet +%{\tt ldexp(...)} XXX not yet +{\tt log(x)}, +{\tt log10(x)}, +%{\tt modf(...)} XXX not yet +{\tt pow(x,y)}, +{\tt sin(x)}, +{\tt sinh(x)}, +{\tt sqrt(x)}, +{\tt tan(x)}, +{\tt tanh(x)}. + +It also defines two mathematical constants: +{\tt pi} +and +{\tt e}. + +\subsection{Built-in Module {\tt time}} + +This module provides various time-related functions. +It is always available. +Functions are: +\begin{description} +\funcitem{sleep}{secs} +Suspends execution for the given number of seconds. +\funcitem{time}{} +Returns the time in seconds since the Epoch (Thursday January 1, +00:00:00, 1970 UCT on \UNIX\ machines). +\end{description} + +\noindent +In some versions (Amoeba, Mac) the following functions also exist: +\begin{description} +\funcitem{millisleep}{msecs} +Suspends execution for the given number of milliseconds. +\funcitem{millitimer}{} +Returns the number of milliseconds of real time elapsed since some point +in the past that is fixed per execution of the python interpreter (but +may change in each following run). +\end{description} + +\noindent +The granularity of the milliseconds functions may be more than a +millisecond (100 msecs on Amoeba, 1/60 sec on the Mac). + +\subsection{Built-in Module {\tt regexp}} + +This module provides a regular expression matching operation. +It is always available. + +The module defines a function and an exception: + +\begin{description} + +\funcitem{compile}{pattern} + +Compile a regular expression given as a string into a regular +expression object. +The string must be an egrep-style regular expression; +this means that the characters +{\tt '(' ')' '*' '+' '?'\ '|' }\verb='^' '$'= +are special. +(It is implemented using Henry Spencer's regular expression matching +functions.) + +excitem{error}{regexp.error} + +Exception raised when a string passed to {\tt compile()} is not a +valid regular expression (e.g., unmatched parentheses) or when some other +error occurs during compilation or matching +(``no match found'' is not an error). + +\end{description} + +Compiled regular expression objects support a single method: + +\begin{description} + +\funcitem{exec}{str} + +Find the first occurrence of the compiled regular expression in the +string {\tt str}. +The return value is a tuple of pairs specifying where a match was +found and where matches were found for subpatterns specified with +{\tt '('} and {\tt ')'} in the pattern. +If no match is found, an empty tuple is returned; otherwise the first +item of the tuple is a pair of slice indices into the search string +giving the match found. +If there were any subpatterns in the pattern, the returned tuple has an +additional item for each subpattern, giving the slice indices into the +search string where that subpattern was found. + +\end{description} + +For example: +\bcode\begin{verbatim} +>>> import regexp +>>> r = regexp.compile('--(.*)--') +>>> s = 'a--b--c' +>>> r.exec(s) +((1, 6), (3, 4)) +>>> s[1:6] # The entire match +'--b--' +>>> s[3:4] # The subpattern +'b' +>>> +\end{verbatim}\ecode + +\subsection{Built-in Module {\tt posix}} + +This module provides access to operating system functionality that is +standardized by the C Standard and the POSIX standard (a thinly diguised +{\UNIX} interface). +It is available in all {\Python} versions except on the Macintosh. +Errors are reported exceptions. +It defines the following items: +\begin{description} +\funcitem{chdir}{path} +Changes the current directory to +{\tt path}. +\funcitem{chmod}{path, mode} +Change the mode of +{\tt path} +to the numeric +{\tt mode}. +\funcitem{environ} +A dictionary representing the string environment at the time +the interpreter was started. +(Modifying this dictionary does not affect the string environment of the +interpreter.) +For example, +{\tt posix.environ['HOME']} +is the pathname of your home directory, equivalent to +{\tt getenv("HOME")} +in C. +\excitem{error}{posix.error} +%.br +The exception raised when an POSIX function returns an error. +The value accompanying this exception is a pair containing the numeric +error code from +{\tt errno} +and the corresponding string, as would be printed by the C function +{\tt perror()}. +\funcitem{getcwd}{} +Returns a string representing the current working directory. +\funcitem{link}{src, dst} +Creates a hard link pointing to +{\tt src} +named +{\tt dst}. +\funcitem{listdir}{path} +Returns a list containing the names of the entries in the +directory. +The list is in arbitrary order. +It includes the special entries +{\tt '.'} +and +{\tt '..'} +if they are present in the directory. +\funcitem{mkdir}{path, mode} +Creates a directory named +{\tt path} +with numeric mode +{\tt mode}. +\funcitem{rename}{src, dst} +Renames the file or directory +{\tt src} +to +{\tt dst}. +\funcitem{rmdir}{path} +Removes the directory +{\tt path}. +\funcitem{stat}{path} +Performs a +{\em stat} +system call on the given path. +The return value is a tuple of at least 10 integers giving the most +important (and portable) members of the +{\em stat} +structure, in the order +{\tt st\_mode}, +{\tt st\_ino}, +{\tt st\_dev}, +{\tt st\_nlink}, +{\tt st\_uid}, +{\tt st\_gid}, +{\tt st\_size}, +{\tt st\_atime}, +{\tt st\_mtime}, +{\tt st\_ctime}. +More items may be added at the end by some implementations. +\funcitem{system}{command} +Executes the command (a string) in a subshell. +This is implemented by calling the Standard C function +{\tt system()}, +and has the same limitations. +Changes to +{\tt posix.environ}, +{\tt sys.stdin} +etc. are not reflected in the environment of the executed command. +The return value is the exit status of the process as returned by +Standard C +{\tt system()}. +\funcitem{umask}{mask} +Sets the current numeric umask and returns the previous umask. +\funcitem{unlink}{path} +Unlinks the file +{\tt path}. +\funcitem{utimes(path, }{atime, mtime)} +%.br +Sets the access and modified time of the file to the given values. +(The second argument is a tuple of two items.) +\end{description} + +The following functions are only available on systems that support +symbolic links: +\begin{description} +\funcitem{lstat}{path} +Like +{\tt stat()}, +but does not follow symbolic links. +\funcitem{readlink}{path} +Returns a string representing the path to which the symbolic link +points. +\funcitem{symlink}{src, dst} +Creates a symbolic link pointing to +{\tt src} +named +{\tt dst}. +\end{description} + +\subsection{Built-in Module {\tt stdwin}} + +This module defines several new object types and functions that +provide access to the functionality of the Standard Window System +Interface, STDWIN [CWI report CR-R8817]. +It is available on systems to which STDWIN has been ported (which is +most systems). +It is only available if the {\tt DISPLAY} environment variable is set +or an explicit `{\tt -display \it displayname}' argument is passed to +the interpreter. + +Functions have names that usually resemble their C STDWIN counterparts +with the initial `w' dropped. +Points are represented by pairs of integers; rectangles +by pairs of points. +For a complete description of STDWIN please refer to the documentation +of STDWIN for C programmers (aforementioned CWI report). +\subsubsection{Functions Defined in Module {\tt stdwin}} + +The following functions are defined in the {\tt stdwin} module: +\begin{description} +\funcitem{open}{title} +%.br +Opens a new window whose initial title is given by the string argument. +Returns a window object; window object methods are described below.% +\footnote{ +The {\Python} version of STDWIN does not support draw procedures; all +drawing requests are reported as draw events. +} +\funcitem{getevent}{} +%.br +Waits for and returns the next event. +An event is returned as a triple: the first element is the event +type, a small integer; the second element is the window object to which +the event applies, or +{\tt None} +if it applies to no window in particular; +the third element is type-dependent. +Names for event types and command codes are defined in the standard +module +{\tt stdwinevent}. +\funcitem{setdefwinpos}{h, v} +%.br +Sets the default window position. +\funcitem{setdefwinsize}{width, height} +%.br +Sets the default window size. +\funcitem{menucreate}{title} +%.br +Creates a menu object referring to a global menu (a menu that appears in +all windows). +Methods of menu objects are described below. +\funcitem{fleep}{} +%.br +Causes a beep or bell (or perhaps a `visual bell' or flash, hence the +name). +\funcitem{message}{string} +%.br +Displays a dialog box containing the string. +The user must click OK before the function returns. +\funcitem{askync}{prompt, default} +%.br +Displays a dialog that prompts the user to answer a question with yes or +no. +The function returns 0 for no, 1 for yes. +If the user hits the Return key, the default (which must be 0 or 1) is +returned. +If the user cancels the dialog, the +{\tt KeyboardInterrupt} +exception is raised. +\funcitem{askstr}{prompt, default} +%.br +Displays a dialog that prompts the user for a string. +If the user hits the Return key, the default string is returned. +If the user cancels the dialog, the +{\tt KeyboardInterrupt} +exception is raised. +\funcitem{askfile}{prompt, default, new} +%.br +Asks the user to specify a filename. +If +{\tt new} +is zero it must be an existing file; otherwise, it must be a new file. +If the user cancels the dialog, the +{\tt KeyboardInterrupt} +exception is raised. +\funcitem{setcutbuffer}{i, string} +%.br +Stores the string in the system's cut buffer number +{\tt i}, +where it can be found (for pasting) by other applications. +On X11, there are 8 cut buffers (numbered 0..7). +Cut buffer number 0 is the `clipboard' on the Macintosh. +\funcitem{getcutbuffer}{i} +%.br +Returns the contents of the system's cut buffer number +{\tt i}. +\funcitem{rotatebutbuffers}{n} +%.br +On X11, this rotates the 8 cut buffers by +{\tt n}. +Ignored on the Macintosh. +\funcitem{getselection}{i} +%.br +Returns X11 selection number +{\tt i.} +Selections are not cut buffers. +Selection numbers are defined in module +{\tt stdwinevents}. +Selection {\tt WS\_PRIMARY} is the +{\em primary} +selection (used by +xterm, +for instance); +selection {\tt WS\_SECONDARY} is the +{\em secondary} +selection; selection {\tt WS\_CLIPBOARD} is the +{\em clipboard} +selection (used by +xclipboard). +On the Macintosh, this always returns an empty string. +\funcitem{resetselection}{i} +%.br +Resets selection number +{\tt i}, +if this process owns it. +(See window method +{\tt setselection()}). +\funcitem{baseline}{} +%.br +Return the baseline of the current font (defined by STDWIN as the +vertical distance between the baseline and the top of the +characters).% +\footnote{ +There is no way yet to set the current font. +This will change in a future version. +} +\funcitem{lineheight}{} +%.br +Return the total line height of the current font. +\funcitem{textbreak}{str, width} +%.br +Return the number of characters of the string that fit into a space of +{\tt width} +bits wide when drawn in the curent font. +\funcitem{textwidth}{str} +%.br +Return the width in bits of the string when drawn in the current font. +\end{description} + +\subsubsection{Window Object Methods} + +Window objects are created by +{\tt stdwin.open()}. +There is no explicit function to close a window; windows are closed when +they are garbage-collected. +Window objects have the following methods: +\begin{description} +\funcitem{begindrawing}{} +Returns a drawing object, whose methods (described below) allow drawing +in the window. +\funcitem{change}{rect} +Invalidates the given rectangle; this may cause a draw event. +\funcitem{gettitle}{} +Returns the window's title string. +\funcitem{getdocsize}{} +\begin{sloppypar} +Returns a pair of integers giving the size of the document as set by +{\tt setdocsize()}. +\end{sloppypar} +\funcitem{getorigin}{} +Returns a pair of integers giving the origin of the window with respect +to the document. +\funcitem{getwinsize}{} +Returns a pair of integers giving the size of the window. +\funcitem{menucreate}{title} +Creates a menu object referring to a local menu (a menu that appears +only in this window). +Methods menu objects are described below. +\funcitem{scroll}{rect,~point} +Scrolls the given rectangle by the vector given by the point. +\funcitem{setwincursor}{name} +\begin{sloppypar} +Sets the window cursor to a cursor of the given name. +It raises the +{\tt Runtime\-Error} +exception if no cursor of the given name exists. +Suitable names are +{\tt 'ibeam'}, +{\tt 'arrow'}, +{\tt 'cross'}, +{\tt 'watch'} +and +{\tt 'plus'}. +On X11, there are many more (see +{\tt <X11/cursorfont.h>}). +\end{sloppypar} +\funcitem{setdocsize}{point} +Sets the size of the drawing document. +\funcitem{setorigin}{point} +Moves the origin of the window to the given point in the document. +\funcitem{setselection}{i, str} +Attempts to set X11 selection number +{\tt i} +to the string +{\tt str}. +(See stdwin method +{\tt getselection()} +for the meaning of +{\tt i}.) +Returns true if it succeeds. +If it succeeds, the window ``owns'' the selection until +(a) another applications takes ownership of the selection; or +(b) the window is deleted; or +(c) the application clears ownership by calling +{\tt stdwin.resetselection(i)}. +When another application takes ownership of the selection, a +{\tt WE\_LOST\_SEL} +event is received for no particular window and with the selection number +as detail. +Ignored on the Macintosh. +\funcitem{settitle}{title} +Sets the window's title string. +\funcitem{settimer}{dsecs} +Schedules a timer event for the window in +{\tt dsecs/10} +seconds. +\funcitem{show}{rect} +Tries to ensure that the given rectangle of the document is visible in +the window. +\funcitem{textcreate}{rect} +Creates a text-edit object in the document at the given rectangle. +Methods of text-edit objects are described below. +\end{description} + +\subsubsection{Drawing Object Methods} + +Drawing objects are created exclusively by the window method +{\tt begindrawing()}. +Only one drawing object can exist at any given time; the drawing object +must be deleted to finish drawing. +No drawing object may exist when +{\tt stdwin.getevent()} +is called. +Drawing objects have the following methods: +\begin{description} +\funcitem{box}{rect} +Draws a box around a rectangle. +\funcitem{circle}{center, radius} +%.br +Draws a circle with given center point and radius. +\funcitem{elarc(center, (rh, rv), }{a1, a2)} +%.br +Draws an elliptical arc with given center point. +{\tt (rh, rv)} +gives the half sizes of the horizontal and vertical radii. +{\tt (a1, a2)} +gives the angles (in degrees) of the begin and end points. +0 degrees is at 3 o'clock, 90 degrees is at 12 o'clock. +\funcitem{erase}{rect} +Erases a rectangle. +\funcitem{invert}{rect} +Inverts a rectangle. +\funcitem{line}{p1, p2} +Draws a line from point +{\tt p1} +to +{\tt p2}. +\funcitem{paint}{rect} +Fills a rectangle. +\funcitem{text}{p, str} +Draws a string starting at point p (the point specifies the +top left coordinate of the string). +\funcitem{shade}{rect, percent} +%.br +Fills a rectangle with a shading pattern that is about +{\tt percent} +percent filled. +\funcitem{xorline}{p1, p2} +Draws a line in XOR mode. +\funcitem{baseline(), lineheight(), textbreak(), textwidth}{} +%.br +These functions are similar to the corresponding functions described +above for the +{\tt stdwin} +module, but use the current font of the window instead of the (global) +default font. +\end{description} + +\subsubsection{Menu Object Methods} + +A menu object represents a menu. +The menu is destroyed when the menu object is deleted. +The following methods are defined: +\begin{description} +\funcitem{additem}{text, shortcut} +%.br +Adds a menu item with given text. +The shortcut must be a string of length 1, or omitted (to specify no +shortcut). +\funcitem{setitem}{i, text} +Sets the text of item number +{\tt i}. +\funcitem{enable}{i, flag} +Enables or disables item +{\tt i}. +\funcitem{check}{i, flag} +Sets or clears the +{\em check mark} +for item +{\tt i}. +\end{description} + +\subsubsection{Text-edit Object Methods} + +A text-edit object represents a text-edit block. +For semantics, see the STDWIN documentation for C programmers. +The following methods exist: +\begin{description} +\funcitem{arrow}{code} +Passes an arrow event to the text-edit block. +The +{\tt code} +must be one of +{\tt WC\_LEFT}, +{\tt WC\_RIGHT}, +{\tt WC\_UP} +or +{\tt WC\_DOWN} +(see module +{\tt stdwinevents}). +\funcitem{draw}{rect} +Passes a draw event to the text-edit block. +The rectangle specifies the redraw area. +\funcitem{event}{type, window, detail} +%.br +Passes an event gotten from +{\tt stdwin.getevent()} +to the text-edit block. +Returns true if the event was handled. +\funcitem{getfocus}{} +Returns 2 integers representing the start and end positions of the +focus, usable as slice indices on the string returned by +{\tt getfocustext()}. +\funcitem{getfocustext}{} +Returns the text in the focus. +\funcitem{getrect}{} +Returns a rectangle giving the actual position of the text-edit block. +(The bottom coordinate may differ from the initial position because +the block automatically shrinks or grows to fit.) +\funcitem{gettext}{} +Returns the entire text buffer. +\funcitem{move}{rect} +Specifies a new position for the text-edit block in the document. +\funcitem{replace}{str} +Replaces the focus by the given string. +The new focus is an insert point at the end of the string. +\funcitem{setfocus}{i,~j} +Specifies the new focus. +Out-of-bounds values are silently clipped. +\end{description} + +\subsubsection{Example} + +Here is a simple example of using STDWIN in Python. +It creates a window and draws the string ``Hello world'' in the top +left corner of the window. +The window will be correctly redrawn when covered and re-exposed. +The program quits when the close icon or menu item is requested. +\bcode\begin{verbatim} +import stdwin +from stdwinevents import * + +def main(): + mywin = stdwin.open('Hello') + # + while 1: + (type, win, detail) = stdwin.getevent() + if type = WE_DRAW: + draw = win.begindrawing() + draw.text((0, 0), 'Hello, world') + del draw + elif type = WE_CLOSE: + break + +main() +\end{verbatim}\ecode + +\subsection{Built-in Module {\tt amoeba}} + +This module provides some object types and operations useful for +Amoeba applications. +It is only available on systems that support Amoeba operations. +RPC errors and other Amoeba errors are reported as the exception +{\tt amoeba.error = 'amoeba.error'}. +The module +{\tt amoeba} +defines the following items: +\begin{description} +\funcitem{name\_append}{path,~cap} +%.br +Stores a capability in the Amoeba directory tree. +Arguments are the pathname (a string) and the capability (a capability +object as returned by +{\tt name\_lookup()}). +\funcitem{name\_delete}{path} +%.br +Deletes a capability from the Amoeba directory tree. +Argument is the pathname. +\funcitem{name\_lookup}{path} +%.br +Looks up a capability. +Argument is the pathname. +Returns a +{\em capability} +object, to which various interesting operations apply, described below. +\funcitem{name\_replace}{path,~cap} +%.br +Replaces a capability in the Amoeba directory tree. +Arguments are the pathname and the new capability. +(This differs from +{\tt name\_append()} +in the behavior when the pathname already exists: +{\tt name\_append()} +finds this an error while +{\tt name\_replace()} +allows it, as its name suggests.) +\funcitem{capv} +A table representing the capability environment at the time the +interpreter was started. +(Alas, modifying this table does not affect the capability environment +of the interpreter.) +For example, +{\tt amoeba.capv['ROOT']} +is the capability of your root directory, similar to +{\tt getcap("ROOT")} +in C. +\excitem{error}{amoeba.error} +%.br +The exception raised when an Amoeba function returns an error. +The value accompanying this exception is a pair containing the numeric +error code and the corresponding string, as returned by the C function +{\tt err\_why()}. +\funcitem{timeout}{msecs} +%.br +Sets the transaction timeout, in milliseconds. +Returns the previous timeout. +Initially, the timeout is set to 2 seconds by the {\Python} interpreter. +\end{description} + +\subsubsection{Capability Operations} + +Capabilities are written in a convenient ASCII format, also used by the +Amoeba utilities +{\em c2a}(U) +and +{\em a2c}(U). +For example: +\bcode\begin{verbatim} +>>> amoeba.name_lookup('/profile/cap') +aa:1c:95:52:6a:fa/14(ff)/8e:ba:5b:8:11:1a +>>> +\end{verbatim}\ecode +The following methods are defined for capability objects. +\begin{description} +\funcitem{dir\_list}{} +Returns a list of the names of the entries in an Amoeba directory. +\funcitem{b\_read}{offset, maxsize} +%.br +Reads (at most) +{\tt maxsize} +bytes from a bullet file at offset +{\tt offset.} +The data is returned as a string. +EOF is reported as an empty string. +\funcitem{b\_size}{} +Returns the size of a bullet file. +\funcitem{dir\_append(), dir\_delete(), dir\_lookup(), dir\_replace}{} +%.br +\itembreak +Like the corresponding +{\tt name\_*} +functions, but with a path relative to the capability. +(For paths beginning with a slash the capability is ignored, since this +is the defined semantics for Amoeba.) +\funcitem{std\_info}{} +Returns the standard info string of the object. +\funcitem{tod\_gettime}{} +Returns the time (in seconds since the Epoch, in UCT, as for POSIX) from +a time server. +\funcitem{tod\_settime}{t} +Sets the time kept by a time server. +\end{description} + +\subsection{Built-in Module {\tt audio}} + +This module provides rudimentary access to the audio I/O device +{\tt /dev/audio} +on the Silicon Graphics Personal IRIS; see audio(7). +It supports the following operations: +\begin{description} +\funcitem{setoutgain}{n} +Sets the output gain (0-255). +\funcitem{getoutgain}{} +Returns the output gain. +\funcitem{setrate}{n} +Sets the sampling rate: 1=32K/sec, 2=16K/sec, 3=8K/sec. +\funcitem{setduration}{n} +Sets the `sound duration' in units of 1/100 seconds. +\funcitem{read}{n} +Reads a chunk of +{\tt n} +sampled bytes from the audio input (line in or microphone). +The chunk is returned as a string of length n. +Each byte encodes one sample as a signed 8-bit quantity using linear +encoding. +This string can be converted to numbers using {\tt chr2num()} described +below. +\funcitem{write}{buf} +Writes a chunk of samples to the audio output (speaker). +\end{description} + +These operations support asynchronous audio I/O: +\begin{description} +\funcitem{start\_recording}{n} +%.br +Starts a second thread (a process with shared memory) that begins reading +{\tt n} +bytes from the audio device. +The main thread immediately continues. +\funcitem{wait\_recording}{} +%.br +Waits for the second thread to finish and returns the data read. +\funcitem{stop\_recording}{} +%.br +Makes the second thread stop reading as soon as possible. +Returns the data read so far. +\funcitem{poll\_recording}{} +%.br +Returns true if the second thread has finished reading (so +{\tt wait\_recording()} would return the data without delay). +\item[{\tt start\_playing(chunk)}, {\tt wait\_playing()}, +{\tt stop\_playing()}, {\tt poll\_playing()}] +%.br +\begin{sloppypar} +Similar but for output. +{\tt stop\_playing()} +returns a lower bound for the number of bytes actually played (not very +accurate). +\end{sloppypar} +\end{description} + +The following operations do not affect the audio device but are +implemented in C for efficiency: +\begin{description} +\funcitem{amplify}{buf, f1, f2} +%.br +Amplifies a chunk of samples by a variable factor changing from +{\tt f1}/256 to {\tt f2}/256. +Negative factors are allowed. +Resulting values that are to large to fit in a byte are clipped. +\funcitem{reverse}{buf} +%.br +Returns a chunk of samples backwards. +\funcitem{add}{buf1, buf2} +%.br +Bytewise adds two chunks of samples. +Bytes that exceed the range are clipped. +If one buffer shorter, it is assumed to be padded with zeros. +\funcitem{chr2num}{buf} +%.br +Converts a string of sampled bytes as returned by {\tt read()} into +a list containing the numeric values of the samples. +\funcitem{num2chr}{list} +%.br +\begin{sloppypar} +Converts a list as returned by +{\tt chr2num()} +back to a buffer acceptable by +{\tt write()}. +\end{sloppypar} +\end{description} + +\subsection{Built-in Module {\tt gl}} + +This module provides access to the Silicon Graphics +{\em Graphics Library}. +It is available only on Silicon Graphics machines. + +{\bf Warning:} +Some illegal calls to the GL library cause the {\Python} interpreter to dump +core. +In particular, the use of most GL calls is unsafe before the first +window is opened. + +The module is too large to document here in its entirety, but the +following should help you to get started. +The parameter conventions for the C functions are translated to {\Python} as +follows: + +\begin{itemize} +\item +All (short, long, unsigned) int values are represented by {\Python} +integers. +\item +All float and double values are represented by {\Python} floating point +numbers. +In most cases, {\Python} integers are also allowed. +\item +All arrays are represented by one-dimensional {\Python} lists. +In most cases, tuples are also allowed. +\item +\begin{sloppypar} +All string and character arguments are represented by {\Python} strings, +for instance, +{\tt winopen('Hi~There!')} +and +{\tt rotate(900,~'z')}. +\end{sloppypar} +\item +All (short, long, unsigned) integer arguments or return values that are +only used to specify the length of an array argument are omitted. +For example, the C call +\bcode\begin{verbatim} +lmdef(deftype, index, np, props) +\end{verbatim}\ecode +is translated to {\Python} as +\bcode\begin{verbatim} +lmdef(deftype, index, props) +\end{verbatim}\ecode +\item +Output arguments are omitted from the argument list; they are +transmitted as function return values instead. +If more than one value must be returned, the return value is a tuple. +If the C function has both a regular return value (that is not omitted +because of the previous rule) and an output argument, the return value +comes first in the tuple. +Examples: the C call +\bcode\begin{verbatim} +getmcolor(i, &red, &green, &blue) +\end{verbatim}\ecode +is translated to {\Python} as +\bcode\begin{verbatim} +red, green, blue = getmcolor(i) +\end{verbatim}\ecode +\end{itemize} + +The following functions are non-standard or have special argument +conventions: +\begin{description} +\funcitem{varray}{} +Equivalent to but faster than a number of +{\tt v3d()} +calls. +The argument is a list (or tuple) of points. +Each point must be a tuple of coordinates (x, y, z) or (x, y). +The points may be 2- or 3-dimensional but must all have the +same dimension. +Float and int values may be mixed however. +The points are always converted to 3D double precision points +by assuming z=0.0 if necessary (as indicated in the man page), +and for each point +{\tt v3d()} +is called. +\funcitem{nvarray}{} +Equivalent to but faster than a number of +{\tt n3f} +and +{\tt v3f} +calls. +The argument is an array (list or tuple) of pairs of normals and points. +Each pair is a tuple of a point and a normal for that point. +Each point or normal must be a tuple of coordinates (x, y, z). +Three coordinates must be given. +Float and int values may be mixed. +For each pair, +{\tt n3f()} +is called for the normal, and then +{\tt v3f()} +is called for the point. +\funcitem{vnarray}{} +Similar to +{\tt nvarray()} +but the pairs have the point first and the normal second. +\funcitem{nurbssurface}{s\_k[], t\_k[], ctl[][], s\_ord, t\_ord, type} +%.br +\itembreak +Defines a nurbs surface. +The dimensions of +{\tt ctl[][]} +are computed as follows: +{\tt [len(s\_k)~-~s\_ord]}, +{\tt [len(t\_k)~-~t\_ord]}. +\funcitem{nurbscurve}{knots, ctlpoints, order, type} +%.br +Defines a nurbs curve. +The length of ctlpoints is +{\tt len(knots)~-~order}. +\funcitem{pwlcurve}{points, type} +%.br +Defines a piecewise-linear curve. +{\tt points} +is a list of points. +{\tt type} +must be +{\tt N\_ST}. +\funcitem{pick(n), select}{n} +%.br +The only argument to these functions specifies the desired size of the +pick or select buffer. +\funcitem{endpick(), endselect}{} +%.br +These functions have no arguments. +They return a list of integers representing the used part of the +pick/select buffer. +No method is provided to detect buffer overrun. +\end{description} + +Here is a tiny but complete example GL program in {\Python}: +\bcode\begin{verbatim} +import gl, GL, time + +def main(): + gl.foreground() + gl.prefposition(500, 900, 500, 900) + w = gl.winopen('CrissCross') + gl.ortho2(0.0, 400.0, 0.0, 400.0) + gl.color(GL.WHITE) + gl.clear() + gl.color(GL.RED) + gl.bgnline() + gl.v2f(0.0, 0.0) + gl.v2f(400.0, 400.0) + gl.endline() + gl.bgnline() + gl.v2f(400.0, 0.0) + gl.v2f(0.0, 400.0) + gl.endline() + time.sleep(5) + +main() +\end{verbatim}\ecode + +\subsection{Built-in Module {\tt pnl}} + +This module provides access to the +{\em Panel Library} +built by NASA Ames (to get it, send e-mail to +{\tt [email protected]}). +All access to it should be done through the standard module +{\tt panel}, +which transparantly exports most functions from +{\tt pnl} +but redefines +{\tt pnl.dopanel()}. + +{\bf Warning:} +the {\Python} interpreter will dump core if you don't create a GL window +before calling +{\tt pnl.mkpanel()}. + +The module is too large to document here in its entirety. diff --git a/doc/mod3.tex b/doc/mod3.tex new file mode 100644 index 0000000..d1a99b1 --- /dev/null +++ b/doc/mod3.tex @@ -0,0 +1,484 @@ +\section{Standard Modules} + +The following standard modules are defined. +They are available in one of the directories in the default module +search path (try printing +{\tt sys.path} +to find out the default search path.) + +\subsection{Standard Module {\tt string}} + +This module defines some constants useful for checking character +classes, some exceptions, and some useful string functions. +The constants are: +\begin{description} +\funcitem{digits} +The string +{\tt '0123456789'}. +\funcitem{hexdigits} +The string +{\tt '0123456789abcdefABCDEF'}. +\funcitem{letters} +The concatenation of the strings +{\tt lowercase} +and +{\tt uppercase} +described below. +\funcitem{lowercase} +The string +{\tt 'abcdefghijklmnopqrstuvwxyz'}. +\funcitem{octdigits} +The string +{\tt '01234567'}. +\funcitem{uppercase} +The string +{\tt 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'}. +\funcitem{whitespace} +A string containing all characters that are considered whitespace, +i.e., +space, tab and newline. +This definition is used by +{\tt split()} +and +{\tt strip()}. +\end{description} + +The exceptions are: +\begin{description} +\excitem{atoi\_error}{non-numeric argument to string.atoi} +%.br +Exception raised by +{\tt atoi} +when a non-numeric string argument is detected. +The exception argument is the offending string. +\excitem{index\_error}{substring not found in string.index} +%.br +Exception raised by +{\tt index} +when +{\tt sub} +is not found. +The argument are the offending arguments to index: {\tt (s, sub)}. +\end{description} + +The functions are: +\begin{description} +\funcitem{atoi}{s} +Converts a string to a number. +The string must consist of one or more digits, optionally preceded by a +sign ({\tt '+'} or {\tt '-'}). +\funcitem{index}{s, sub} +Returns the lowest index in +{\tt s} +where the substring +{\tt sub} +is found. +\funcitem{lower}{s} +Convert letters to lower case. +\funcitem{split}{s} +Returns a list of the whitespace-delimited words of the string +{\tt s}. +\funcitem{splitfields}{s, sep} +%.br +Returns a list containing the fields of the string +{\tt s}, +using the string +{\tt sep} +as a separator. +The list will have one more items than the number of non-overlapping +occurrences of the separator in the string. +Thus, +{\tt string.splitfields(s, ' ')} +is not the same as +{\tt string.split(s)}, +as the latter only returns non-empty words. +\funcitem{strip}{s} +Removes leading and trailing whitespace from the string +{\tt s}. +\funcitem{swapcase}{s} +Converts lower case letters to upper case and vice versa. +\funcitem{upper}{s} +Convert letters to upper case. +\funcitem{ljust(s, width), rjust(s, width), center}{s, width} +%.br +These functions respectively left-justify, right-justify and center a +string in a field of given width. +They return a string that is at least +{\tt width} +characters wide, created by padding the string +{\tt s} +with spaces until the given width on the right, left or both sides. +The string is never truncated. +\end{description} + +\subsection{Standard Module {\tt path}} + +This module implements some useful functions on POSIX pathnames. +\begin{description} +\funcitem{basename}{p} +Returns the base name of pathname +{\tt p}. +This is the second half of the pair returned by +{\tt path.split(p)}. +\funcitem{cat}{p, q} +Performs intelligent pathname concatenation on paths +{\tt p} +and +{\tt q}: +If +{\tt q} +is an absolute path, the return value is +{\tt q}. +Otherwise, the concatenation of +{\tt p} +and +{\tt q} +is returned, with a slash ({\tt '/'}) inserted unless +{\tt p} +is empty or ends in a slash. +\funcitem{commonprefix}{list} +%.br +Returns the longest string that is a prefix of all strings in +{\tt list}. +If +{\tt list} +is empty, the empty string ({\tt ''}) is returned. +\funcitem{exists}{p} +Returns true if +{\tt p} +refers to an existing path. +\funcitem{isdir}{p} +Returns true if +{\tt p} +refers to an existing directory. +\funcitem{islink}{p} +Returns true if +{\tt p} +refers to a directory entry that is a symbolic link. +Always false if symbolic links are not supported. +\funcitem{ismount}{p} +Returns true if +{\tt p} +is an absolute path that occurs in the mount table as output by the +{\tt /etc/mount} +utility. +This output is read once when the function is used for the first +time.% +\footnote{ +Is there a better way to check for mount points? +} +\funcitem{split}{p} +Returns a pair +{\tt (head,~tail)} +such that +{\tt tail} +contains no slashes and +{\tt path.cat(head, tail)} +is equal to +{\tt p}. +\funcitem{walk}{p, visit, arg} +%.br +Calls the function +{\tt visit} +with arguments +{\tt (arg, dirname, names)} +for each directory in the directory tree rooted at +{\tt p} +(including +{\tt p} +itself, if it is a directory). +The argument +{\tt dirname} +specifies the visited directory, the argument +{\tt names} +lists the files in the directory (gotten from +{\tt posix.listdir(dirname)}). +The +{\tt visit} +function may modify +{\tt names} +to influence the set of directories visited below +{\tt dirname}, +e.g., +to avoid visiting certain parts of the tree. +(The object referred to by +{\tt names} +must be modified in place, using +{\tt del} +or slice assignment.) +\end{description} + +\subsection{Standard Module {\tt getopt}} + +This module helps scripts to parse the command line arguments in +{\tt sys.argv}. +It uses the same conventions as the {\UNIX} +{\tt getopt()} +function. +It defines the function +{\tt getopt.getopt(args, options)} +and the exception +{\tt getopt.error}. + +The first argument to +{\tt getopt()} +is the argument list passed to the script with its first element +chopped off (i.e., +{\tt sys.argv[1:]}). +The second argument is the string of option letters that the +script wants to recognize, with options that require an argument +followed by a colon (i.e., the same format that {\UNIX} +{\tt getopt()} +uses). +The return value consists of two elements: the first is a list of +option-and-value pairs; the second is the list of program arguments +left after the option list was stripped (this is a trailing slice of the +first argument). +Each option-and-value pair returned has the option as its first element, +prefixed with a hyphen (e.g., +{\tt '-x'}), +and the option argument as its second element, or an empty string if the +option has no argument. +The options occur in the list in the same order in which they were +found, thus allowing multiple occurrences. +Example: +\bcode\begin{verbatim} +>>> import getopt, string +>>> args = string.split('-a -b -cfoo -d bar a1 a2') +>>> args +['-a', '-b', '-cfoo', '-d', 'bar', 'a1', 'a2'] +>>> optlist, args = getopt.getopt(args, 'abc:d:') +>>> optlist +[('-a', ''), ('-b', ''), ('-c', 'foo'), ('-d', 'bar')] +>>> args +['a1', 'a2'] +>>> +\end{verbatim}\ecode +The exception +{\tt getopt.error = 'getopt error'} +is raised when an unrecognized option is found in the argument list or +when an option requiring an argument is given none. +The argument to the exception is a string indicating the cause of the +error. + +\subsection{Standard Module {\tt rand}} + +This module implements a pseudo-random number generator similar to +{\tt rand()} +in C. +It defines the following functions: +\begin{description} +\funcitem{rand}{} +Returns an integer random number in the range [0 ... 32768). +\funcitem{choice}{s} +Returns a random element from the sequence (string, tuple or list) +{\tt s.} +\funcitem{srand}{seed} +Initializes the random number generator with the given integral seed. +When the module is first imported, the random number is initialized with +the current time. +\end{description} + +\subsection{Standard Module {\tt whrandom}} + +This module implements a Wichmann-Hill pseudo-random number generator. +It defines the following functions: +\begin{description} +\funcitem{random}{} +Returns the next random floating point number in the range [0.0 ... 1.0). +\funcitem{seed}{x, y, z} +Initializes the random number generator from the integers +{\tt x}, +{\tt y} +and +{\tt z}. +When the module is first imported, the random number is initialized +using values derived from the current time. +\end{description} + +\subsection{Standard Module {\tt stdwinevents}} + +This module defines constants used by STDWIN for event types +({\tt WE\_ACTIVATE} etc.), command codes ({\tt WC\_LEFT} etc.) +and selection types ({\tt WS\_PRIMARY} etc.). +Read the file for details. +Suggested usage is +\bcode\begin{verbatim} +>>> from stdwinevents import * +>>> +\end{verbatim}\ecode + +\subsection{Standard Module {\tt rect}} + +This module contains useful operations on rectangles. +A rectangle is defined as in module +{\tt stdwin}: +a pair of points, where a point is a pair of integers. +For example, the rectangle +\bcode\begin{verbatim} +(10, 20), (90, 80) +\end{verbatim}\ecode +is a rectangle whose left, top, right and bottom edges are 10, 20, 90 +and 80, respectively. +Note that the positive vertical axis points down (as in +{\tt stdwin}). + +The module defines the following objects: +\begin{description} +\excitem{error}{rect.error} +%.br +The exception raised by functions in this module when they detect an +error. +The exception argument is a string describing the problem in more +detail. +\funcitem{empty} +%.br +The rectangle returned when some operations return an empty result. +This makes it possible to quickly check whether a result is empty: +\bcode\begin{verbatim} +>>> import rect +>>> r1 = (10, 20), (90, 80) +>>> r2 = (0, 0), (10, 20) +>>> r3 = rect.intersect(r1, r2) +>>> if r3 is rect.empty: print 'Empty intersection' +Empty intersection +>>> +\end{verbatim}\ecode +\funcitem{is\_empty}{r} +%.br +Returns true if the given rectangle is empty. +A rectangle +{\em (left,~top), (right,~bottom)} +is empty if +{\em left~$\geq$~right} +or +{\em top~$\leq$~bottom}. +\funcitem{intersect}{list} +%.br +Returns the intersection of all rectangles in the list argument. +It may also be called with a tuple argument or with two or more +rectangles as arguments. +Raises +{\tt rect.error} +if the list is empty. +Returns +{\tt rect.empty} +if the intersection of the rectangles is empty. +\funcitem{union}{list} +%.br +Returns the smallest rectangle that contains all non-empty rectangles in +the list argument. +It may also be called with a tuple argument or with two or more +rectangles as arguments. +Returns +{\tt rect.empty} +if the list is empty or all its rectangles are empty. +\funcitem{pointinrect}{point, rect} +%.br +Returns true if the point is inside the rectangle. +By definition, a point +{\em (h,~v)} +is inside a rectangle +{\em (left,~top),} +{\em (right,~bottom)} +if +{\em left~$\leq$~h~$<$~right} +and +{\em top~$\leq$~v~$<$~bottom}. +\funcitem{inset(rect, }{dh, dv)} +%.br +Returns a rectangle that lies inside the +{\tt rect} +argument by +{\tt dh} +pixels horizontally +and +{\tt dv} +pixels +vertically. +If +{\tt dh} +or +{\tt dv} +is negative, the result lies outside +{\tt rect}. +\funcitem{rect2geom}{rect} +%.br +Converts a rectangle to geometry representation: +{\em (left,~top),} +{\em (width,~height)}. +\funcitem{geom2rect}{geom} +%.br +Converts a rectangle given in geometry representation back to the +standard rectangle representation +{\em (left,~top),} +{\em (right,~bottom)}. +\end{description} + +\subsection{Standard Modules {\tt GL} and {\tt DEVICE}} + +These modules define the constants used by the Silicon Graphics +{\em Graphics Library} +that C programmers find in the header files +{\tt <gl/gl.h>} +and +{\tt <gl/device.h>}. +Read the module files for details. + +\subsection{Standard Module {\tt panel}} + +This module should be used instead of the built-in module +{\tt pnl} +to interface with the +{\em Panel Library}. + +The module is too large to document here in its entirety. +One interesting function: +\begin{description} +\funcitem{defpanellist}{filename} +%.br +Parses a panel description file containing S-expressions written by the +{\em Panel Editor} +that accompanies the Panel Library and creates the described panels. +It returns a list of panel objects. +\end{description} + +{\bf Warning:} +the {\Python} interpreter will dump core if you don't create a GL window +before calling +{\tt panel.mkpanel()} +or +{\tt panel.defpanellist()}. + +\subsection{Standard Module {\tt panelparser}} + +This module defines a self-contained parser for S-expressions as output +by the Panel Editor (which is written in Scheme so it can't help writing +S-expressions). +The relevant function is +{\tt panelparser.parse\_file(file)} +which has a file object (not a filename!) as argument and returns a list +of parsed S-expressions. +Each S-expression is converted into a {\Python} list, with atoms converted +to {\Python} strings and sub-expressions (recursively) to {\Python} lists. +For more details, read the module file. + +\section{P.M.} + +\begin{verse} + +commands + +cmp? + +*cache? + +localtime? + +calendar? + +\_\_dict? + +mac? + +\end{verse} diff --git a/doc/myformat.sty b/doc/myformat.sty new file mode 100644 index 0000000..be70239 --- /dev/null +++ b/doc/myformat.sty @@ -0,0 +1,34 @@ +% Style parameters and macros used by all documents here + +% Page lay-out parameters +\textwidth = 160mm +\textheight = 240mm +\topmargin = -11mm +\oddsidemargin = 0mm +\evensidemargin = 0mm +%\parindent = 0mm + +% Frequently used system names +\newcommand{\Python}{Python} % Sometimes I want this italicized +\newcommand{\UNIX}{U{\sc nix}} + +% Variable used by begin code command +\newlength{\codewidth} + +\newcommand{\bcode}{ + % Calculate the text width for the minipage: + \setlength{\codewidth}{\linewidth} + \addtolength{\codewidth}{-\parindent} + % + \vspace{3mm} + \par + \indent + \begin{minipage}[t]{\codewidth} +} + +\newcommand{\ecode}{ + \end{minipage} + \vspace{3mm} + \par + \noindent +} diff --git a/doc/pytry b/doc/pytry new file mode 100755 index 0000000..dcc3f84 --- /dev/null +++ b/doc/pytry @@ -0,0 +1,20 @@ +TMP=/usr/tmp/pytry$$ +trap 'rm -f $TMP; exit 1' 1 2 3 13 14 15 + +cat $* >$TMP + +( + cat $TMP + + sed ' + s/^>>> // + s/^>>>$// + s/^\.\.\. // + s/^\.\.\.$// + ' $TMP | + python + + echo '>>> ' +) 2>&1 + +rm $TMP diff --git a/doc/tut.tex b/doc/tut.tex new file mode 100644 index 0000000..ad5f56c --- /dev/null +++ b/doc/tut.tex @@ -0,0 +1,1550 @@ +% Format this file with latex. + +%\documentstyle[garamond,11pt,myformat]{article} +\documentstyle[11pt,myformat]{article} + +\title{\bf + Python Tutorial \\ + (DRAFT) +} + +\author{ + Guido van Rossum \\ + Dept. CST, CWI, Kruislaan 413 \\ + 1098 SJ Amsterdam, The Netherlands \\ + E-mail: {\tt [email protected]} +} + +\begin{document} + +\pagenumbering{roman} + +\maketitle + +\begin{abstract} + +\noindent +\Python\ is a simple, yet powerful programming language that bridges the +gap between C and shell programming, and is thus ideally suited for rapid +prototyping. +Its syntax is put together from constructs borrowed from a variety of other +languages; most prominent are influences from ABC, C, Modula-3 and Icon. + +The \Python\ interpreter is easily extended with new functions and data +types implemented in C. +\Python\ is also suitable as an extension language for highly +customizable C applications such as editors or window managers. + +\Python\ is available for various operating systems, amongst which +several flavors of \UNIX, Amoeba, and the Apple Macintosh O.S. + +This tutorial introduces the reader informally to the basic concepts and +features of the \Python\ language and system. +It helps to have a \Python\ interpreter handy for hands-on experience, +but as the examples are self-contained, the tutorial can be read +off-line as well. + +For a description of standard objects and modules, see the Library +Reference document. +The Language Reference document (XXX not yet existing) +gives a more formal reference to the language. + +\end{abstract} + +\pagebreak + +\tableofcontents + +\pagebreak + +\pagenumbering{arabic} + +\section{Whetting Your Appetite} + +If you ever wrote a large shell script, you probably know this feeling: +you'd love to add yet another feature, but it's already so slow, and so +big, and so complicated; or the feature involves a system call or other +funcion that is only accessible from C \ldots +Usually the problem at hand isn't serious enough to warrant rewriting +the script in C; perhaps because the problem requires variable-length +strings or other data types (like sorted lists of file names) that +are easy in the shell but lots of work to implement in C; or perhaps +just because you're not sufficiently familiar with C. + +In all such cases, \Python\ is just the language for you. +\Python\ is simple to use, but it is a real programming language, offering +much more structure and support for large programs than the shell has. +On the other hand, it also offers much more error checking than C, and, +being a +{\em very-high-level language}, +it has high-level data types built in, such as flexible arrays and +dictionaries that would cost you days to implement efficiently in C. +Because of its more general data types \Python\ is applicable to a +much larger problem domain than +{\em Awk} +or even +{\em Perl}, +yet most simple things are at least as easy in \Python\ as in those +languages. + +\Python\ allows you to split up your program in modules that can be reused +in other \Python\ programs. +It comes with a large collection of standard modules that you can use as +the basis for your programs --- or as examples to start learning to +program in \Python. +There are also built-in modules that provide things like file I/O, +system calls, and even a generic interface to window systems (STDWIN). + +\Python\ is an interpreted language, which saves you considerable time +during program development because no compilation and linking is +necessary. +The interpreter can be used interactively, which makes it easy to +experiment with features of the language, to write throw-away programs, +or to test functions during bottom-up program development. +It is also a handy desk calculator. + +\Python\ allows writing very compact and readable programs. +Programs written in \Python\ are typically much shorter than equivalent C +programs: +No declarations are necessary (all type checking is +dynamic); statement grouping is done by indentation instead of begin/end +brackets; and the high-level data types allow you to express complex +operations in a single statement. + +\Python\ is +{\em extensible}: +if you know how to program in C it is easy to add a new built-in module +to the interpreter, either to perform critical operations at maximum +speed, or to link \Python\ programs to libraries that may be only available +in binary form (such as a vendor-specific graphics library). +Once you are really hooked, you can link the \Python\ interpreter into an +application written in C and use it as an extension or command language. + +\subsection{Where From Here} + +Now that you are all excited about \Python, you'll want to examine it in +some more detail. +Since the best introduction to a language is using it, you are invited +here to do so. + +In the next section, the mechanics of using the interpreter are +explained. +This is rather mundane information, but essential for trying out the +examples shown later. +The rest of the tutorial introduces various features of the \Python\ +language and system though examples, beginning with simple expressions, +statements and data types, through functions and modules, and finally +touching upon advanced concepts like exceptions and classes. + +\section{Using the Python Interpreter} + +The \Python\ interpreter is usually installed as +{\tt /usr/local/python} +on those machines where it is available; putting +{\tt /usr/local} +in your \UNIX\ shell's search path makes it possible to start it by +typing the command +\bcode\begin{verbatim} +python +\end{verbatim}\ecode +to the shell. +Since the choice of the directory where the interpreter lives is an +installation option, other places instead of +{\tt /usr/local} +are possible; check with your local \Python\ guru or system +administrator.% +\footnote{ + At CWI, at the time of writing, the interpreter can be found in + the following places: + On the Amoeba Ultrix machines, use the standard path, + {\tt /usr/local/python}. + On the Sun file servers, use + {\tt /ufs/guido/bin/}{\em arch}{\tt /python}, + where {\em arch} can be {\tt sgi} or {\tt sun4}. + On piring, use {\tt /userfs3/amoeba/bin/python}. + (If you can't find a binary advertised here, get in touch with me.) +} + +The interpreter operates somewhat like the \UNIX\ shell: when called with +standard input connected to a tty device, it reads and executes commands +interactively; when called with a file name argument or with a file as +standard input, it reads and executes a +{\em script} +from that file.% +\footnote{ + There is a difference between ``{\tt python file}'' and + ``{\tt python $<$file}''. In the latter case {\tt input()} and + {\tt raw\_input()} are satisfied from {\em file}, which has + already been read until the end by the parser, so they will read + EOF immediately. In the former case (which is usually what + you want) they are satisfied from whatever file or device is + connected to standard input of the \Python\ interpreter. +} +If available, the script name and additional arguments thereafter are +passed to the script in the variable +{\tt sys.argv}, +which is a list of strings. + +When standard input is a tty, the interpreter is said to be in +{\em interactive\ mode}. +In this mode it prompts for the next command with the +{\em primary\ prompt}, +usually three greater-than signs ({\tt >>>}); for continuation lines +it prompts with the +{\em secondary\ prompt}, +by default three dots ({\tt ...}). +Typing an EOF (Control-D) at the primary prompt causes the interpreter +to exit with a zero exit status. + +When an error occurs in interactive mode, the interpreter prints a +message and a stack trace and returns to the primary prompt; with input +from a file, it exits with a nonzero exit status. +(Exceptions handled by an +{\tt except} +clause in a +{\tt try} +statement are not errors in this context.) +Some errors are unconditionally fatal and cause an exit with a nonzero +exit; this applies to internal inconsistencies and some cases of running +out of memory. +All error messages are written to the standard error stream; normal +output from the executed commands is written to standard output. + +Typing an interrupt (normally Control-C or DEL) to the primary or +secondary prompt cancels the input and returns to the primary prompt. +Typing an interrupt while a command is being executed raises the +{\tt KeyboardInterrupt} +exception, which may be handled by a +{\tt try} +statement. + +When a module named +{\tt foo} +is imported, the interpreter searches for a file named +{\tt foo.py} +in a list of directories specified by the environment variable +{\tt PYTHONPATH}. +It has the same syntax as the \UNIX\ shell variable +{\tt PATH}, +i.e., a list of colon-separated directory names. +When +{\tt PYTHONPATH} +is not set, an installation-dependent default path is used, usually +{\tt .:/usr/local/lib/python}.% +\footnote{ + Modules are really searched in the list of directories given by + the variable {\tt sys.path} which is initialized from + {\tt PYTHONPATH} or from the installation-dependent default. + See the section on Standard Modules later. +} + +On BSD'ish \UNIX\ systems, \Python\ scripts can be made directly executable, +like shell scripts, by putting the line +\bcode\begin{verbatim} +#! /usr/local/python +\end{verbatim}\ecode +(assuming that's the name of the interpreter) at the beginning of the +script and giving the file an executable mode. +(The +{\tt \#!} +must be the first two characters of the file.) + +\subsection{Interactive Input Editing and History Substitution} + +Some versions of the \Python\ interpreter support editing of the current +input line and history substitution, similar to facilities found in the +Korn shell and the GNU Bash shell. +This is implemented using the +{\em GNU\ Readline} +library, which supports Emacs-style and vi-style editing. +This library has its own documentation which I won't duplicate here; +however, the basics are easily explained. + +If supported,% +\footnote{ + Perhaps the quickest check to see whether command line editing + is supported is typing Control-P to the first \Python\ prompt + you get. If it beeps, you have command line editing. + If not, you can skip the rest of this section. +} +input line editing is active whenever the interpreter prints a primary +or secondary prompt. +The current line can be edited using the conventional Emacs control +characters. +The most important of these are: +C-A (Control-A) moves the cursor to the beginning of the line, C-E to +the end, C-B moves it one position to the left, C-F to the right. +Backspace erases the character to the left of the cursor, C-D the +character to its right. +C-K kills (erases) the rest of the line to the right of the cursor, C-Y +yanks back the last killed string. +C-underscore undoes the last change you made; it can be repeated for +cumulative effect. + +History substitution works as follows. +All non-empty input lines issued are saved in a history buffer, +and when a new prompt is given you are positioned on a new line at the +bottom of this buffer. +C-P moves one line up (back) in the history buffer, C-N moves one down. +Any line in the history buffer can be edited; an asterisk appears in +front of the prompt to mark a line as modified. +Pressing the Return key passes the current line to the interpreter. +C-R starts an incremental reverse search; C-S starts a forward search. + +The key bindings and some other parameters of the Readline library can +be customized by placing commands in an initialization file called +{\tt \$HOME/.initrc}. +Key bindings have the form +\bcode\begin{verbatim} +key-name: function-name +\end{verbatim}\ecode +and options can be set with +\bcode\begin{verbatim} +set option-name value +\end{verbatim}\ecode +Example: +\bcode\begin{verbatim} +# I prefer vi-style editing: +set editing-mode vi +# Edit using a single line: +set horizontal-scroll-mode On +# Rebind some keys: +Meta-h: backward-kill-word +Control-u: universal-argument +\end{verbatim}\ecode +Note that the default binding for TAB in \Python\ is to insert a TAB +instead of Readline's default filename completion function. +If you insist, you can override this by putting +\bcode\begin{verbatim} +TAB: complete +\end{verbatim}\ecode +in your +{\tt \$HOME/.inputrc}. +(Of course, this makes it hard to type indented continuation lines.) + +This facility is an enormous step forward compared to previous versions of +the interpreter; however, some wishes are left: +It would be nice if the proper indentation were suggested on +continuation lines (the parser knows if an indent token is required +next). +The completion mechanism might use the interpreter's symbol table. +A function to check (or even suggest) matching parentheses, quotes +etc. would also be useful. + +\section{An Informal Introduction to Python} + +In the following examples, input and output are distinguished by the +presence or absence of prompts ({\tt >>>} and {\tt ...}): to repeat the +example, you must type everything after the prompt, when the prompt +appears; everything on lines that do not begin with a prompt is output +from the interpreter. +Note that a secondary prompt on a line by itself in an example means you +must type a blank line; this is used to end a multi-line command. + +\subsection{Using Python as a Calculator} + +Let's try some simple \Python\ commands. +Start the interpreter and wait for the primary prompt, +{\tt >>>}. +The interpreter acts as a simple calculator: you can type an expression +at it and it will write the value. +Expression syntax is straightforward: the operators +{\tt +}, +{\tt -}, +{\tt *} +and +{\tt /} +work just as in most other languages (e.g., Pascal or C); parentheses +can be used for grouping. +For example: +\bcode\begin{verbatim} +>>> # This is a comment +>>> 2+2 +4 +>>> +>>> (50-5+5*6+25)/4 +25 +>>> # Division truncates towards zero: +>>> 7/3 +2 +>>> +\end{verbatim}\ecode +As in C, the equal sign ({\tt =}) is used to assign a value to a variable. +The value of an assignment is not written: +\bcode\begin{verbatim} +>>> width = 20 +>>> height = 5*9 +>>> width * height +900 +>>> +\end{verbatim}\ecode +There is some support for floating point, but you can't mix floating +point and integral numbers in expression (yet): +\bcode\begin{verbatim} +>>> 10.0 / 3.3 +3.0303030303 +>>> +\end{verbatim}\ecode +Besides numbers, \Python\ can also manipulate strings, enclosed in single +quotes: +\bcode\begin{verbatim} +>>> 'foo bar' +'foo bar' +>>> 'doesn\'t' +'doesn\'t' +>>> +\end{verbatim}\ecode +Strings are written inside quotes and with quotes and other funny +characters escaped by backslashes, to show the precise value. +(There is also a way to write strings without quotes and escapes.) +Strings can be concatenated (glued together) with the +{\tt +} +operator, and repeated with~{\tt *}: +\bcode\begin{verbatim} +>>> word = 'Help' + 'A' +>>> word +'HelpA' +>>> '<' + word*5 + '>' +'<HelpAHelpAHelpAHelpAHelpA>' +>>> +\end{verbatim}\ecode +Strings can be subscripted; as in C, the first character of a string has +subscript 0. +There is no separate character type; a character is simply a string of +size one. +As in Icon, substrings can be specified with the +{\em slice} +notation: two subscripts (indices) separated by a colon. +\bcode\begin{verbatim} +>>> word[4] +'A' +>>> word[0:2] +'He' +>>> word[2:4] +'lp' +>>> # Slice indices have useful defaults: +>>> word[:2] # Take first two characters +'He' +>>> word[2:] # Drop first two characters +'lpA' +>>> # A useful invariant: s[:i] + s[i:] = s +>>> word[:3] + word[3:] +'HelpA' +>>> +\end{verbatim}\ecode +Degenerate cases are handled gracefully: an index that is too large is +replaced by the string size, an upper bound smaller than the lower bound +returns an empty string. +\bcode\begin{verbatim} +>>> word[1:100] +'elpA' +>>> word[10:] +'' +>>> word[2:1] +'' +>>> +\end{verbatim}\ecode +Slice indices (but not simple subscripts) may be negative numbers, to +start counting from the right. +For example: +\bcode\begin{verbatim} +>>> word[-2:] # Take last two characters +'pA' +>>> word[:-2] # Drop last two characters +'Hel' +>>> # But -0 does not count from the right! +>>> word[-0:] # (since -0 equals 0) +'HelpA' +>>> +\end{verbatim}\ecode +The best way to remember how slices work is to think of the indices as +pointing +{\em between} +characters, with the left edge of the first character numbered 0. +Then the right edge of the last character of a string of +{\tt n} +characters has index +{\tt n}, +for example: +\bcode\begin{verbatim} + +---+---+---+---+---+ + | H | e | l | p | A | + +---+---+---+---+---+ + 0 1 2 3 4 5 +-5 -4 -3 -2 -1 +\end{verbatim}\ecode +The first row of numbers gives the position of the indices 0...5 in the +string; the second row gives the corresponding negative indices. +For nonnegative indices, the length of a slice is the difference of the +indices, if both are within bounds, +e.g., +the length of +{\tt word[1:3]} +is 3--1 = 2. + +Finally, the built-in function {\tt len()} computes the length of a +string: +\bcode\begin{verbatim} +>>> s = 'supercalifragilisticexpialidocious' +>>> len(s) +34 +>>> +\end{verbatim}\ecode +\Python\ knows a number of +{\em compound} +data types, used to group together other values. +The most versatile is the +{\em list}, +which can be written as a list of comma-separated values between square +brackets: +\bcode\begin{verbatim} +>>> a = ['foo', 'bar', 100, 1234] +>>> a +['foo', 'bar', 100, 1234] +>>> +\end{verbatim}\ecode +As for strings, list subscripts start at 0: +\bcode\begin{verbatim} +>>> a[0] +'foo' +>>> a[3] +1234 +>>> +\end{verbatim}\ecode +Lists can be sliced and concatenated like strings: +\bcode\begin{verbatim} +>>> a[1:3] +['bar', 100] +>>> a[:2] + ['bletch', 2*2] +['foo', 'bar', 'bletch', 4] +>>> +\end{verbatim}\ecode +Unlike strings, which are +{\em immutable}, +it is possible to change individual elements of a list: +\bcode\begin{verbatim} +>>> a +['foo', 'bar', 100, 1234] +>>> a[2] = a[2] + 23 +>>> a +['foo', 'bar', 123, 1234] +>>> +\end{verbatim}\ecode +Assignment to slices is also possible, and this may even change the size +of the list: +\bcode\begin{verbatim} +>>> # Replace some items: +>>> a[0:2] = [1, 12] +>>> a +[1, 12, 123, 1234] +>>> # Remove some: +>>> a[0:2] = [] +>>> a +[123, 1234] +>>> # Insert some: +>>> a[1:1] = ['bletch', 'xyzzy'] +>>> a +[123, 'bletch', 'xyzzy', 1234] +>>> +\end{verbatim}\ecode +The built-in function {\tt len()} also applies to lists: +\bcode\begin{verbatim} +>>> len(a) +4 +>>> +\end{verbatim}\ecode + +\subsection{Tuples and Sequences} + +XXX To Be Done. + +\subsection{First Steps Towards Programming} + +Of course, we can use \Python\ for more complicated tasks than adding two +and two together. +For instance, we can write an initial subsequence of the +{\em Fibonacci} +series as follows: +\bcode\begin{verbatim} +>>> # Fibonacci series: +>>> # the sum of two elements defines the next +>>> a, b = 0, 1 +>>> while b < 100: +... print b +... a, b = b, a+b +... +1 +1 +2 +3 +5 +8 +13 +21 +34 +55 +89 +>>> +\end{verbatim}\ecode +This example introduces several new features. +\begin{itemize} +\item +The first line contains a +{\em multiple\ assignment}: +the variables +{\tt a} +and +{\tt b} +simultaneously get the new values 0 and 1. +On the last line this is used again, demonstrating that the expressions +on the right-hand side are all evaluated first before any of the +assignments take place. +\item +The +{\tt while} +loop executes as long as the condition (here: $b < 100$) remains true. +In \Python, as in C, any non-zero integer value is true; zero is false. +The condition may also be a string or list value, in fact any sequence; +anything with a non-zero length is true, empty sequences are false. +The test used in the example is a simple comparison. +The standard comparison operators are written as +{\tt <}, +{\tt >}, +{\tt =}, +{\tt <=}, +{\tt >=} +and +{\tt <>}.% +\footnote{ + The ambiguity of using {\tt =} + for both assignment and equality is resolved by disallowing + unparenthesized conditions at the right hand side of assignments. +} +\item +The +{\em body} +of the loop is +{\em indented}: indentation is \Python's way of grouping statements. +\Python\ does not (yet!) provide an intelligent input line editing +facility, so you have to type a tab or space(s) for each indented line. +In practice you will prepare more complicated input for \Python\ with a +text editor; most text editors have an auto-indent facility. +When a compound statement is entered interactively, it must be +followed by a blank line to indicate completion (since the parser +cannot guess when you have typed the last line). +\item +The +{\tt print} +statement writes the value of the expression(s) it is given. +It differs from just writing the expression you want to write (as we did +earlier in the calculator examples) in the way it handles multiple +expressions and strings. +Strings are written without quotes and a space is inserted between +items, so you can format things nicely, like this: +\bcode\begin{verbatim} +>>> i = 256*256 +>>> print 'The value of i is', i +The value of i is 65536 +>>> +\end{verbatim}\ecode +A trailing comma avoids the newline after the output: +\bcode\begin{verbatim} +>>> a, b = 0, 1 +>>> while b < 1000: +... print b, +... a, b = b, a+b +... +1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 +>>> +\end{verbatim}\ecode +Note that the interpreter inserts a newline before it prints the next +prompt if the last line was not completed. +\end{itemize} + +\subsection{More Control Flow Tools} + +Besides the {\tt while} statement just introduced, \Python\ knows the +usual control flow statements known from other languages, with some +twists. + +\subsubsection{If Statements} + +Perhaps the most well-known statement type is the {\tt if} statement. +For example: +\bcode\begin{verbatim} +>>> if x < 0: +... x = 0 +... print 'Negative changed to zero' +... elif x = 0: +... print 'Zero' +... elif x = 1: +... print 'Single' +... else: +... print 'More' +... +\end{verbatim}\ecode +There can be zero or more {\tt elif} parts, and the {\tt else} part is +optional. +The keyword `{\tt elif}' is short for `{\tt else if}', and is useful to +avoid excessive indentation. +An {\tt if...elif...elif...} sequence is a substitute for the +{\em switch} or {\em case} statements found in other languages. + +\subsubsection{For Statements} + +The {\tt for} statement in \Python\ differs a bit from what you may be +used to in C or Pascal. +Rather than always iterating over an arithmetic progression of numbers +(as Pascal), or leaving the user completely free in the iteration test +and step (as C), \Python's {\tt for} statement iterates over the items +of any sequence (e.g., a list or a string). +For example (no pun intended): +\bcode\begin{verbatim} +>>> # Measure some strings: +>>> a = ['cat', 'window', 'defenestrate'] +>>> for x in a: +... print x, len(x) +... +cat 3 +window 6 +defenestrate 12 +>>> +\end{verbatim}\ecode + +\subsubsection{The {\tt range()} Function} + +If you do need to iterate over a sequence of numbers, the built-in +function {\tt range()} comes in handy. +It generates lists containing arithmetic progressions, +e.g.: +\bcode\begin{verbatim} +>>> range(10) +[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +>>> +\end{verbatim}\ecode +The given end point is never part of the generated list; +{\tt range(10)} generates a list of 10 values, +exactly the legal indices for items of a sequence of length 10. +It is possible to let the range start at another number, or to specify a +different increment (even negative): +\bcode\begin{verbatim} +>>> range(5, 10) +[5, 6, 7, 8, 9] +>>> range(0, 10, 3) +[0, 3, 6, 9] +>>> range(-10, -100, -30) +[-10, -40, -70] +>>> +\end{verbatim}\ecode +To iterate over the indices of a sequence, combine {\tt range()} +and {\tt len()} as follows: +\bcode\begin{verbatim} +>>> a = ['Mary', 'had', 'a', 'little', 'boy'] +>>> for i in range(len(a)): +... print i, a[i] +... +0 Mary +1 had +2 a +3 little +4 boy +>>> +\end{verbatim}\ecode + +\subsubsection{Break Statements and Else Clauses on Loops} + +The {\tt break} statement breaks out of the smallest enclosing {\tt for} +or {\tt while} loop. +Loop statements may have an {\tt else} clause; it is executed when the +loop terminates through exhaustion of the list (with {\tt for}) or when +the condition becomes false (with {\tt while}) but not when the loop is +terminated by a {\tt break} statement. +This is exemplified by the following loop, which searches for a list +item of value 0: +\bcode\begin{verbatim} +>>> for n in range(2, 10): +... for x in range(2, n): +... if n % x = 0: +... print n, 'equals', x, '*', n/x +... break +... else: +... print n, 'is a prime number' +... +2 is a prime number +3 is a prime number +4 equals 2 * 2 +5 is a prime number +6 equals 2 * 3 +7 is a prime number +8 equals 2 * 4 +9 equals 3 * 3 +>>> +\end{verbatim}\ecode + +\subsubsection{Pass Statements} + +The {\tt pass} statement does nothing. +It can be used when a statement is required syntactically but the +program requires no action. +For example: +\bcode\begin{verbatim} +>>> while 1: +... pass # Busy-wait for keyboard interrupt +... +\end{verbatim}\ecode + +\subsubsection{Conditions Revisited} + +XXX To Be Done. + +\subsection{Defining Functions} + +We can create a function that writes the Fibonacci series to an +arbitrary boundary: +\bcode\begin{verbatim} +>>> def fib(n): # write Fibonacci series up to n +... a, b = 0, 1 +... while b <= n: +... print b, +... a, b = b, a+b +... +>>> # Now call the function we just defined: +>>> fib(2000) +1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 +>>> +\end{verbatim}\ecode +The keyword +{\tt def} +introduces a function +{\em definition}. +It must be followed by the function name and the parenthesized list of +formal parameters. +The statements that form the body of the function starts at the next +line, indented by a tab stop. +The +{\em execution} +of a function introduces a new symbol table used for the local variables +of the function. +More precisely, all variable assignments in a function store the value +in the local symbol table; variable references first look in the local +symbol table, then in the global symbol table, and then in the table of +built-in names. +Thus, the global symbol table is +{\em read-only} +within a function. +The actual parameters (arguments) to a function call are introduced in +the local symbol table of the called function when it is called; +thus, arguments are passed using +{\em call\ by\ value}.% +\footnote{ + Actually, {\em call by object reference} would be a better + description, since if a mutable object is passed, the caller + will see any changes the callee makes to it (e.g., items + inserted into a list). +} +When a function calls another function, a new local symbol table is +created for that call. + +A function definition introduces the function name in the global symbol +table. +The value has a type that is recognized by the interpreter as a +user-defined function. +This value can be assigned to another name which can then also be used +as a function. +This serves as a general renaming mechanism: +\bcode\begin{verbatim} +>>> fib +<function object at 10042ed0> +>>> f = fib +>>> f(100) +1 1 2 3 5 8 13 21 34 55 89 +>>> +\end{verbatim}\ecode +You might object that +{\tt fib} +is not a function but a procedure. +In \Python, as in C, procedures are just functions that don't return a +value. +In fact, technically speaking, procedures do return a value, albeit a +rather boring one. +This value is called {\tt None} (it's a built-in name). +Writing the value {\tt None} is normally suppressed by the interpreter +if it would be the only value written. +You can see it if you really want to: +\bcode\begin{verbatim} +>>> print fib(0) +None +>>> +\end{verbatim}\ecode +It is simple to write a function that returns a list of the numbers of +the Fibonacci series, instead of printing it: +\bcode\begin{verbatim} +>>> def fib2(n): # return Fibonacci series up to n +... result = [] +... a, b = 0, 1 +... while b <= n: +... result.append(b) # see below +... a, b = b, a+b +... return result +... +>>> f100 = fib2(100) # call it +>>> f100 # write the result +[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] +>>> +\end{verbatim}\ecode +This example, as usual, demonstrates some new \Python\ features: +\begin{itemize} +\item +The +{\tt return} +statement returns with a value from a function. +{\tt return} +without an expression argument is used to return from the middle of a +procedure (falling off the end also returns from a proceduce). +\item +The statement +{\tt ret.append(b)} +calls a +{\em method} +of the list object +{\tt ret}. +A method is a function that `belongs' to an object and is named +{\tt obj.methodname}, +where +{\tt obj} +is some object (this may be an expression), and +{\tt methodname} +is the name of a method that is defined by the object's type. +Different types define different methods. +Methods of different types may have the same name without causing +ambiguity. +See the section on classes, later, to find out how you can define your +own object types and methods. +The method +{\tt append} +shown in the example, is defined for list objects; it adds a new element +at the end of the list. +In this case it is equivalent to +{\tt ret = ret + [b]}, +but more efficient.% +\footnote{ + There is a subtle semantic difference if the object + is referenced from more than one place. +} +\end{itemize} +The list object type has two more methods: +\begin{description} +\item[{\tt insert(i, x)}] +Inserts an item at a given position. +The first argument is the index of the element before which to insert, +so {\tt a.insert(0, x)} inserts at the front of the list, and +{\tt a.insert(len(a), x)} is equivalent to {\tt a.append(x)}. +\item[{\tt sort()}] +Sorts the elements of the list. +\end{description} +For example: +\bcode\begin{verbatim} +>>> a = [10, 100, 1, 1000] +>>> a.insert(2, -1) +>>> a +[10, 100, -1, 1, 1000] +>>> a.sort() +>>> a +[-1, 1, 10, 100, 1000] +>>> # Strings are sorted according to ASCII: +>>> b = ['Mary', 'had', 'a', 'little', 'boy'] +>>> b.sort() +>>> b +['Mary', 'a', 'boy', 'had', 'little'] +>>> +\end{verbatim}\ecode + +\subsection{Modules} + +If you quit from the \Python\ interpreter and enter it again, the +definitions you have made (functions and variables) are lost. +Therefore, if you want to write a somewhat longer program, you are +better off using a text editor to prepare the input for the interpreter +and run it with that file as input instead. +This is known as creating a +{\em script}. +As your program gets longer, you may want to split it into several files +for easier maintenance. +You may also want to use a handy function that you've written in several +programs without copying its definition into each program. +To support this, \Python\ has a way to put definitions in a file and use +them in a script or in an interactive instance of the interpreter. +Such a file is called a +{\em module}; +definitions from a module can be +{\em imported} +into other modules or into the +{\em main} +module (the collection of variables that you have access to in +a script and in calculator mode). + +A module is a file containing \Python\ definitions and statements. +The file name is the module name with the suffix +{\tt .py} +appended. +For instance, use your favorite text editor to create a file called +{\tt fibo.py} +in the current directory with the following contents: +\bcode\begin{verbatim} +# Fibonacci numbers module + +def fib(n): # write Fibonacci series up to n + a, b = 0, 1 + while b <= n: + print b, + a, b = b, a+b + +def fib2(n): # return Fibonacci series up to n + ret = [] + a, b = 0, 1 + while b <= n: + ret.append(b) + a, b = b, a+b + return ret +\end{verbatim}\ecode +Now enter the \Python\ interpreter and import this module with the +following command: +\bcode\begin{verbatim} +>>> import fibo +>>> +\end{verbatim}\ecode +This does not enter the names of the functions defined in +{\tt fibo} +directly in the symbol table; it only enters the module name +{\tt fibo} +there. +Using the module name you can access the functions: +\bcode\begin{verbatim} +>>> fibo.fib(1000) +1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 +>>> fibo.fib2(100) +[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] +>>> +\end{verbatim}\ecode +If you intend to use a function often you can assign it to a local name: +\bcode\begin{verbatim} +>>> fib = fibo.fib +>>> fib(500) +1 1 2 3 5 8 13 21 34 55 89 144 233 377 +>>> +\end{verbatim}\ecode + +\subsubsection{More on Modules} + +A module can contain executable statements as well as function +definitions. +These statements are intended to initialize the module. +They are executed only the +{\em first} +time the module is imported somewhere.% +\footnote{ + In fact function definitions are also `statements' that are + `executed'; the execution enters the function name in the + module's global symbol table. +} + +Each module has its own private symbol table, which is used as the +global symbol table by all functions defined in the module. +Thus, the author of a module can use global variables in the module +without worrying about accidental clashes with a user's global +variables. +On the other hand, if you know what you are doing you can touch a +module's global variables with the same notation used to refer to its +functions, +{\tt modname.itemname}. + +Modules can import other modules. +It is customary but not required to place all +{\tt import} +statements at the beginning of a module (or script, for that matter). +The imported module names are placed in the importing module's global +symbol table. + +There is a variant of the +{\tt import} +statement that imports names from a module directly into the importing +module's symbol table. +For example: +\bcode\begin{verbatim} +>>> from fibo import fib, fib2 +>>> fib(500) +1 1 2 3 5 8 13 21 34 55 89 144 233 377 +>>> +\end{verbatim}\ecode +This does not introduce the module name from which the imports are taken +in the local symbol table (so in the example, {\tt fibo} is not +defined). + +There is even a variant to import all names that a module defines: +\bcode\begin{verbatim} +>>> from fibo import * +>>> fib(500) +1 1 2 3 5 8 13 21 34 55 89 144 233 377 +>>> +\end{verbatim}\ecode +This imports all names except those beginning with an underscore +({\tt \_}). + +\subsubsection{Standard Modules} + +\Python\ comes with a library of standard modules, described in a separate +document (Python Library and Module Reference). +Some modules are built into the interpreter; these provide access to +operations that are not part of the core of the language but are +nevertheless built in, either for efficiency or to provide access to +operating system primitives such as system calls. +The set of such modules is a configuration option; e.g., the +{\tt amoeba} +module is only provided on systems that somehow support Amoeba +primitives. +One particular module deserves some attention: +{\tt sys}, +which is built into every \Python\ interpreter. +The variables +{\tt sys.ps1} +and +{\tt sys.ps2} +define the strings used as primary and secondary prompts: +\bcode\begin{verbatim} +>>> import sys +>>> sys.ps1 +'>>> ' +>>> sys.ps2 +'... ' +>>> sys.ps1 = 'C> ' +C> print 'Yuck!' +Yuck! +C> +\end{verbatim}\ecode +These two variables are only defined if the interpreter is in +interactive mode. + +The variable +{\tt sys.path} +is a list of strings that determine the interpreter's search path for +modules. +It is initialized to a default path taken from the environment variable +{\tt PYTHONPATH}, +or from a built-in default if +{\tt PYTHONPATH} +is not set. +You can modify it using standard list operations, e.g.: +\bcode\begin{verbatim} +>>> import sys +>>> sys.path.append('/ufs/guido/lib/python') +>>> +\end{verbatim}\ecode + +\subsection{Errors and Exceptions} + +Until now error messages haven't yet been mentioned, but if you have +tried out the examples you have probably seen some. +There are (at least) two distinguishable kinds of errors: +{\em syntax\ errors} +and +{\em exceptions}. + +\subsubsection{Syntax Errors} + +Syntax errors, also known as parsing errors, are perhaps the most common +kind of complaint you get while you are still learning \Python: +\bcode\begin{verbatim} +>>> while 1 print 'Hello world' +Parsing error: file <stdin>, line 1: +while 1 print 'Hello world' + ^ +Unhandled exception: run-time error: syntax error +>>> +\end{verbatim}\ecode +The parser repeats the offending line and displays a little `arrow' +pointing at the earliest point in the line where the error was detected. +The error is caused by (or at least detected at) the token +{\em preceding} +the arrow: in the example, the error is detected at the keyword +{\tt print}, since a colon ({\tt :}) is missing before it. +File name and line number are printed so you know where to look in case +the input came from a script. + +\subsubsection{Exceptions} + +Even if a statement or expression is syntactically correct, it may cause +an error when an attempt is made to execute it: +\bcode\small\begin{verbatim} +>>> 10 * (1/0) +Unhandled exception: run-time error: integer division by zero +Stack backtrace (innermost last): + File "<stdin>", line 1 +>>> 4 + foo*3 +Unhandled exception: undefined name: foo +Stack backtrace (innermost last): + File "<stdin>", line 1 +>>> '2' + 2 +Unhandled exception: type error: illegal argument type for built-in operation +Stack backtrace (innermost last): + File "<stdin>", line 1 +>>> +\end{verbatim}\ecode +Errors detected during execution are called +{\em exceptions} +and are not unconditionally fatal: you will soon learn how to handle +them in \Python\ programs. +Most exceptions are not handled by programs, however, and result +in error messages as shown here. + +The first line of the error message indicates what happened. +Exceptions come in different types, and the type is printed as part of +the message: the types in the example are +{\tt run-time error}, +{\tt undefined name} +and +{\tt type error}. +The rest of the line is a detail whose interpretation depends on the +exception type. + +The rest of the error message shows the context where the +exception happened. +In general it contains a stack backtrace listing source lines; however, +it will not display lines read from standard input. + +Here is a summary of the most common exceptions: +\begin{itemize} +\item +{\em Run-time\ errors} +are generally caused by wrong data used by the program; this can be the +programmer's fault or caused by bad input. +The detail states the cause of the error in more detail. +\item +{\em Undefined\ name} +errors are more serious: these are usually caused by misspelled +identifiers.% +\footnote{ + The parser does not check whether names used in a program are at + all defined elsewhere in the program, so such checks are + postponed until run-time. The same holds for type checking. +} +The detail is the offending identifier. +\item +{\em Type\ errors} +are also pretty serious: this is another case of using wrong data (or +better, using data the wrong way), but here the error can be glanced +from the object type(s) alone. +The detail shows in what context the error was detected. +\end{itemize} + +\subsubsection{Handling Exceptions} + +It is possible to write programs that handle selected exceptions. +Look at the following example, which prints a table of inverses of +some floating point numbers: +\bcode\begin{verbatim} +>>> numbers = [0.3333, 2.5, 0.0, 10.0] +>>> for x in numbers: +... print x, +... try: +... print 1.0 / x +... except RuntimeError: +... print '*** has no inverse ***' +... +0.3333 3.00030003 +2.5 0.4 +0 *** has no inverse *** +10 0.1 +>>> +\end{verbatim}\ecode +The {\tt try} statement works as follows. +\begin{itemize} +\item +First, the +{\em try\ clause} +(the statement(s) between the {\tt try} and {\tt except} keywords) is +executed. +\item +If no exception occurs, the +{\em except\ clause} +is skipped and execution of the {\tt try} statement is finished. +\item +If an exception occurs during execution of the try clause, and its +type matches the exception named after the {\tt except} keyword, the +rest of the try clause is skipped, the except clause is executed, and +then execution continues after the {\tt try} statement. +\item +If an exception occurs which does not match the exception named in the +except clause, it is passed on to outer try statements; if no handler is +found, it is an +{\em unhandled\ exception} +and execution stops with a message as shown above. +\end{itemize} +A {\tt try} statement may have more than one except clause, to specify +handlers for different exceptions. +At most one handler will be executed. +Handlers only handle exceptions that occur in the corresponding try +clause, not in other handlers of the same {\tt try} statement. +An except clause may name multiple exceptions as a parenthesized list, +e.g.: +\bcode\begin{verbatim} +... except (RuntimeError, TypeError, NameError): +... pass +\end{verbatim}\ecode +The last except clause may omit the exception name(s), to serve as a +wildcard. +Use this with extreme caution! + +When an exception occurs, it may have an associated value, also known as +the exceptions's +{\em argument}. +The presence and type of the argument depend on the exception type. +For exception types which have an argument, the except clause may +specify a variable after the exception name (or list) to receive the +argument's value, as follows: +\bcode\begin{verbatim} +>>> try: +... foo() +... except NameError, x: +... print 'name', x, 'undefined' +... +name foo undefined +>>> +\end{verbatim}\ecode +If an exception has an argument, it is printed as the third part +(`detail') of the message for unhandled exceptions. + +Standard exception names are built-in identifiers (not reserved +keywords). +These are in fact string objects whose +{\em object\ identity} +(not their value!) identifies the exceptions.% +\footnote{ + There should really be a separate exception type; it is pure + laziness that exceptions are identified by strings, and this may + be fixed in the future. +} +The string is printed as the second part of the message for unhandled +exceptions. +Their names and values are: +\bcode\begin{verbatim} +EOFError 'end-of-file read' +KeyboardInterrupt 'keyboard interrupt' +MemoryError 'out of memory' * +NameError 'undefined name' * +RuntimeError 'run-time error' * +SystemError 'system error' * +TypeError 'type error' * +\end{verbatim}\ecode +The meanings should be clear enough. +Those exceptions with a {\tt *} in the third column have an argument. + +Exception handlers don't just handle exceptions if they occur +immediately in the try clause, but also if they occur inside functions +that are called (even indirectly) in the try clause. +For example: +\bcode\begin{verbatim} +>>> def this_fails(): +... x = 1/0 +... +>>> try: +... this_fails() +... except RuntimeError, detail: +... print 'Handling run-time error:', detail +... +Handling run-time error: domain error or zero division +>>> +\end{verbatim}\ecode + +\subsubsection{Raising Exceptions} + +The {\tt raise} statement allows the programmer to force a specified +exception to occur. +For example: +\bcode\begin{verbatim} +>>> raise NameError, 'Hi There!' +Unhandled exception: undefined name: Hi There! +Stack backtrace (innermost last): + File "<stdin>", line 1 +>>> +\end{verbatim}\ecode +The first argument to {\tt raise} names the exception to be raised. +The optional second argument specifies the exception's argument. + +\subsubsection{User-defined Exceptions} + +Programs may name their own exceptions by assigning a string to a +variable. +For example: +\bcode\begin{verbatim} +>>> my_exc = 'nobody likes me!' +>>> try: +... raise my_exc, 2*2 +... except my_exc, val: +... print 'My exception occured, value:', val +... +My exception occured, value: 4 +>>> raise my_exc, 1 +Unhandled exception: nobody likes me!: 1 +Stack backtrace (innermost last): + File "<stdin>", line 7 +>>> +\end{verbatim}\ecode +Many standard modules use this to report errors that may occur in +functions they define. + +\subsubsection{Defining Clean-up Actions} + +The {\tt try} statement has another optional clause which is intended to +define clean-up actions that must be executed under all circumstances. +For example: +\bcode\begin{verbatim} +>>> try: +... raise KeyboardInterrupt +... finally: +... print 'Goodbye, world!' +... +Goodbye, world! +Unhandled exception: keyboard interrupt +Stack backtrace (innermost last): + File "<stdin>", line 2 +>>> +\end{verbatim}\ecode +The +{\em finally\ clause} +must follow the except clauses(s), if any. +It is executed whether or not an exception occurred. +If the exception is handled, the finally clause is executed after the +handler (and even if another exception occurred in the handler). +It is also executed when the {\tt try} statement is left via a +{\tt break} or {\tt return} statement. + +\subsection{Classes} + +Classes in \Python\ make it possible to play the game of encapsulation in a +somewhat different way than it is played with modules. +Classes are an advanced topic and are probably best skipped on the first +encounter with \Python. + +\subsubsection{Prologue} + +\Python's class mechanism is not particularly elegant, but quite powerful. +It is a mixture of the class mechanisms found in C++ and Modula-3. +As is true for modules, classes in \Python\ do not put an absolute barrier +between definition and user, but rather rely on the politeness of the +user not to ``break into the definition.'' +The most important features of classes are retained with full power, +however: the class inheritance mechanism allows multiple base classes, +a derived class can override any method of its base class(es), a method +can call the method of a base class with the same name. +Objects can contain an arbitrary amount of private data. + +In C++ terminology, all class members (including data members) are +{\em public}, +and all member functions (methods) are +{\em virtual}. +There are no special constructors or destructors. +As in Modula-3, there are no shorthands for referencing the object's +members from its methods: the method function is declared with an +explicit first argument representing the object, which is provided +implicitly by the call. +As in Smalltalk, classes themselves are objects, albeit in the wider +sense of the word: in \Python, all data types are objects. +This provides semantics for renaming or aliasing. +But, just like in C++ or Modula-3, the built-in types cannot be used as +base classes for extension by the user. +Also, like Modula-3 but unlike C++, the built-in operators with special +syntax (arithmetic operators, subscripting etc.) cannot be redefined for +class members.% +\footnote{ + They can be redefined for new object types implemented in C in + extensions to the interpreter, however. It would require only a + naming convention and a relatively small change to the + interpreter to allow operator overloading for classes, so + perhaps someday... +} + +\subsubsection{A Simple Example} + +Consider the following example, which defines a class {\tt Set} +representing a (finite) mathematical set with operations to add and +remove elements, a membership test, and a request for the size of the +set. +\bcode\begin{verbatim} +class Set(): + def new(self): + self.elements = [] + return self + def add(self, e): + if e not in self.elements: + self.elements.append(e) + def remove(self, e): + if e in self.elements: + for i in range(len(self.elements)): + if self.elements[i] = e: + del self.elements[i] + break + def is_element(self, e): + return e in self.elements + def size(self): + return len(self.elements) +\end{verbatim}\ecode +Note that the class definition looks like a big compound statement, +with all the function definitons indented repective to the +{\tt class} +keyword. + +Let's assume that this +{\em class\ definition} +is the only contents of the module file +{\tt SetClass.py}. +We can then use it in a \Python\ program as follows: +\bcode\begin{verbatim} +>>> from SetClass import Set +>>> a = Set().new() # create a Set object +>>> a.add(2) +>>> a.add(3) +>>> a.add(1) +>>> a.add(1) +>>> if a.is_element(3): print '3 is in the set' +... +3 is in the set +>>> if not a.is_element(4): print '4 is not in the set' +... +4 is not in the set +>>> print 'a has', a.size(), 'elements' +a has 3 elements +>>> a.remove(1) +>>> print 'now a has', a.size(), 'elements' +>>> +now a has 2 elements +>>> +\end{verbatim}\ecode +From the example we learn in the first place that the functions defined +in the class (e.g., +{\tt add}) +can be called using the +{\em member} +notation for the object +{\tt a}. +The member function is called with one less argument than it is defined: +the object is implicitly passed as the first argument. +Thus, the call +{\tt a.add(2)} +is equivalent to +{\tt Set.add(a, 2)}. + +XXX This section is not complete yet! + +\section{XXX P.M.} + +\begin{itemize} +\item The {\tt del} statement. +\item The {\tt dir()} function. +\item Tuples. +\item Dictionaries. +\item Objects and types in general. +\item Backquotes. +\item And/Or/Not. +\end{itemize} + +\end{document} diff --git a/lib/Abstract.py b/lib/Abstract.py new file mode 100644 index 0000000..385e6e5 --- /dev/null +++ b/lib/Abstract.py @@ -0,0 +1,61 @@ +# Abstract classes for parents and children. +# +# Do not use as base class -- this is for documentation only. +# +# Note that the tree must be built top down (create the parent, +# then add the children). +# +# Also note that the creation methods are not standardized -- +# these have extra parameters dependent on the widget type. +# For historical reasons, button creation methods are called +# define() while split creation methods are called create(). + +class AbstractParent(): + # + # Upcalls from child to parent + # + def addchild(self, child): unimpl() + def delchild(self, child): unimpl() + # + def need_mouse(self, child): unimpl() + def no_mouse(self, child): unimpl() + # + def need_timer(self, child): unimpl() + def no_timer(self, child): unimpl() + # + # XXX need_kbd, no_kbd; focus??? + # + def begindrawing(self): return unimpl() + def beginmeasuring(self): return unimpl() + # + def change(self, area): unimpl() + def scroll(self, (area, (dh, dv))): unimpl() + def settimer(self, itimer): unimpl() + +class AbstractChild(): + # + # Downcalls from parent to child + # + def destroy(self): unimpl() + # + def minsize(self, m): return unimpl() + def getbounds(self): return unimpl() + def setbounds(self, bounds): unimpl() + def draw(self, (d, area)): unimpl() + # + # Downcalls only made after certain upcalls + # + def mouse_down(self, detail): unimpl() + def mouse_move(self, detail): unimpl() + def mouse_up(self, detail): unimpl() + # + def timer(self): unimpl() + +# A "Split" is a child that manages one or more children. +# (This terminology is due to DEC SRC, except for CSplits.) +# A child of a split may be another split, a button, a slider, etc. +# Certain upcalls and downcalls can be handled transparently, but +# for others (e.g., all geometry related calls) this is not possible. + +class AbstractSplit() = AbstractChild(), AbstractParent(): + pass diff --git a/lib/Buttons.py b/lib/Buttons.py new file mode 100644 index 0000000..7c36021 --- /dev/null +++ b/lib/Buttons.py @@ -0,0 +1,399 @@ +# Module 'Buttons' + + +# Import module 'rect' renamed as '_rect' to avoid exporting it on +# 'from Buttons import *' +# +import rect +_rect = rect +del rect + + +# Field indices in mouse event detail +# +_HV = 0 +_CLICKS = 1 +_BUTTON = 2 +_MASK = 3 + + +# LabelAppearance provides defaults for all appearance methods. +# selected state not visible +# disabled --> crossed out +# hilited --> inverted +# +class LabelAppearance(): + # + # Initialization + # + def init_appearance(self): + self.bounds = _rect.empty + self.enabled = 1 + self.hilited = 0 + self.selected = 0 + self.text = '' + # + # Size enquiry + # + def minsize(self, m): + try: + self.text = self.text + except NameError: + self.text = '' + return m.textwidth(self.text) + 6, m.lineheight() + 6 + # + def getbounds(self): + return self.bounds + # + # Changing the parameters + # + def settext(self, text): + self.text = text + if self.bounds <> _rect.empty: + self.recalctextpos() + self.redraw() + # + def setbounds(self, bounds): + if self.bounds <> _rect.empty: + self.parent.change(self.bounds) + self.bounds = bounds + if self.bounds <> _rect.empty: + self.recalc() + self.parent.change(bounds) + # + # Changing the state bits + # + def enable(self, flag): + if flag <> self.enabled: + self.enabled = flag + if self.bounds <> _rect.empty: + self.flipenable(self.parent.begindrawing()) + # + def hilite(self, flag): + if flag <> self.hilited: + self.hilited = flag + if self.bounds <> _rect.empty: + self.fliphilite(self.parent.begindrawing()) + # + def select(self, flag): + if flag <> self.selected: + self.selected = flag + if self.bounds <> _rect.empty: + self.redraw() + # + # Recalculate the box bounds and text position. + # This can be overridden by buttons that draw different boxes + # or want their text in a different position. + # + def recalc(self): + if self.bounds <> _rect.empty: + self.recalcbounds() + self.recalctextpos() + # + def recalcbounds(self): + self.hilitebounds = _rect.inset(self.bounds, (3, 3)) + self.crossbounds = self.bounds + # + def recalctextpos(self): + (left, top), (right, bottom) = self.bounds + m = self.parent.beginmeasuring() + h = (left + right - m.textwidth(self.text)) / 2 + v = (top + bottom - m.lineheight()) / 2 + self.textpos = h, v + # + # Generic drawing interface. + # Do not override redraw() or draw() methods; override drawit() c.s. + # + def redraw(self): + if self.bounds <> _rect.empty: + self.draw(self.parent.begindrawing(), self.bounds) + # + def draw(self, (d, area)): + area = _rect.intersect(area, self.bounds) + if area = _rect.empty: + return + d.cliprect(area) + d.erase(self.bounds) + self.drawit(d) + d.noclip() + # + # The drawit() method is fairly generic but may be overridden. + # + def drawit(self, d): + self.drawpict(d) + if self.text: + d.text(self.textpos, self.text) + if not self.enabled: + self.flipenable(d) + if self.hilited: + self.fliphilite(d) + # + # Default drawing detail functions. + # Overriding these is normally sufficient to get different + # appearances. + # + def drawpict(self, d): + pass + # + def flipenable(self, d): + _xorcross(d, self.crossbounds) + # + def fliphilite(self, d): + d.invert(self.hilitebounds) + + +# ButtonAppearance displays a centered string in a box. +# selected --> bold border +# disabled --> crossed out +# hilited --> inverted +# +class ButtonAppearance() = LabelAppearance(): + # + def drawpict(self, d): + d.box(_rect.inset(self.bounds, (1, 1))) + if self.selected: + # Make a thicker box + d.box(self.bounds) + d.box(_rect.inset(self.bounds, (2, 2))) + d.box(_rect.inset(self.bounds, (3, 3))) + # + + +# CheckAppearance displays a small square box and a left-justified string. +# selected --> a cross appears in the box +# disabled --> whole button crossed out +# hilited --> box is inverted +# +class CheckAppearance() = LabelAppearance(): + # + def minsize(self, m): + width, height = m.textwidth(self.text) + 6, m.lineheight() + 6 + return width + height + m.textwidth(' '), height + # + def drawpict(self, d): + d.box(self.boxbounds) + if self.selected: _xorcross(d, self.boxbounds) + # + def recalcbounds(self): + LabelAppearance.recalcbounds(self) + (left, top), (right, bottom) = self.bounds + self.size = bottom - top - 4 + self.boxbounds = (left+2, top+2), (left+2+self.size, bottom-2) + self.hilitebounds = self.boxbounds + # + def recalctextpos(self): + m = self.parent.beginmeasuring() + (left, top), (right, bottom) = self.boxbounds + h = right + m.textwidth(' ') + v = top + (self.size - m.lineheight()) / 2 + self.textpos = h, v + # + + +# RadioAppearance displays a round indicator and a left-justified string. +# selected --> a dot appears in the indicator +# disabled --> whole button crossed out +# hilited --> indicator is inverted +# +class RadioAppearance() = CheckAppearance(): + # + def drawpict(self, d): + (left, top), (right, bottom) = self.boxbounds + radius = self.size / 2 + h, v = left + radius, top + radius + d.circle((h, v), radius) + if self.selected: + some = radius/3 + d.paint((h-some, v-some), (h+some, v+some)) + # + + +# NoReactivity ignores mouse events. +# +class NoReactivity(): + def init_reactivity(self): pass + + +# BaseReactivity defines hooks and asks for mouse events, +# but provides only dummy mouse event handlers. +# The trigger methods call the corresponding hooks set by the user. +# Hooks (and triggers) mean the following: +# down_hook called on some mouse-down events +# move_hook called on some mouse-move events +# up_hook called on mouse-up events +# on_hook called for buttons with on/off state, when it goes on +# hook called when a button 'fires' or a radiobutton goes on +# There are usually extra conditions, e.g., hooks are only called +# when the button is enabled, or active, or selected (on). +# +class BaseReactivity(): + # + def init_reactivity(self): + self.down_hook = self.move_hook = self.up_hook = \ + self.on_hook = self.off_hook = \ + self.hook = self.active = 0 + self.parent.need_mouse(self) + # + def mousetest(self, hv): + return _rect.pointinrect(hv, self.bounds) + # + def mouse_down(self, detail): + pass + # + def mouse_move(self, detail): + pass + # + def mouse_up(self, detail): + pass + # + def down_trigger(self): + if self.down_hook: self.down_hook(self) + # + def move_trigger(self): + if self.move_hook: self.move_hook(self) + # + def up_trigger(self): + if self.up_hook: self.up_hook(self) + # + def on_trigger(self): + if self.on_hook: self.on_hook(self) + # + def off_trigger(self): + if self.off_hook: self.off_hook(self) + # + def trigger(self): + if self.hook: self.hook(self) + + +# ToggleReactivity acts like a simple pushbutton. +# It toggles its hilite state on mouse down events. +# +class ToggleReactivity() = BaseReactivity(): + # + def mouse_down(self, detail): + if self.enabled and self.mousetest(detail[_HV]): + self.active = 1 + self.hilite(not self.hilited) + self.down_trigger() + # + def mouse_move(self, detail): + if self.active: + self.move_trigger() + # + def mouse_up(self, detail): + if self.active: + self.up_trigger() + self.active = 0 + # + def down_trigger(self): + if self.hilited: + self.on_trigger() + else: + self.off_trigger() + self.trigger() + # + + +# TriggerReactivity acts like a fancy pushbutton. +# It hilites itself while the mouse is down within its bounds. +# +class TriggerReactivity() = BaseReactivity(): + # + def mouse_down(self, detail): + if self.enabled and self.mousetest(detail[_HV]): + self.active = 1 + self.hilite(1) + self.down_trigger() + # + def mouse_move(self, detail): + if self.active: + self.hilite(self.mousetest(detail[_HV])) + if self.hilited: + self.move_trigger() + # + def mouse_up(self, detail): + if self.active: + self.hilite(self.mousetest(detail[_HV])) + if self.hilited: + self.up_trigger() + self.trigger() + self.active = 0 + self.hilite(0) + # + + +# CheckReactivity handles mouse events like TriggerReactivity, +# It overrides the up_trigger method to flip its selected state. +# +class CheckReactivity() = TriggerReactivity(): + # + def up_trigger(self): + self.select(not self.selected) + if self.selected: + self.on_trigger() + else: + self.off_trigger() + self.trigger() + + +# RadioReactivity turns itself on and the other buttons in its group +# off when its up_trigger method is called. +# +class RadioReactivity() = TriggerReactivity(): + # + def init_reactivity(self): + TriggerReactivity.init_reactivity(self) + self.group = [] + # + def up_trigger(self): + for b in self.group: + if b <> self: + if b.selected: + b.select(0) + b.off_trigger() + self.select(1) + self.on_trigger() + self.trigger() + + +# Auxiliary class for 'define' method. +# Call the initializers in the right order. +# +class Define(): + # + def define(self, parent): + self.parent = parent + parent.addchild(self) + self.init_appearance() + self.init_reactivity() + return self + # + def destroy(self): + self.parent = 0 + # + def definetext(self, (parent, text)): + self = self.define(parent) + self.settext(text) + return self + + +# Subroutine to cross out a rectangle. +# +def _xorcross(d, bounds): + ((left, top), (right, bottom)) = bounds + # This is s bit funny to make it look better + left = left + 2 + right = right - 2 + top = top + 2 + bottom = bottom - 3 + d.xorline(((left, top), (right, bottom))) + d.xorline((left, bottom), (right, top)) + + +# Ready-made button classes. +# +class Label() = NoReactivity(), LabelAppearance(), Define(): pass +class PushButton() = TriggerReactivity(), ButtonAppearance(), Define(): pass +class CheckButton() = CheckReactivity(), CheckAppearance(), Define(): pass +class RadioButton() = RadioReactivity(), RadioAppearance(), Define(): pass +class ToggleButton() = ToggleReactivity(), ButtonAppearance(), Define(): pass diff --git a/lib/CSplit.py b/lib/CSplit.py new file mode 100644 index 0000000..a28b1c8 --- /dev/null +++ b/lib/CSplit.py @@ -0,0 +1,70 @@ +# A CSplit is a Clock-shaped split: the children are grouped in a circle. +# The numbering is a little different from a real clock: the 12 o'clock +# position is called 0, not 12. This is a little easier since Python +# usually counts from zero. (BTW, there needn't be exactly 12 children.) + + +from math import pi, sin, cos +from Split import Split + +class CSplit() = Split(): + # + def minsize(self, m): + # Since things look best if the children are spaced evenly + # along the circle (and often all children have the same + # size anyway) we compute the max child size and assume + # this is each child's size. + width, height = 0, 0 + for child in self.children: + wi, he = child.minsize(m) + width = max(width, wi) + height = max(height, he) + # In approximation, the diameter of the circle we need is + # (diameter of box) * (#children) / pi. + # We approximate pi by 3 (so we slightly overestimate + # our minimal size requirements -- not so bad). + # Because the boxes stick out of the circle we add the + # box size to each dimension. + # Because we really deal with ellipses, do everything + # separate in each dimension. + n = len(self.children) + return width + (width*n + 2)/3, height + (height*n + 2)/3 + # + def getbounds(self): + return self.bounds + # + def setbounds(self, bounds): + self.bounds = bounds + # Place the children. This involves some math. + # Compute center positions for children as if they were + # ellipses with a diameter about 1/N times the + # circumference of the big ellipse. + # (There is some rounding involved to make it look + # reasonable for small and large N alike.) + # XXX One day Python will have automatic conversions... + n = len(self.children) + fn = float(n) + if n = 0: return + (left, top), (right, bottom) = bounds + width, height = right-left, bottom-top + child_width, child_height = width*3/(n+4), height*3/(n+4) + half_width, half_height = \ + float(width-child_width)/2.0, \ + float(height-child_height)/2.0 + center_h, center_v = center = (left+right)/2, (top+bottom)/2 + fch, fcv = float(center_h), float(center_v) + alpha = 2.0 * pi / fn + for i in range(n): + child = self.children[i] + fi = float(i) + fh, fv = \ + fch + half_width*sin(fi*alpha), \ + fcv - half_height*cos(fi*alpha) + left, top = \ + int(fh) - child_width/2, \ + int(fv) - child_height/2 + right, bottom = \ + left + child_width, \ + top + child_height + child.setbounds((left, top), (right, bottom)) + # diff --git a/lib/DEVICE.py b/lib/DEVICE.py new file mode 100644 index 0000000..4f2fadc --- /dev/null +++ b/lib/DEVICE.py @@ -0,0 +1,423 @@ +#/************************************************************************** +# * * +# * Copyright (C) 1984, Silicon Graphics, Inc. * +# * * +# * These coded instructions, statements, and computer programs contain * +# * unpublished proprietary information of Silicon Graphics, Inc., and * +# * are protected by Federal copyright law. They may not be disclosed * +# * to third parties or copied or duplicated in any form, in whole or * +# * in part, without the prior written consent of Silicon Graphics, Inc. * +# * * +# **************************************************************************/ +#/* file with device definitions (see /usr/include/device.h) */ + +NULLDEV = 0 +BUTOFFSET = 1 +VALOFFSET = 256 +TIMOFFSET = 515 +XKBDOFFSET = 143 +INOFFSET = 1024 +OUTOFFSET = 1033 +BUTCOUNT = 190 +VALCOUNT = 27 +TIMCOUNT = 4 +XKBDCOUNT = 28 +INCOUNT = 8 +OUTCOUNT = 8 +# +# +# +# +BUT0 = 1 +BUT1 = 2 +BUT2 = 3 +BUT3 = 4 +BUT4 = 5 +BUT5 = 6 +BUT6 = 7 +BUT7 = 8 +BUT8 = 9 +BUT9 = 10 +BUT10 = 11 +BUT11 = 12 +BUT12 = 13 +BUT13 = 14 +BUT14 = 15 +BUT15 = 16 +BUT16 = 17 +BUT17 = 18 +BUT18 = 19 +BUT19 = 20 +BUT20 = 21 +BUT21 = 22 +BUT22 = 23 +BUT23 = 24 +BUT24 = 25 +BUT25 = 26 +BUT26 = 27 +BUT27 = 28 +BUT28 = 29 +BUT29 = 30 +BUT30 = 31 +BUT31 = 32 +BUT32 = 33 +BUT33 = 34 +BUT34 = 35 +BUT35 = 36 +BUT36 = 37 +BUT37 = 38 +BUT38 = 39 +BUT39 = 40 +BUT40 = 41 +BUT41 = 42 +BUT42 = 43 +BUT43 = 44 +BUT44 = 45 +BUT45 = 46 +BUT46 = 47 +BUT47 = 48 +BUT48 = 49 +BUT49 = 50 +BUT50 = 51 +BUT51 = 52 +BUT52 = 53 +BUT53 = 54 +BUT54 = 55 +BUT55 = 56 +BUT56 = 57 +BUT57 = 58 +BUT58 = 59 +BUT59 = 60 +BUT60 = 61 +BUT61 = 62 +BUT62 = 63 +BUT63 = 64 +BUT64 = 65 +BUT65 = 66 +BUT66 = 67 +BUT67 = 68 +BUT68 = 69 +BUT69 = 70 +BUT70 = 71 +BUT71 = 72 +BUT72 = 73 +BUT73 = 74 +BUT74 = 75 +BUT75 = 76 +BUT76 = 77 +BUT77 = 78 +BUT78 = 79 +BUT79 = 80 +BUT80 = 81 +BUT81 = 82 +BUT82 = 83 +MAXKBDBUT = 83 +BUT100 = 101 +BUT101 = 102 +BUT102 = 103 +BUT110 = 111 +BUT111 = 112 +BUT112 = 113 +BUT113 = 114 +BUT114 = 115 +BUT115 = 116 +BUT116 = 117 +BUT117 = 118 +BUT118 = 119 +BUT119 = 120 +BUT120 = 121 +BUT121 = 122 +BUT122 = 123 +BUT123 = 124 +BUT124 = 125 +BUT125 = 126 +BUT126 = 127 +BUT127 = 128 +BUT128 = 129 +BUT129 = 130 +BUT130 = 131 +BUT131 = 132 +BUT132 = 133 +BUT133 = 134 +BUT134 = 135 +BUT135 = 136 +BUT136 = 137 +BUT137 = 138 +BUT138 = 139 +BUT139 = 140 +BUT140 = 141 +BUT141 = 142 +BUT142 = 143 +BUT143 = 144 +BUT144 = 145 +BUT145 = 146 +BUT146 = 147 +BUT147 = 148 +BUT148 = 149 +BUT149 = 150 +BUT150 = 151 +BUT151 = 152 +BUT152 = 153 +BUT153 = 154 +BUT154 = 155 +BUT155 = 156 +BUT156 = 157 +BUT157 = 158 +BUT158 = 159 +BUT159 = 160 +BUT160 = 161 +BUT161 = 162 +BUT162 = 163 +BUT163 = 164 +BUT164 = 165 +BUT165 = 166 +BUT166 = 167 +BUT167 = 168 +BUT168 = 169 +BUT181 = 182 +BUT182 = 183 +BUT183 = 184 +BUT184 = 185 +BUT185 = 186 +BUT186 = 187 +BUT187 = 188 +BUT188 = 189 +BUT189 = 190 +MOUSE1 = 101 +MOUSE2 = 102 +MOUSE3 = 103 +LEFTMOUSE = 103 +MIDDLEMOUSE = 102 +RIGHTMOUSE = 101 +LPENBUT = 104 +BPAD0 = 105 +BPAD1 = 106 +BPAD2 = 107 +BPAD3 = 108 +LPENVALID = 109 +SWBASE = 111 +SW0 = 111 +SW1 = 112 +SW2 = 113 +SW3 = 114 +SW4 = 115 +SW5 = 116 +SW6 = 117 +SW7 = 118 +SW8 = 119 +SW9 = 120 +SW10 = 121 +SW11 = 122 +SW12 = 123 +SW13 = 124 +SW14 = 125 +SW15 = 126 +SW16 = 127 +SW17 = 128 +SW18 = 129 +SW19 = 130 +SW20 = 131 +SW21 = 132 +SW22 = 133 +SW23 = 134 +SW24 = 135 +SW25 = 136 +SW26 = 137 +SW27 = 138 +SW28 = 139 +SW29 = 140 +SW30 = 141 +SW31 = 142 +SBBASE = 182 +SBPICK = 182 +SBBUT1 = 183 +SBBUT2 = 184 +SBBUT3 = 185 +SBBUT4 = 186 +SBBUT5 = 187 +SBBUT6 = 188 +SBBUT7 = 189 +SBBUT8 = 190 +AKEY = 11 +BKEY = 36 +CKEY = 28 +DKEY = 18 +EKEY = 17 +FKEY = 19 +GKEY = 26 +HKEY = 27 +IKEY = 40 +JKEY = 34 +KKEY = 35 +LKEY = 42 +MKEY = 44 +NKEY = 37 +OKEY = 41 +PKEY = 48 +QKEY = 10 +RKEY = 24 +SKEY = 12 +TKEY = 25 +UKEY = 33 +VKEY = 29 +WKEY = 16 +XKEY = 21 +YKEY = 32 +ZKEY = 20 +ZEROKEY = 46 +ONEKEY = 8 +TWOKEY = 14 +THREEKEY = 15 +FOURKEY = 22 +FIVEKEY = 23 +SIXKEY = 30 +SEVENKEY = 31 +EIGHTKEY = 38 +NINEKEY = 39 +BREAKKEY = 1 +SETUPKEY = 2 +CTRLKEY = 3 +LEFTCTRLKEY = CTRLKEY +CAPSLOCKKEY = 4 +RIGHTSHIFTKEY = 5 +LEFTSHIFTKEY = 6 +NOSCRLKEY = 13 +ESCKEY = 7 +TABKEY = 9 +RETKEY = 51 +SPACEKEY = 83 +LINEFEEDKEY = 60 +BACKSPACEKEY = 61 +DELKEY = 62 +SEMICOLONKEY = 43 +PERIODKEY = 52 +COMMAKEY = 45 +QUOTEKEY = 50 +ACCENTGRAVEKEY = 55 +MINUSKEY = 47 +VIRGULEKEY = 53 +BACKSLASHKEY = 57 +EQUALKEY = 54 +LEFTBRACKETKEY = 49 +RIGHTBRACKETKEY = 56 +LEFTARROWKEY = 73 +DOWNARROWKEY = 74 +RIGHTARROWKEY = 80 +UPARROWKEY = 81 +PAD0 = 59 +PAD1 = 58 +PAD2 = 64 +PAD3 = 65 +PAD4 = 63 +PAD5 = 69 +PAD6 = 70 +PAD7 = 67 +PAD8 = 68 +PAD9 = 75 +PADPF1 = 72 +PADPF2 = 71 +PADPF3 = 79 +PADPF4 = 78 +PADPERIOD = 66 +PADMINUS = 76 +PADCOMMA = 77 +PADENTER = 82 +LEFTALTKEY = 143 +RIGHTALTKEY = 144 +RIGHTCTRLKEY = 145 +F1KEY = 146 +F2KEY = 147 +F3KEY = 148 +F4KEY = 149 +F5KEY = 150 +F6KEY = 151 +F7KEY = 152 +F8KEY = 153 +F9KEY = 154 +F10KEY = 155 +F11KEY = 156 +F12KEY = 157 +PRINTSCREENKEY = 158 +SCROLLLOCKKEY = 159 +PAUSEKEY = 160 +INSERTKEY = 161 +HOMEKEY = 162 +PAGEUPKEY = 163 +ENDKEY = 164 +PAGEDOWNKEY = 165 +NUMLOCKKEY = 166 +PADVIRGULEKEY = 167 +PADASTERKEY = 168 +PADPLUSKEY = 169 +SGIRESERVED = 256 +DIAL0 = 257 +DIAL1 = 258 +DIAL2 = 259 +DIAL3 = 260 +DIAL4 = 261 +DIAL5 = 262 +DIAL6 = 263 +DIAL7 = 264 +DIAL8 = 265 +MOUSEX = 266 +MOUSEY = 267 +LPENX = 268 +LPENY = 269 +BPADX = 270 +BPADY = 271 +CURSORX = 272 +CURSORY = 273 +GHOSTX = 274 +GHOSTY = 275 +SBTX = 276 +SBTY = 277 +SBTZ = 278 +SBRX = 279 +SBRY = 280 +SBRZ = 281 +SBPERIOD = 282 +TIMER0 = 515 +TIMER1 = 516 +TIMER2 = 517 +TIMER3 = 518 +KEYBD = 513 +RAWKEYBD = 514 +VALMARK = 523 +GERROR = 524 +REDRAW = 528 +WMSEND = 529 +WMREPLY = 530 +WMGFCLOSE = 531 +WMTXCLOSE = 532 +MODECHANGE = 533 +INPUTCHANGE = 534 +QFULL = 535 +PIECECHANGE = 536 +WINCLOSE = 537 +QREADERROR = 538 +WINFREEZE = 539 +WINTHAW = 540 +REDRAWICONIC = 541 +WINQUIT = 542 +DEPTHCHANGE = 543 +KEYBDFNAMES = 544 +KEYBDFSTRINGS = 545 +WINSHUT = 546 +INPUT0 = 1024 +INPUT1 = 1025 +INPUT2 = 1026 +INPUT3 = 1027 +INPUT4 = 1028 +INPUT5 = 1029 +INPUT6 = 1030 +INPUT7 = 1032 +OUTPUT0 = 1033 +OUTPUT1 = 1034 +OUTPUT2 = 1035 +OUTPUT3 = 1036 +OUTPUT4 = 1037 +OUTPUT5 = 1038 +OUTPUT6 = 1039 +OUTPUT7 = 1040 +MAXSGIDEVICE = 20000 +MENUBUTTON = RIGHTMOUSE diff --git a/lib/GL.py b/lib/GL.py new file mode 100644 index 0000000..b733e51 --- /dev/null +++ b/lib/GL.py @@ -0,0 +1,365 @@ +# Constants defined in <gl.h> + +#************************************************************************** +#* * +#* Copyright (C) 1984, Silicon Graphics, Inc. * +#* * +#* These coded instructions, statements, and computer programs contain * +#* unpublished proprietary information of Silicon Graphics, Inc., and * +#* are protected by Federal copyright law. They may not be disclosed * +#* to third parties or copied or duplicated in any form, in whole or * +#* in part, without the prior written consent of Silicon Graphics, Inc. * +#* * +#************************************************************************** + +# Graphics Libary constants + +# Booleans +TRUE = 1 +FALSE = 0 + +# maximum X and Y screen coordinates +XMAXSCREEN = 1279 +YMAXSCREEN = 1023 +XMAXMEDIUM = 1023 # max for medium res monitor +YMAXMEDIUM = 767 +XMAX170 = 645 # max for RS-170 +YMAX170 = 484 +XMAXPAL = 779 # max for PAL +YMAXPAL = 574 + +# various hardware/software limits +ATTRIBSTACKDEPTH = 10 +VPSTACKDEPTH = 8 +MATRIXSTACKDEPTH = 32 +NAMESTACKDEPTH = 1025 +STARTTAG = -2 +ENDTAG = -3 +CPOSX_INVALID = -(2*XMAXSCREEN) + +# names for colors in color map loaded by greset +BLACK = 0 +RED = 1 +GREEN = 2 +YELLOW = 3 +BLUE = 4 +MAGENTA = 5 +CYAN = 6 +WHITE = 7 + +# popup colors +PUP_CLEAR = 0 +PUP_COLOR = 1 +PUP_BLACK = 2 +PUP_WHITE = 3 + +# defines for drawmode +NORMALDRAW = 0 +PUPDRAW = 1 +OVERDRAW = 2 +UNDERDRAW = 3 +CURSORDRAW = 4 + +# defines for defpattern +PATTERN_16 = 16 +PATTERN_32 = 32 +PATTERN_64 = 64 + +PATTERN_16_SIZE = 16 +PATTERN_32_SIZE = 64 +PATTERN_64_SIZE = 256 + +# defines for readsource +SRC_AUTO = 0 +SRC_FRONT = 1 +SRC_BACK = 2 +SRC_ZBUFFER = 3 +SRC_PUP = 4 +SRC_OVER = 5 +SRC_UNDER = 6 +SRC_FRAMEGRABBER = 7 + +# defines for blendfunction +BF_ZERO = 0 +BF_ONE = 1 +BF_DC = 2 +BF_SC = 2 +BF_MDC = 3 +BF_MSC = 3 +BF_SA = 4 +BF_MSA = 5 +BF_DA = 6 +BF_MDA = 7 + +# defines for zfunction +ZF_NEVER = 0 +ZF_LESS = 1 +ZF_EQUAL = 2 +ZF_LEQUAL = 3 +ZF_GREATER = 4 +ZF_NOTEQUAL = 5 +ZF_GEQUAL = 6 +ZF_ALWAYS = 7 + +# defines for zsource +ZSRC_DEPTH = 0 +ZSRC_COLOR = 1 + +# defines for pntsmooth +SMP_OFF = 0 +SMP_ON = 1 + +# defines for linesmooth +SML_OFF = 0 +SML_ON = 1 + +# defines for setpup +PUP_NONE = 0 +PUP_GREY = 1 + +# defines for glcompat +GLC_OLDPOLYGON = 0 +GLC_ZRANGEMAP = 1 + +# defines for curstype +C16X1 = 0 +C16X2 = 1 +C32X1 = 2 +C32X2 = 3 +CCROSS = 4 + +# defines for shademodel +FLAT = 0 +GOURAUD = 1 + +# defines for logicop +### LO_ZERO = 0x0 +### LO_AND = 0x1 +### LO_ANDR = 0x2 +### LO_SRC = 0x3 +### LO_ANDI = 0x4 +### LO_DST = 0x5 +### LO_XOR = 0x6 +### LO_OR = 0x7 +### LO_NOR = 0x8 +### LO_XNOR = 0x9 +### LO_NDST = 0xa +### LO_ORR = 0xb +### LO_NSRC = 0xc +### LO_ORI = 0xd +### LO_NAND = 0xe +### LO_ONE = 0xf + + +# +# START defines for getgdesc +# + +GD_XPMAX = 0 +GD_YPMAX = 1 +GD_XMMAX = 2 +GD_YMMAX = 3 +GD_ZMIN = 4 +GD_ZMAX = 5 +GD_BITS_NORM_SNG_RED = 6 +GD_BITS_NORM_SNG_GREEN = 7 +GD_BITS_NORM_SNG_BLUE = 8 +GD_BITS_NORM_DBL_RED = 9 +GD_BITS_NORM_DBL_GREEN = 10 +GD_BITS_NORM_DBL_BLUE = 11 +GD_BITS_NORM_SNG_CMODE = 12 +GD_BITS_NORM_DBL_CMODE = 13 +GD_BITS_NORM_SNG_MMAP = 14 +GD_BITS_NORM_DBL_MMAP = 15 +GD_BITS_NORM_ZBUFFER = 16 +GD_BITS_OVER_SNG_CMODE = 17 +GD_BITS_UNDR_SNG_CMODE = 18 +GD_BITS_PUP_SNG_CMODE = 19 +GD_BITS_NORM_SNG_ALPHA = 21 +GD_BITS_NORM_DBL_ALPHA = 22 +GD_BITS_CURSOR = 23 +GD_OVERUNDER_SHARED = 24 +GD_BLEND = 25 +GD_CIFRACT = 26 +GD_CROSSHAIR_CINDEX = 27 +GD_DITHER = 28 +GD_LINESMOOTH_CMODE = 30 +GD_LINESMOOTH_RGB = 31 +GD_LOGICOP = 33 +GD_NSCRNS = 35 +GD_NURBS_ORDER = 36 +GD_NBLINKS = 37 +GD_NVERTEX_POLY = 39 +GD_PATSIZE_64 = 40 +GD_PNTSMOOTH_CMODE = 41 +GD_PNTSMOOTH_RGB = 42 +GD_PUP_TO_OVERUNDER = 43 +GD_READSOURCE = 44 +GD_READSOURCE_ZBUFFER = 48 +GD_STEREO = 50 +GD_SUBPIXEL_LINE = 51 +GD_SUBPIXEL_PNT = 52 +GD_SUBPIXEL_POLY = 53 +GD_TRIMCURVE_ORDER = 54 +GD_WSYS = 55 +GD_ZDRAW_GEOM = 57 +GD_ZDRAW_PIXELS = 58 +GD_SCRNTYPE = 61 +GD_TEXTPORT = 62 +GD_NMMAPS = 63 +GD_FRAMEGRABBER = 64 +GD_TIMERHZ = 66 +GD_DBBOX = 67 +GD_AFUNCTION = 68 +GD_ALPHA_OVERUNDER = 69 +GD_BITS_ACBUF = 70 +GD_BITS_ACBUF_HW = 71 +GD_BITS_STENCIL = 72 +GD_CLIPPLANES = 73 +GD_FOGVERTEX = 74 +GD_LIGHTING_TWOSIDE = 76 +GD_POLYMODE = 77 +GD_POLYSMOOTH = 78 +GD_SCRBOX = 79 +GD_TEXTURE = 80 + +# return value for inquiries when there is no limit +GD_NOLIMIT = 2 + +# return values for GD_WSYS +GD_WSYS_NONE = 0 +GD_WSYS_4S = 1 + +# return values for GD_SCRNTYPE +GD_SCRNTYPE_WM = 0 +GD_SCRNTYPE_NOWM = 1 + +# +# END defines for getgdesc +# + + +# +# START NURBS interface definitions +# + +# NURBS Rendering Properties +N_PIXEL_TOLERANCE = 1 +N_CULLING = 2 +N_DISPLAY = 3 +N_ERRORCHECKING = 4 +N_SUBDIVISIONS = 5 +N_S_STEPS = 6 +N_T_STEPS = 7 +N_TILES = 8 + +N_SHADED = 1.0 + +# --------------------------------------------------------------------------- +# FLAGS FOR NURBS SURFACES AND CURVES +# +# Bit: 9876 5432 1 0 +# |tttt|nnnn|f|r| : r - 1 bit = 1 if rational coordinate exists +# : f - 1 bit = 1 if rational coordinate is before rest +# : = 0 if rational coordinate is after rest +# : nnnn - 4 bits for number of coordinates +# : tttt - 4 bits for type of data (color, position, etc.) +# +# NURBS data type +# N_T_ST 0 parametric space data +# N_T_XYZ 1 model space data +# +# rational or non-rational data and position in memory +# N_NONRATIONAL 0 non-rational data +# N_RATAFTER 1 rational data with rat coord after rest +# N_RATBEFORE 3 rational data with rat coord before rest +# +# N_MKFLAG(a,b,c) ((a<<6) | (b<<2) | c) +# +# --------------------------------------------------------------------------- +# +N_ST = 0x8 # N_MKFLAG( N_T_ST, 2, N_NONRATIONAL ) +N_STW = 0xd # N_MKFLAG( N_T_ST, 3, N_RATAFTER ) +N_WST = 0xf # N_MKFLAG( N_T_ST, 3, N_RATBEFORE ) +N_XYZ = 0x4c # N_MKFLAG( N_T_XYZ, 3, N_NONRATIONAL ) +N_XYZW = 0x51 # N_MKFLAG( N_T_XYZ, 4, N_RATAFTER ) +N_WXYZ = 0x53 # N_MKFLAG( N_T_XYZ, 4, N_RATBEFORE ) + +# +# END NURBS interface definitions +# + + +# +# START lighting model defines +# + +LMNULL = 0.0 + +# MATRIX modes +MSINGLE = 0 +MPROJECTION = 1 +MVIEWING = 2 + +# LIGHT constants +MAXLIGHTS = 8 +MAXRESTRICTIONS = 4 + +# MATERIAL properties +DEFMATERIAL = 0 +EMISSION = 1 +AMBIENT = 2 +DIFFUSE = 3 +SPECULAR = 4 +SHININESS = 5 +COLORINDEXES = 6 +ALPHA = 7 + +# LIGHT properties +DEFLIGHT = 100 +LCOLOR = 101 +POSITION = 102 + +# LIGHTINGMODEL properties +DEFLMODEL = 200 +LOCALVIEWER = 201 +ATTENUATION = 202 + +# TARGET constants +MATERIAL = 1000 +LIGHT0 = 1100 +LIGHT1 = 1101 +LIGHT2 = 1102 +LIGHT3 = 1103 +LIGHT4 = 1104 +LIGHT5 = 1105 +LIGHT6 = 1106 +LIGHT7 = 1107 +LMODEL = 1200 + +# lmcolor modes +LMC_COLOR = 0 +LMC_EMISSION = 1 +LMC_AMBIENT = 2 +LMC_DIFFUSE = 3 +LMC_SPECULAR = 4 +LMC_AD = 5 +LMC_NULL = 6 + +# +# END lighting model defines +# + + +# +# START distributed graphics library defines +# + +DGLSINK = 0 # sink connection +DGLLOCAL = 1 # local connection +DGLTSOCKET = 2 # tcp socket connection +DGL4DDN = 3 # 4DDN (DECnet) + +# +# END distributed graphics library defines +# diff --git a/lib/HVSplit.py b/lib/HVSplit.py new file mode 100644 index 0000000..d52af8e --- /dev/null +++ b/lib/HVSplit.py @@ -0,0 +1,56 @@ +# HVSplit contains generic code for HSplit and VSplit. +# HSplit and VSplit are specializations to either dimension. + +# XXX This does not yet stretch/shrink children if there is too much +# XXX or too little space in the split dimension. +# XXX (NB There is no interface to ask children for stretch preferences.) + +from Split import Split + +class HVSplit() = Split(): + # + def create(self, (parent, hv)): + # hv is 0 or 1 for HSplit or VSplit + self = Split.create(self, parent) + self.hv = hv + return self + # + def minsize(self, m): + hv, vh = self.hv, 1 - self.hv + size = [0, 0] + for c in self.children: + csize = c.minsize(m) + if csize[vh] > size[vh]: size[vh] = csize[vh] + size[hv] = size[hv] + csize[hv] + return size[0], size[1] + # + def getbounds(self): + return self.bounds + # + def setbounds(self, bounds): + self.bounds = bounds + hv, vh = self.hv, 1 - self.hv + mf = self.parent.beginmeasuring + size = self.minsize(mf()) + # XXX not yet used! Later for stretching + maxsize_hv = bounds[1][hv] - bounds[0][hv] + origin = [self.bounds[0][0], self.bounds[0][1]] + for c in self.children: + size = c.minsize(mf()) + corner = [0, 0] + corner[vh] = bounds[1][vh] + corner[hv] = origin[hv] + size[hv] + c.setbounds((origin[0], origin[1]), \ + (corner[0], corner[1])) + origin[hv] = corner[hv] + # XXX stretch + # XXX too-small + # + +class HSplit() = HVSplit(): + def create(self, parent): + return HVSplit.create(self, (parent, 0)) + +class VSplit() = HVSplit(): + def create(self, parent): + return HVSplit.create(self, (parent, 1)) diff --git a/lib/Histogram.py b/lib/Histogram.py new file mode 100644 index 0000000..3f6da76 --- /dev/null +++ b/lib/Histogram.py @@ -0,0 +1,36 @@ +# Module 'Histogram' + +from Buttons import * + +# A Histogram displays a histogram of numeric data. +# +class HistogramAppearance() = LabelAppearance(), Define(): + # + def define(self, parent): + Define.define(self, (parent, '')) + self.ydata = [] + self.scale = (0, 100) + return self + # + def setdata(self, (ydata, scale)): + self.ydata = ydata + self.scale = scale # (min, max) + self.parent.change(self.bounds) + # + def drawpict(self, d): + (left, top), (right, bottom) = self.bounds + min, max = self.scale + size = max-min + width, height = right-left, bottom-top + ydata = self.ydata + npoints = len(ydata) + v1 = top + height # constant + h1 = left # changed in loop + for i in range(npoints): + h0 = h1 + v0 = top + height - (ydata[i]-min)*height/size + h1 = left + (i+1) * width/npoints + d.paint((h0, v0), (h1, v1)) + # + +class Histogram() = NoReactivity(), HistogramAppearance(): pass diff --git a/lib/Sliders.py b/lib/Sliders.py new file mode 100644 index 0000000..e44b466 --- /dev/null +++ b/lib/Sliders.py @@ -0,0 +1,175 @@ +# Module 'Sliders' + + +import stdwin +from stdwinevents import * +import rect +from Buttons import * +from HVSplit import HSplit + + +# Field indices in event detail +# +_HV = 0 +_CLICKS = 1 +_BUTTON = 2 +_MASK = 3 + + +# DragSlider is the simplest possible slider. +# It looks like a button but dragging the mouse left or right +# changes the controlled value. +# It does not support any of the triggers or hooks defined by Buttons, +# but defines its own setval_trigger and setval_hook. +# +class DragSliderReactivity() = BaseReactivity(): + # + def mouse_down(self, detail): + h, v = hv = detail[_HV] + if self.enabled and self.mousetest(hv): + self.anchor = h + self.oldval = self.val + self.active = 1 + # + def mouse_move(self, detail): + if self.active: + h, v = detail[_HV] + self.setval(self.oldval + (h - self.anchor)) + # + def mouse_up(self, detail): + if self.active: + h, v = detail[_HV] + self.setval(self.oldval + (h - self.anchor)) + self.active = 0 + # + +class DragSliderAppearance() = ButtonAppearance(): + # + # INVARIANTS maintained by the setval method: + # + # self.min <= self.val <= self.max + # self.text = self.pretext + `self.val` + self.postext + # + # (Notice that unlike Python ranges, the end point belongs + # to the range.) + # + def init_appearance(self): + ButtonAppearance.init_appearance(self) + self.min = 0 + self.val = 0 + self.max = 100 + self.hook = 0 + self.pretext = self.postext = '' + self.recalctext() + # + # The 'get*' and 'set*' methods belong to the generic slider interface + # + def getval(self): return self.val + # + def sethook(self, hook): + self.hook = hook + # + def setminvalmax(self, (min, val, max)): + self.min = min + self.max = max + self.setval(val) + # + def settexts(self, (pretext, postext)): + self.pretext = pretext + self.postext = postext + self.recalctext() + # + def setval(self, val): + val = min(self.max, max(self.min, val)) + if val <> self.val: + self.val = val + self.recalctext() + self.trigger() + # + def trigger(self): + if self.hook: + self.hook(self) + # + def recalctext(self): + self.settext(self.pretext + `self.val` + self.postext) + # + +class DragSlider() = DragSliderReactivity(), DragSliderAppearance(), Define(): + def definetext(self, (parent, text)): + raise RuntimeError, 'DragSlider.definetext() not supported' + + +# Auxiliary class for PushButton incorporated in ComplexSlider +# +class _StepButton() = PushButton(): + def define(self, parent): + self = PushButton.define(self, parent) + self.step = 0 + return self + def setstep(self, step): + self.step = step + def definetextstep(self, (parent, text, step)): + self = self.definetext(parent, text) + self.setstep(step) + return self + def init_reactivity(self): + PushButton.init_reactivity(self) + self.parent.need_timer(self) + def step_trigger(self): + self.parent.setval(self.parent.getval() + self.step) + def down_trigger(self): + self.step_trigger() + self.parent.settimer(5) + def timer(self): + if self.hilited: + self.step_trigger() + if self.active: + self.parent.settimer(1) + + +# A complex slider is an HSplit initialized to three buttons: +# one to step down, a dragslider, and one to step up. +# +class ComplexSlider() = HSplit(): + # + # Override Slider define() method + # + def define(self, parent): + self = self.create(parent) # HSplit + # + self.downbutton = _StepButton().definetextstep(self, '-', -1) + self.dragbutton = DragSlider().define(self) + self.upbutton = _StepButton().definetextstep(self, '+', 1) + # + return self + # + # Override HSplit methods + # + def minsize(self, m): + w1, h1 = self.downbutton.minsize(m) + w2, h2 = self.dragbutton.minsize(m) + w3, h3 = self.upbutton.minsize(m) + height = max(h1, h2, h3) + w1 = max(w1, height) + w3 = max(w3, height) + return w1+w2+w3, height + # + def setbounds(self, bounds): + (left, top), (right, bottom) = self.bounds = bounds + size = bottom - top + self.downbutton.setbounds((left, top), (left+size, bottom)) + self.dragbutton.setbounds((left+size, top), \ + (right-size, bottom)) + self.upbutton.setbounds((right-size, top), (right, bottom)) + # + # Pass other Slider methods on to dragbutton + # + def getval(self): return self.dragbutton.getval() + def sethook(self, hook): self.dragbutton.sethook(hook) + def setminvalmax(self, args): self.dragbutton.setminvalmax(args) + def settexts(self, args): self.dragbutton.settexts(args) + def setval(self, val): self.dragbutton.setval(val) + def enable(self, flag): + self.downbutton.enable(flag) + self.dragbutton.enable(flag) + self.upbutton.enable(flag) diff --git a/lib/Soundogram.py b/lib/Soundogram.py new file mode 100644 index 0000000..38dd5ef --- /dev/null +++ b/lib/Soundogram.py @@ -0,0 +1,36 @@ +# Module 'Soundogram' + +import audio +from Histogram import Histogram + +class Soundogram() = Histogram(): + # + def define(self, (win, chunk)): + width, height = corner = win.getwinsize() + bounds = (0, 0), corner + self.chunk = chunk + self.step = (len(chunk)-1)/(width/2+1) + 1 + ydata = _make_ydata(chunk, self.step) + return Histogram.define(self, (win, bounds, ydata, (0, 128))) + # + def setchunk(self, chunk): + self.chunk = chunk + self.recompute() + # + def recompute(self): + (left, top), (right, bottom) = self.bounds + width = right - left + self.step = (len(chunk)-1)/width + 1 + ydata = _make_ydata(chunk, self.step) + self.setdata(ydata, (0, 128)) + # + + +def _make_ydata(chunk, step): + ydata = [] + for i in range(0, len(chunk), step): + piece = audio.chr2num(chunk[i:i+step]) + mi, ma = min(piece), max(piece) + y = max(abs(mi), abs(ma)) + ydata.append(y) + return ydata diff --git a/lib/Split.py b/lib/Split.py new file mode 100644 index 0000000..8c0a8dc --- /dev/null +++ b/lib/Split.py @@ -0,0 +1,116 @@ +# Generic Split implementation. +# Use as a base class for other splits. +# Derived classes should at least implement the methods that call +# unimpl() below: minsize(), getbounds() and setbounds(). + +Error = 'Split.Error' # Exception + +import rect +from util import remove + +class Split(): + # + # Calls from creator + # NB derived classes may add parameters to create() + # + def create(self, parent): + parent.addchild(self) + self.parent = parent + self.children = [] + self.mouse_interest = [] + self.timer_interest = [] + self.mouse_focus = 0 + return self + # + # Downcalls from parent to child + # + def destroy(self): + self.parent = None + for child in self.children: + child.destroy() + del self.children[:] + del self.mouse_interest[:] + del self.timer_interest[:] + self.mouse_focus = None + # + def minsize(self, m): return unimpl() + def getbounds(self): return unimpl() + def setbounds(self, bounds): unimpl() + # + def draw(self, d_detail): + # (Could avoid calls to children outside the area) + for child in self.children: + child.draw(d_detail) + # + # Downcalls only made after certain upcalls + # + def mouse_down(self, detail): + if self.mouse_focus: + self.mouse_focus.mouse_down(detail) + p = detail[0] + for child in self.mouse_interest: + if rect.pointinrect(p, child.getbounds()): + self.mouse_focus = child + child.mouse_down(detail) + def mouse_move(self, detail): + if self.mouse_focus: + self.mouse_focus.mouse_move(detail) + def mouse_up(self, detail): + if self.mouse_focus: + self.mouse_focus.mouse_up(detail) + self.mouse_focus = 0 + # + def timer(self): + for child in self.timer_interest: + child.timer() + # + # Upcalls from child to parent + # + def addchild(self, child): + if child in self.children: + raise Error, 'addchild: child already inlist' + self.children.append(child) + def delchild(self, child): + if child not in self.children: + raise Error, 'delchild: child not in list' + remove(child, self.children) + if child in self.mouse_interest: + remove(child, self.mouse_interest) + if child in self.timer_interest: + remove(child, self.timer_interest) + if child = self.mouse_focus: + self.mouse_focus = 0 + # + def need_mouse(self, child): + if child not in self.mouse_interest: + self.mouse_interest.append(child) + self.parent.need_mouse(self) + def no_mouse(self, child): + if child in self.mouse_interest: + remove(child, self.mouse_interest) + if not self.mouse_interest: + self.parent.no_mouse(self) + # + def need_timer(self, child): + if child not in self.timer_interest: + self.timer_interest.append(child) + self.parent.need_timer(self) + def no_timer(self, child): + if child in self.timer_interest: + remove(child, self.timer_interest) + if not self.timer_interest: + self.parent.no_timer(self) + # + # The rest are transparent: + # + def begindrawing(self): + return self.parent.begindrawing() + def beginmeasuring(self): + return self.parent.beginmeasuring() + # + def change(self, area): + self.parent.change(area) + def scroll(self, area_vector): + self.parent.scroll(area_vector) + def settimer(self, itimer): + self.parent.settimer(itimer) diff --git a/lib/StripChart.py b/lib/StripChart.py new file mode 100644 index 0000000..fc707cb --- /dev/null +++ b/lib/StripChart.py @@ -0,0 +1,68 @@ +# Module 'StripChart' + +import rect +from Buttons import LabelAppearance, NoReactivity + +# A StripChart doesn't really look like a label but it needs a base class. +# LabelAppearance allows it to be disabled and hilited. + +class StripChart() = LabelAppearance(), NoReactivity(): + # + def define(self, (parent, scale)): + self.parent = parent + parent.addchild(self) + self.init_appearance() + self.init_reactivity() + self.ydata = [] + self.scale = scale + self.resetbounds() + return self + # + def setbounds(self, bounds): + LabelAppearance.setbounds(self, bounds) + self.resetbounds() + # + def resetbounds(self): + (left, top), (right, bottom) = self.bounds + self.width = right-left + self.height = bottom-top + excess = len(self.ydata) - self.width + if excess > 0: + del self.ydata[:excess] + elif excess < 0: + while len(self.ydata) < self.width: + self.ydata.insert(0, 0) + # + def append(self, y): + self.ydata.append(y) + excess = len(self.ydata) - self.width + if excess > 0: + del self.ydata[:excess] + if self.bounds <> rect.empty: + self.parent.scroll(self.bounds, (-excess, 0)) + if self.bounds <> rect.empty: + (left, top), (right, bottom) = self.bounds + i = len(self.ydata) + area = (left+i-1, top), (left+i, bottom) + self.draw(self.parent.begindrawing(), area) + # + def draw(self, (d, area)): + area = rect.intersect(area, self.bounds) + if area = rect.empty: + print 'mt' + return + d.cliprect(area) + d.erase(self.bounds) + (a_left, a_top), (a_right, a_bottom) = area + (left, top), (right, bottom) = self.bounds + height = bottom - top + i1 = a_left - left + i2 = a_right - left + for i in range(max(0, i1), min(len(self.ydata), i2)): + split = bottom-self.ydata[i]*height/self.scale + d.paint((left+i, split), (left+i+1, bottom)) + if not self.enabled: + self.flipenable(d) + if self.hilited: + self.fliphilite(d) + d.noclip() diff --git a/lib/Tcl.py b/lib/Tcl.py new file mode 100644 index 0000000..9d45e37 --- /dev/null +++ b/lib/Tcl.py @@ -0,0 +1,421 @@ +# An emulator for John Ousterhout's 'Tcl' language in Python (wow!). +# Currently only the most basic commands are implemented. +# +# Design choices: +# +# - Names used for functions are not exactly those used by C Tcl. +# In Python, names without 'Tcl_' prefix are acceptable because +# names are less global than in C (and often they are prefixed +# with a module name anyway). Parameter conventions also differ. +# +# - The Tcl Interpreter type is implemented using a Python class. +# Almost all functions with an Interpreter as first parameter are +# methods of this class. +# Applications can create derived classes to add additional commands +# or to override specific internal functions. +# +# - Tcl errors are mapped to Python exceptions. +# (I bet Ousterhout would have done the same in a language with +# a proper exception mechanism). +# +# - Tcl expressions are evaluated by Python's built-in function eval(). +# This makes Python Tcl scripts incompatible with C Tcl scripts, +# but is the only sensible solution for a quick-and-dirty version. +# It also makes an escape to Python possible. +# +# - The Backslash function interprets \<newline>, since it +# can return a string instead of a character. + + +from TclUtil import * + + +# Exceptions used to signify 'break' and 'continue' + +TclBreak = 'TclBreak' +TclContinue = 'TclContinue' +TclReturn = 'TclReturn' + + +class CmdBuf(): + # + def Create(buffer): + buffer.string = '' + return buffer + # + def Assemble(buffer, str): + buffer.string = buffer.string + str + if buffer.string[-1:] = '\n': + i, end = 0, len(buffer.string) + try: + while i < end: + list, i = FindNextCommand( \ + buffer.string, i, end, 0) + except TclMatchingError: + return '' + except TclSyntaxError: + pass # Let Eval() return the error + ret = buffer.string + buffer.string = '' + return ret + else: + return '' + + +class _Frame(): + def Create(frame): + frame.locals = {} + return frame + +class _Proc(): + # + def Create(proc, (interp, args, body)): + proc.interp = interp + proc.args = SplitList(args) # Do this once here + proc.body = body + return proc + # + def Call(proc, argv): + if len(argv) <> len(proc.args)+1: + raise TclRuntimeError, \ + 'wrong # args to proc "' + \ + argv[0] + '"' + # XXX No defaults or variable length 'args' yet + frame = _Frame().Create() + for i in range(len(proc.args)): + frame.locals[proc.args[i]] = argv[i+1] + proc.interp.stack.append(frame) + try: + value = proc.interp.Eval(proc.body) + except TclReturn, value: + pass + del proc.interp.stack[-1:] + return value + + +import regexp +_expand_prog = regexp.compile('([^[$\\]+|\n)*') +del regexp + +class Interpreter(): + # + def Create(interp): + interp.globals = {} + interp.commands = {} + interp.stack = [] + interp.commands['break'] = interp.BreakCmd + interp.commands['concat'] = interp.ConcatCmd + interp.commands['continue'] = interp.ContinueCmd + interp.commands['echo'] = interp.EchoCmd + interp.commands['eval'] = interp.EvalCmd + interp.commands['expr'] = interp.ExprCmd + interp.commands['for'] = interp.ForCmd + interp.commands['glob'] = interp.GlobCmd + interp.commands['global'] = interp.GlobalCmd + interp.commands['if'] = interp.IfCmd + interp.commands['index'] = interp.IndexCmd + interp.commands['list'] = interp.ListCmd + interp.commands['proc'] = interp.ProcCmd + interp.commands['rename'] = interp.RenameCmd + interp.commands['return'] = interp.ReturnCmd + interp.commands['set'] = interp.SetCmd + return interp + # + def Delete(interp): + # + # Only break circular references here; + # most things will be garbage-collected. + # + for name in interp.commands.keys(): + del interp.commands[name] + # + def CreateCommand(interp, (name, proc)): + interp.commands[name] = proc + # + def DeleteCommand(interp, (name)): + del interp.commands[name] + # + # Local variables are maintained on the stack. + # A local variable with value "None" is a dummy + # meaning that the corresponding global variable + # should be used. + # + def GetVar(interp, varName): + dict = interp.globals + if interp.stack: + d = interp.stack[-1:][0].locals + if d.has_key(varName) and d[varName] = None: + pass + else: + dict = d + if not dict.has_key(varName): + raise TclRuntimeError, \ + 'Variable "' + varName + '" not found' + return dict[varName] + # + def SetVar(interp, (varName, newValue)): + dict = interp.globals + if interp.stack: + d = interp.stack[-1:][0].locals + if d.has_key(varName) and d[varName] = None: + pass + else: + dict = d + dict[varName] = newValue + # + def Expand(interp, (str, i, end)): + if end <= i: return '' + if str[i] = '{' and str[end-1] = '}': + return str[i+1:end-1] + if str[i] = '"' and str[end-1] = '"': + i, end = i+1, end-1 + result = '' + while i < end: + c = str[i] + if c = '\\': + x, i = Backslash(str, i, end) + result = result + x + elif c = '[': + j = BalanceBrackets(str, i, end) + x = interp.EvalBasic(str, i+1, j-1, 1) + result = result + x + i = j + elif c = '$': + i = i+1 + j = FindVarName(str, i, end) + name = str[i:j] + i = j + if not name: + result = result + '$' + else: + if name[:1] = '{' and name[-1:] = '}': + name = name[1:-1] + result = result + interp.GetVar(name) + else: + j = _expand_prog.exec(str, i) + j = min(j, end) + result = result + str[i:j] + i = j + return result + # + def EvalBasic(interp, (str, i, end, bracketed)): + result = '' + while i < end: + indexargv, i = FindNextCommand( \ + str, i, end, bracketed) + if indexargv: + argv = [] + for x, y in indexargv: + arg = interp.Expand(str, x, y) + argv.append(arg) + name = argv[0] + if not interp.commands.has_key(name): + raise TclRuntimeError, \ + 'Command "' + name + \ + '" not found' + result = interp.commands[name](argv) + return result + # + def Eval(interp, str): + return interp.EvalBasic(str, 0, len(str), 0) + # + def ExprBasic(interp, (str, begin, end)): + expr = interp.Expand(str, begin, end) + i = SkipSpaces(expr, 0, len(expr)) + expr = expr[i:] + try: + return eval(expr, {}) + except (NameError, TypeError, RuntimeError, EOFError), msg: + import sys + raise TclRuntimeError, sys.exc_type + ': ' + msg + # + def Expr(interp, str): + return interp.ExprBasic(str, 0, len(str)) + # + # The rest are command implementations + # + def BreakCmd(interp, argv): + if len(argv) <> 1: + raise TclRuntimeError, 'usage: break' + raise TclBreak + # + def ConcatCmd(interp, argv): + if len(argv) < 2: + raise TclRuntimeError, 'usage: concat arg ...' + return Concat(argv[1:]) + # + def ContinueCmd(interp, argv): + if len(argv) <> 1: + raise TclRuntimeError, 'usage: continue' + raise TclContinue + # + def EchoCmd(interp, argv): + for arg in argv[1:]: print arg, + print + return '' + # + def EvalCmd(interp, argv): + if len(argv) < 2: + raise TclRuntimeError, 'usage: eval arg [arg ...]' + str = Concat(argv[1:]) + return interp.Eval(str) + # + def ExprCmd(interp, argv): + if len(argv) <> 2: + raise TclRuntimeError, 'usage: expr expression' + expr = argv[1] + result = interp.Expr(expr) + if type(result) <> type(''): result = `result` + return result + # + def ForCmd(interp, argv): + if len(argv) <> 5: + raise TclRuntimeError, \ + 'usage: for start test next body' + x = interp.Eval(argv[1]) + while interp.Expr(argv[2]): + try: + x = interp.Eval(argv[4]) + except TclBreak: + break + except TclContinue: + pass + x = interp.Eval(argv[3]) + return '' + # + def GlobCmd(interp, argv): + import macglob + if len(argv) < 2: + raise TclRuntimeError, 'usage: glob pattern ...' + list = [] + for pat in argv[1:]: + list = list + macglob.glob(pat) + if not list: + raise TclRuntimeError, 'no match for glob pattern(s)' + return BuildList(list) + # + def GlobalCmd(interp, argv): + if len(argv) < 2: + raise TclRuntimeError, 'usage: global varname ...' + if not interp.stack: + raise TclRuntimeError, 'global used outside proc' + dict = interp.stack[-1:][0].locals + for name in argv[1:]: + dict[name] = None + return '' + # + def IfCmd(interp, argv): + argv = argv[:] + if len(argv) > 2 and argv[2] = 'then': del argv[2] + if len(argv) > 3 and argv[3] = 'else': del argv[3] + if not 3 <= len(argv) <= 4: + raise TclRuntimeError, \ + 'usage: if test [then] trueBody [else] falseBody' + if interp.Expr(argv[1]): + return interp.Eval(argv[2]) + if len(argv) > 3: + return interp.Eval(argv[3]) + return '' + # + def IndexCmd(interp, argv): + if len(argv) <> 3: + raise TclRuntimeError, 'usage: index value index' + import string + try: + index = string.atoi(argv[2]) + if index < 0: raise string.atoi_error + except string.atoi_error: + raise TclRuntimeError, 'bad index: ' + argv[2] + list = SplitList(argv[1]) + if index >= len(list): return '' + return list[index] + # + def ListCmd(interp, argv): + if len(argv) < 2: + raise TclRuntimeError, 'usage: list arg ...' + return BuildList(argv[1:]) + # + def ProcCmd(interp, argv): + if len(argv) <> 4: + raise TclRuntimeError, 'usage: proc name args body' + x = _Proc().Create(interp, argv[2], argv[3]) + interp.CreateCommand(argv[1], x.Call) + return '' + # + def RenameCmd(interp, argv): + if len(argv) <> 3: + raise TclRuntimeError, 'usage: rename oldName newName' + oldName, newName = argv[1], argv[2] + if not interp.commands.has_key(oldName): + raise TclRuntimeError, \ + 'command "' + oldName + '" not found' + if newName: interp.commands[newName] = interp.commands[oldName] + del interp.commands[oldName] + return '' + # + def ReturnCmd(interp, argv): + if not 1 <= len(argv) <= 2: + raise TclRuntimeError, 'usage: return [arg]' + if len(argv) = 1: raise TclReturn, '' + raise TclReturn, argv[1] + # + def SetCmd(interp, argv): + n = len(argv) + if not 2 <= n <= 3: + raise TclRuntimeError, 'usage: set varname [newvalue]' + if n = 2: return interp.GetVar(argv[1]) + interp.SetVar(argv[1], argv[2]) + return '' + + +# The rest are just demos: + +def MainLoop(interp): + buffer = CmdBuf().Create() + if not interp.globals.has_key('ps1'): interp.globals['ps1'] = '% ' + if not interp.globals.has_key('ps2'): interp.globals['ps2'] = '' + psname = 'ps1' + while 1: + try: + line = raw_input(interp.globals[psname]) + except (EOFError, KeyboardInterrupt): + print + break + line = buffer.Assemble(line + '\n') + if not line: + psname = 'ps2' + else: + psname = 'ps1' + try: + x = interp.Eval(line) + if x <> '': print 'Result:', `x` + except (TclRuntimeError, TclSyntaxError, \ + TclMatchingError), msg: + print 'Error:', msg + except (TclBreak, TclContinue): + print 'Error: break or continue outside loop' + except TclReturn, value: + # Return outside proc returns to main loop + if value: print value + + +the_interpreter = Interpreter().Create() + +def main(): + MainLoop(the_interpreter) + + +# XXX To do: +# for proc: "args" and default arguments +# More commands: +# case +# uplevel +# info +# string +# list operations +# error, catch +# print +# scan, format +# source +# history? +# others? diff --git a/lib/TclShell.py b/lib/TclShell.py new file mode 100644 index 0000000..78d8dc4 --- /dev/null +++ b/lib/TclShell.py @@ -0,0 +1,255 @@ +# Tcl-based shell (for the Macintosh) + +import TclUtil +import Tcl +from Tcl import Interpreter, TclRuntimeError +import mac +import macpath +from macpath import isfile, isdir, exists + +UsageError = TclRuntimeError + +class ShellInterpreter() = Interpreter(): + # + def ResetVariables(interp): + interp.globals['ps1'] = '$ ' + interp.globals['ps2'] = '> ' + interp.globals['home'] = mac.getcwd() + # + def DefineCommands(interp): + interp.commands['cd'] = interp.CdCmd + interp.commands['grep'] = interp.GrepCmd + interp.commands['ls'] = interp.LsCmd + interp.commands['mkdir'] = interp.MkdirCmd + interp.commands['mv'] = interp.MvCmd + interp.commands['pg'] = interp.PgCmd + interp.commands['pwd'] = interp.PwdCmd + interp.commands['rm'] = interp.RmCmd + interp.commands['rmdir'] = interp.RmdirCmd + interp.commands['sync'] = interp.SyncCmd + # + def Reset(interp): + interp.ResetVariables() + interp.DefineCommands() + # + def Create(interp): + interp = Interpreter.Create(interp) # initialize base class + interp.Reset() + return interp + # + # Command-implementing functions + # + def CdCmd(interp, argv): + if len(argv) > 2: + raise UsageError, 'usage: cd [dirname]' + if len(argv) = 2: + chdirto(argv[1]) + else: + chdirto(interp.globals['home']) + return '' + # + def GrepCmd(interp, argv): + if len(argv) < 3: + raise UsageError, 'usage: grep regexp file ...' + import regexp + try: + prog = regexp.compile(argv[1]) + except regexp.error, msg: + raise TclRuntimeError, \ + ('grep', argv[1], ': bad regexp :', msg) + for file in argv[2:]: + grepfile(prog, file) + return '' + # + def LsCmd(interp, argv): + if len(argv) < 2: + lsdir(':') + else: + for dirname in argv[1:]: + lsdir(dirname) + return '' + # + def MkdirCmd(interp, argv): + if len(argv) < 2: + raise UsageError, 'usage: mkdir name ...' + for name in argv[1:]: + makedir(name) + return '' + # + def MvCmd(interp, argv): + if len(argv) <> 3: + raise UsageError, 'usage: mv src dst' + src, dst = argv[1], argv[2] + if not exists(src): + raise TclRuntimeError, \ + ('mv', src, dst, ': source does not exist') + if exists(dst): + raise TclRuntimeError, \ + ('mv', src, dst, ': destination already exists') + try: + mac.rename(src, dst) + except mac.error, msg: + raise TclRuntimeError, \ + (src, dst, ': rename failed :', msg) + return '' + # + def PgCmd(interp, argv): + if len(argv) < 2: + raise UsageError, 'usage: page file ...' + for name in argv[1:]: + pagefile(name) + return '' + # + def PwdCmd(interp, argv): + if len(argv) > 1: + raise UsageError, 'usage: pwd' + else: + return mac.getcwd() + # + def RmCmd(interp, argv): + if len(argv) < 2: + raise UsageError, 'usage: rm file ...' + for name in argv[1:]: + remove(name) + return '' + # + def RmdirCmd(interp, argv): + if len(argv) < 2: + raise UsageError, 'usage: rmdir dir ...' + for name in argv[1:]: + rmdir(name) + return '' + # + def SyncCmd(interp, argv): + if len(argv) > 1: + raise UsageError, 'usage: sync' + try: + mac.sync() + except mac.error, msg: + raise TclRuntimeError, ('sync failed :', msg) + # + +def chdirto(dirname): + try: + mac.chdir(dirname) + except mac.error, msg: + raise TclRuntimeError, (dirname, ': chdir failed :', msg) + +def grepfile(prog, file): + try: + fp = open(file, 'r') + except RuntimeError, msg: + raise TclRuntimeError, (file, ': open failed :', msg) + lineno = 0 + while 1: + line = fp.readline() + if not line: break + lineno = lineno+1 + if prog.exec(line): + print file+'('+`lineno`+'):', line, + +def lsdir(dirname): + if not isdir(dirname): + print dirname, ': no such directory' + return + names = mac.listdir(dirname) + lsfiles(names, dirname) + +def lsfiles(names, dirname): + names = names[:] # Make a copy so we can modify it + for i in range(len(names)): + name = names[i] + if isdir(macpath.cat(dirname, name)): + names[i] = ':' + name + ':' + columnize(names) + +def makedir(name): + if exists(name): + print name, ': already exists' + return + try: + mac.mkdir(name, 0777) + except mac.error, msg: + raise TclRuntimeError, (name, ': mkdir failed :', msg) + +def pagefile(name): + import string + if not isfile(name): + print name, ': no such file' + return + LINES = 24 - 1 + # For THINK C 3.0, make the path absolute: + # if not macpath.isabs(name): + # name = macpath.cat(mac.getcwd(), name) + try: + fp = open(name, 'r') + except RuntimeError, msg: + raise TclRuntimeError, (name, ': open failed :', msg) + line = fp.readline() + while line: + for i in range(LINES): + print line, + line = fp.readline() + if not line: break + if line: + try: + more = raw_input('[more]') + except (EOFError, KeyboardInterrupt): + print + break + if string.strip(more)[:1] in ('q', 'Q'): + break + +def remove(name): + if not isfile(name): + print name, ': no such file' + return + try: + mac.unlink(name) + except mac.error, msg: + raise TclRuntimeError, (name, ': unlink failed :', msg) + +def rmdir(name): + if not isdir(name): + raise TclRuntimeError, (name, ': no such directory') + try: + mac.rmdir(name) + except mac.error, msg: + raise TclRuntimeError, (name, ': rmdir failed :', msg) + +def printlist(list): + for word in list: + print word, + +def columnize(list): + import string + COLUMNS = 80-1 + n = len(list) + colwidth = maxwidth(list) + ncols = (COLUMNS + 1) / (colwidth + 1) + if ncols < 1: ncols = 1 + nrows = (n + ncols - 1) / ncols + for irow in range(nrows): + line = '' + for icol in range(ncols): + i = irow + nrows*icol + if 0 <= i < n: + word = list[i] + if i+nrows < n: + word = string.ljust(word, colwidth) + if icol > 0: + word = ' ' + word + line = line + word + print line + +def maxwidth(list): + width = 0 + for word in list: + if len(word) > width: + width = len(word) + return width + +the_interpreter = ShellInterpreter().Create() + +def main(): + Tcl.MainLoop(the_interpreter) diff --git a/lib/TclUtil.py b/lib/TclUtil.py new file mode 100644 index 0000000..0990530 --- /dev/null +++ b/lib/TclUtil.py @@ -0,0 +1,377 @@ +# Utilities used by 'Tcl' emulator. + + +# Many functions in this file parse specific constructs from strings. +# In order to limit the number of slice operations (the strings can +# be very large), they always receive indices into the string that +# indicate the slice of the string that should be considered. +# The return value is in general another index, pointing to the first +# character in the string beyond the recognized construct. +# Errors are reported as exceptions (TclSyntaxError, TclMatchingError). +# A few functions have multiple return values. + + +# For efficiency, the Tcl "tokenizing" routines used pre-compiled +# regular expressions. This is less readable but should be much faster +# than scanning the string a character at a time. +# +# The global variables +# containing the compiled regexp's are named _foo_prog where foo is +# an indication of the function that uses them. +# +# The patterns always +# have the form <something>* so they always match at the start of the +# search buffer---maybe with the empty string. This makes it possible +# to use the expression "_foo_prog.exec(str, i)[0][1]" to find the first +# character beyond the matched string. Note that this may be beyond the +# end variable -- where this matters, "min(i, end)" is used. + +# Constructs that cannot +# be recognized by a finite automaton (like matching braces) are scanned +# by a hybrid technique where the regular expression excludes the +# braces. +# +# Many regular expressions contain an expression that matches +# a Tcl backslash sequence as a subpart: +# \\\\C?M?(.|\n) +# +# This is a bit hard to +# read because the backslash contained in it must be doubled twice: +# once to get past Python's backslash mechanism, once to get past that +# of regular expressions. It uses (.|\n) to match absolutely +# *every character*, becase the MULTILINE regular expression package does +# not accept '\n' as a match for '.'. +# +# There is also a simplification in the pattern for backslashes: +# *any* single character following a backslash is escaped, +# so hex and octal +# excapes are not scanned fully. The forms \Cx, \Mx and \CMx are +# scanned correctly, as these may hide a special character. +# (This does not invalidate the recognition of strings, although the +# match is effectuated in a different way than by the Backslash function.) + +import regexp + + +# Exceptions raised for various error conditions. + +TclAssertError = 'Tcl assert error' +TclSyntaxError = 'Tcl syntax error' +TclRuntimeError = 'Tcl runtime error' +TclMatchingError = 'Tcl matching error' + + +# Find a variable name. +# A variable name is either a (possiblly empty) sequence of letters, +# digits and underscores, or anything enclosed in matching braces. +# Return the index past the end of the name. + +_varname_prog = regexp.compile('[a-zA-Z0-9_]*') + +def FindVarName(str, i, end): + if i < end and str[i] = '{': return BalanceBraces(str, i, end) + i = _varname_prog.exec(str, i)[0][1] + return min(i, end) + + +# Split a list into its elements. +# Return a list of elements (strings). + +def SplitList(str): + i, end = 0, len(str) + list = [] + while 1: + i = SkipSpaces(str, i, end) + if i >= end: break + j = i + i = FindNextElement(str, i, end) + if str[j] = '{' and str[i-1] = '}': + element = str[j+1:i-1] + else: + element = Collapse(str[j:i]) + list.append(element) + return list + + +# Find the next element from a list. + +_element_prog = regexp.compile('([^ \t\n\\]+|\\\\C?M?(.|\n))*') + +def FindNextElement(str, i, end): + if i < end and str[i] = '{': + i = BalanceBraces(str, i, end) + if i < end and str[i] not in ' \t\n': + raise TclSyntaxError, 'Garbage after } in list' + return i + i = _element_prog.exec(str, i)[0][1] + return min(i, end) + + +# Copy a string, expanding all backslash sequences. + +_collapse_prog = regexp.compile('(\n|[^\\]+)*') + +def Collapse(str): + if '\\' not in str: return str + i, end = 0, len(str) + result = '' + while i < end: + j = _collapse_prog.exec(str, i)[0][1] + j = min(j, end) + result = result + str[i:j] + if j >= end: break + c = str[j] + if c <> '\\': raise TclAssertError, 'collapse error' + x, i = Backslash(str, j, end) + result = result + x + return result + + +# Find the next full command. +# Return a list of begin, end indices of words in the string, +# and an index pointing just after the terminating newline or +# semicolon. +# Initial spaces are skipped. +# If the command begins with '#', it is considered empty and +# characters until '\n' are skipped. + +_eol_prog = regexp.compile('[^\n]*') + +def FindNextCommand(str, i, end, bracketed): + i = SkipSpaces(str, i, end) + if i >= end: return [], end + if str[i] = '#': + i = _eol_prog.exec(str, i) + i = min(i, end) + if i < end and str[i] = '\n': i = i+1 + return [], i + if bracketed: terminators = [';'] + else: terminators = [';', '\n'] + list = [] + while i < end: + j = FindNextWord(str, i, end) + word = str[i:j] + if word in terminators: + i = j + break + if word <> '\n': list.append(i, j) + i = SkipSpaces(str, j, end) + return list, i + + +# Find the next word of a command. +# Semicolon and newline terminate words but also count as a word +# themselves. +# The start index must point to the start of the word. + +_word_prog = regexp.compile('([^ \t\n;[\\]+|\\\\C?M?(.|\n))*') + +def FindNextWord(str, i, end): + if i >= end: return end + if str[i] in '{"': + if str[i] = '{': i = BalanceBraces(str, i, end) + else: i = BalanceQuotes(str, i, end) + if i >= end or str[i] in ' \t\n;': return min(i, end) + raise TclSyntaxError, 'Garbage after } or "' + begin = i + while i < end: + i = _word_prog.exec(str, i)[0][1] + if i >= end: + i = end + break + c = str[i] + if c in ' \t': break + if c in ';\n': + if i = begin: i = i+1 + break + if c = '[': i = BalanceBrackets(str, i, end) + else: raise TclAssertError, 'word error' + return i + + +# Parse balanced brackets from str[i:end]. +# str[i] must be '['. +# Returns end such that str[i:end] ends with ']' +# and contains balanced braces and brackets. + +_brackets_prog = regexp.compile('([^][{\\]+|\n|\\\\C?M?(.|\n))*') + +def BalanceBrackets(str, i, end): + if i >= end or str[i] <> '[': + raise TclAssertError, 'BalanceBrackets' + nesting = 0 + while i < end: + i = _brackets_prog.exec(str, i)[0][1] + if i >= end: break + c = str[i] + if c = '{': i = BalanceBraces(str, i, end) + else: + i = i+1 + if c = '[': nesting = nesting + 1 + elif c = ']': + nesting = nesting - 1 + if nesting = 0: return i + else: raise TclAssertError, 'brackets error' + raise TclMatchingError, 'Unmatched bracket ([)' + + +# Parse balanced braces from str[i:end]. +# str[i] must be '{'. +# Returns end such that str[i:end] ends with '}' +# and contains balanced braces. + +_braces_prog = regexp.compile('([^{}\\]+|\n|\\\\C?M?(.|\n))*') + +def BalanceBraces(str, i, end): + if i >= end or str[i] <> '{': + raise TclAssertError, 'BalanceBraces' + nesting = 0 + while i < end: + i = _braces_prog.exec(str, i)[0][1] + if i >= end: break + c = str[i] + i = i+1 + if c = '{': nesting = nesting + 1 + elif c = '}': + nesting = nesting - 1 + if nesting = 0: return i + else: raise TclAssertError, 'braces error' + raise TclMatchingError, 'Unmatched brace ({)' + + +# Parse double quotes from str[i:end]. +# str[i] must be '"'. +# Returns end such that str[i:end] ends with an unescaped '"'. + +_quotes_prog = regexp.compile('([^"\\]+|\n|\\\\C?M?(.|\n))*') + +def BalanceQuotes(str, i, end): + if i >= end or str[i] <> '"': + raise TclAssertError, 'BalanceQuotes' + i = _quotes_prog.exec(str, i+1)[0][1] + if i < end and str[i] = '"': return i+1 + raise TclMatchingError, 'Unmatched quote (")' + + +# Static data used by Backslash() + +_bstab = {} +_bstab['n'] = '\n' +_bstab['r'] = '\r' +_bstab['t'] = '\t' +_bstab['b'] = '\b' +_bstab['e'] = '\033' +_bstab['\n'] = '' +for c in ' {}[]$";\\': _bstab[c] = c +del c + +# Backslash interpretation. +# First character must be a backslash. +# Return a pair (<replacement string>, <end of sequence>). +# Unrecognized or incomplete backslash sequences are not errors; +# this takes only the backslash itself off the string. + +def Backslash(str, i, end): + if i >= end or str[i] <> '\\': + raise TclAssertError, 'Backslash' + i = i+1 + if i = end: return '\\', i + c = str[i] + i = i+1 + if _bstab.has_key(c): return _bstab[c], i + if c = 'C': + if i = end: return '\\', i-1 + c = str[i] + i = i+1 + if c = 'M': + if i = end: return '\\', i-2 + c = str[i] + i = i+1 + x = ord(c) % 040 + 0200 + else: + x = ord(c) % 040 + return chr(x), i + elif c = 'M': + if i = end: return '\\', i-1 + c = str[i] + i = i+1 + x = ord(c) + if x < 0200: x = x + 0200 + return chr(x), i + elif c and c in '0123456789': + x = ord(c) - ord('0') + end = min(end, i+2) + while i < end: + c = str[i] + if c not in '0123456789': break + i = i+1 + x = x*8 + ord(c) - ord('0') + return ord(x), i + else: + # Not something that we recognize + return '\\', i-1 + + +# Skip over spaces and tabs (but not newlines). + +_spaces_prog = regexp.compile('[ \t]*') + +def SkipSpaces(str, i, end): + i = _spaces_prog.exec(str, i)[0][1] + return min(i, end) + + +# Concatenate the elements of a list with intervening spaces. + +def Concat(argv): + result = '' + sep = '' + for arg in argv: + result = result + (sep + arg) + sep = ' ' + return result + + +# Concatenate list elements, adding braces etc. to make them parseable +# again with SplitList. + +def BuildList(argv): + result = '' + sep = '' + for arg in argv: + arg = AddBraces(arg) + result = result + (sep + arg) + sep = ' ' + return result + + +# Add braces around a string if necessary to make it parseable by SplitList. + +def AddBraces(str): + # Special case for empty string + if str = '': return '{}' + # See if it contains balanced braces + res = '{' + str + '}' + if TryNextElement(res): + # See if it would survive unquoted + # XXX should escape [] and $ as well??? + if TryNextElement(str) and Collapse(str) = str: return str + # No -- return with added braces + return res + # Unbalanced braces. Add backslashes before suspect characters + res = '' + for c in str: + if c in '$\\[]{} ;': c = '\\' + c + elif c = '\n': c = '\\n' + elif c = '\t': c = '\\t' + res = res + c + return res + + +def TryNextElement(str): + end = len(str) + try: + i = FindNextElement(str, 0, end) + return i = end + except (TclSyntaxError, TclMatchingError): + return 0 diff --git a/lib/TestCSplit.py b/lib/TestCSplit.py new file mode 100644 index 0000000..b638f81 --- /dev/null +++ b/lib/TestCSplit.py @@ -0,0 +1,26 @@ +# TestCSplit + +import stdwin +from stdwinevents import WE_CLOSE +from WindowParent import WindowParent +from Buttons import PushButton + +def main(n): + from CSplit import CSplit + + the_window = WindowParent().create('TestCSplit', (0, 0)) + the_csplit = CSplit().create(the_window) + + for i in range(n): + the_child = PushButton().define(the_csplit) + the_child.settext(`(i+n-1)%n+1`) + + the_window.realize() + + while 1: + the_event = stdwin.getevent() + if the_event[0] = WE_CLOSE: break + the_window.dispatch(the_event) + the_window.destroy() + +main(12) diff --git a/lib/TransParent.py b/lib/TransParent.py new file mode 100644 index 0000000..a07b4c4 --- /dev/null +++ b/lib/TransParent.py @@ -0,0 +1,96 @@ +# A class that sits transparently between a parent and one child. +# First create the parent, then this thing, then the child. +# Use this as a base class for objects that are almost transparent. +# Don't use as a base class for parents with multiple children. + +Error = 'TransParent.Error' # Exception + +class ManageOneChild(): + # + # Upcalls shared with other single-child parents + # + def addchild(self, child): + if self.child: + raise Error, 'addchild: one child only' + if not child: + raise Error, 'addchild: bad child' + self.child = child + # + def delchild(self, child): + if not self.child: + raise Error, 'delchild: no child' + if child <> self.child: + raise Error, 'delchild: not my child' + self.child = 0 + +class TransParent() = ManageOneChild(): + # + # Calls from creator + # NB derived classes may add parameters to create() + # + def create(self, parent): + parent.addchild(self) + self.parent = parent + self.child = 0 # No child yet + # + # Downcalls from parent to child + # + def destroy(self): + del self.parent + if self.child: self.child.destroy() + del self.child + # + def minsize(self, m): + if not self.child: + return 0, 0 + else: + return self.child.minsize(m) + def getbounds(self, bounds): + if not self.child: + raise Error, 'getbounds w/o child' + else: + return self.child.getbounds() + def setbounds(self, bounds): + if not self.child: + raise Error, 'setbounds w/o child' + else: + self.child.setbounds(bounds) + def draw(self, args): + if self.child: + self.child.draw(args) + # + # Downcalls only made after certain upcalls + # + def mouse_down(self, detail): + if self.child: self.child.mouse_down(detail) + def mouse_move(self, detail): + if self.child: self.child.mouse_move(detail) + def mouse_up(self, detail): + if self.child: self.child.mouse_up(detail) + # + def timer(self): + if self.child: self.child.timer() + # + # Upcalls from child to parent + # + def need_mouse(self, child): + self.parent.need_mouse(self) + def no_mouse(self, child): + self.parent.no_mouse(self) + # + def need_timer(self, child): + self.parent.need_timer(self) + def no_timer(self, child): + self.parent.no_timer(self) + # + def begindrawing(self): + return self.parent.begindrawing() + def beginmeasuring(self): + return self.parent.beginmeasuring() + # + def change(self, area): + self.parent.change(area) + def scroll(self, args): + self.parent.scroll(args) + def settimer(self, itimer): + self.parent.settimer(itimer) diff --git a/lib/VUMeter.py b/lib/VUMeter.py new file mode 100644 index 0000000..c862452 --- /dev/null +++ b/lib/VUMeter.py @@ -0,0 +1,47 @@ +# Module 'VUMeter' + +import audio +from StripChart import StripChart + +K = 1024 +Rates = [0, 32*K, 16*K, 8*K] + +class VUMeter() = StripChart(): + # + # Override define() and timer() methods + # + def define(self, parent): + self = StripChart.define(self, (parent, 128)) + self.parent.need_timer(self) + self.sampling = 0 + self.rate = 3 + self.enable(0) + return self + # + def timer(self): + if self.sampling: + chunk = audio.wait_recording() + self.sampling = 0 + nums = audio.chr2num(chunk) + ampl = max(abs(min(nums)), abs(max(nums))) + self.append(ampl) + if self.enabled and not self.sampling: + audio.setrate(self.rate) + size = Rates[self.rate]/10 + size = size/48*48 + audio.start_recording(size) + self.sampling = 1 + if self.sampling: + self.parent.settimer(1) + # + # New methods: start() and stop() + # + def stop(self): + if self.sampling: + chunk = audio.stop_recording() + self.sampling = 0 + self.enable(0) + # + def start(self): + self.enable(1) + self.timer() diff --git a/lib/WindowParent.py b/lib/WindowParent.py new file mode 100644 index 0000000..1e18930 --- /dev/null +++ b/lib/WindowParent.py @@ -0,0 +1,101 @@ +# A 'WindowParent' is the only module that uses real stdwin functionality. +# It is the root of the tree. +# It should have exactly one child when realized. + +import stdwin +from stdwinevents import * + +from TransParent import ManageOneChild + +Error = 'WindowParent.Error' # Exception + +class WindowParent() = ManageOneChild(): + # + def create(self, (title, size)): + self.title = title + self.size = size # (width, height) + self._reset() + return self + # + def _reset(self): + self.child = 0 + self.win = 0 + self.itimer = 0 + self.do_mouse = 0 + self.do_timer = 0 + # + def destroy(self): + if self.child: self.child.destroy() + self._reset() + # + def need_mouse(self, child): self.do_mouse = 1 + def no_mouse(self, child): self.do_mouse = 0 + # + def need_timer(self, child): self.do_timer = 1 + def no_timer(self, child): self.do_timer = 0 + # + def realize(self): + if self.win: + raise Error, 'realize(): called twice' + if not self.child: + raise Error, 'realize(): no child' + size = self.child.minsize(self.beginmeasuring()) + self.size = max(self.size[0], size[0]), \ + max(self.size[1], size[1]) + #stdwin.setdefwinsize(self.size) + # XXX Compensate stdwin bug: + stdwin.setdefwinsize(self.size[0]+4, self.size[1]+2) + self.win = stdwin.open(self.title) + if self.itimer: + self.win.settimer(self.itimer) + bounds = (0, 0), self.win.getwinsize() + self.child.setbounds(bounds) + # + def beginmeasuring(self): + # Return something with which a child can measure text + if self.win: + return self.win.begindrawing() + else: + return stdwin + # + def begindrawing(self): + if self.win: + return self.win.begindrawing() + else: + raise Error, 'begindrawing(): not realized yet' + # + def change(self, area): + if self.win: + self.win.change(area) + # + def scroll(self, args): + if self.win: + self.win.scroll(args) + # + def settimer(self, itimer): + if self.win: + self.win.settimer(itimer) + else: + self.itimer = itimer + # + # Only call dispatch if we have a child + # + def dispatch(self, (type, win, detail)): + if win <> self.win: + return + elif type = WE_DRAW: + d = self.win.begindrawing() + self.child.draw(d, detail) + elif type = WE_MOUSE_DOWN: + if self.do_mouse: self.child.mouse_down(detail) + elif type = WE_MOUSE_MOVE: + if self.do_mouse: self.child.mouse_move(detail) + elif type = WE_MOUSE_UP: + if self.do_mouse: self.child.mouse_up(detail) + elif type = WE_TIMER: + if self.do_timer: self.child.timer() + elif type = WE_SIZE: + self.win.change((0, 0), (10000, 10000)) # XXX + bounds = (0, 0), self.win.getwinsize() + self.child.setbounds(bounds) + # diff --git a/lib/adv.py b/lib/adv.py new file mode 100644 index 0000000..f32f91b --- /dev/null +++ b/lib/adv.py @@ -0,0 +1,366 @@ +#! /ufs/guido/bin/sgi/python + +# Module 'adv' -- text-oriented adventure game. + + +# Name a constant that may once appear in the language... + +def return_nil(): return +nil = return_nil() + + +# Copy of string.split() (to avoid loading all of string.py) + +whitespace = ' \t\n' +def split(s): + res = [] + i, n = 0, len(s) + while i < n: + while i < n and s[i] in whitespace: i = i+1 + if i = n: break + j = i + while j < n and s[j] not in whitespace: j = j+1 + res.append(s[i:j]) + i = j + return res + + +# Constants to name directions + +N = 'north' +S = 'south' +W = 'west' +E = 'east' +U = 'up' +D = 'down' +NW = 'nw' +NE = 'ne' +SW = 'sw' +SE = 'se' + + +# Constants to name other commands + +INVENT = 'invent' +LOOK = 'look' +BACK = 'back' +HELP = 'help' +GET = 'get' +PUT = 'put' + + +# Aliases recognized by the parser + +alias = {} +alias['n'] = N +alias['s'] = S +alias['e'] = E +alias['w'] = W +alias['u'] = U +alias['d'] = D +alias['i'] = INVENT +alias['l'] = LOOK +alias['b'] = BACK +alias['take'] = GET +alias['drop'] = PUT + + +# Normalize a command, in place: truncate words to 6 chars, and expand aliases. + +def normalize(cmd): + for i in range(len(cmd)): + word = cmd[i][:6] + if alias.has_key(word): + word = alias[word] + cmd[i] = word + + +# The Object class describes objects that the player can carry around. + +class Object(): + def init(this, name): + this.name = name + return this + def describe(this): + print 'A', this.name + '.' + def get(this, (player, room)): + del room.objects[this.name] + player.objects[this.name] = this + def put(this, (player, room)): + del player.objects[this.name] + room.objects[this.name] = this + + +# The Player class embodies first person control. + +class Player(): + # Set initial state, except current room. + def init(self, initial_room): + self.blind = 0 + self.here = initial_room + self.prev = nil + self.objects = {} + return self + # Read and execute commands forever. + def play(self): + self.here.casualdescribe() + while 1: + self.move() + # Read and execute one command. + def move(self): + next = self.here.parser() + if next and next <> self.here: + self.prev = self.here + self.here = next + if not self.blind: + self.here.casualdescribe() + # Print inventory. + def inventory(self): + if not self.objects: + print 'You aren\'t carrying anything.' + return + print 'You are carrying:' + for key in self.objects.keys(): + self.objects[key].describe() + # Go back to previous room. + def back(self): + if self.prev: return self.prev + print 'You can\'t go back now.' + # Get an object from the room. + def get(self, name): + if self.here.objects.has_key(name): + self.here.objects[name].get(self, self.here) + else: + print 'I see no', name, 'here.' + # Put an object in the room. + def put(self, name): + if self.objects.has_key(name): + self.objects[name].put(self, self.here) + else: + print 'You have no', name, 'with you.' + + +# The Room class describes a generic room. +# Rooms with special properties are defined by derived classes +# that override certain operations. + +class Room(): + # Initialize a featureless room. + def init(here, name): + here.seen = 0 + here.name = name + here.exits = {} + here.objects = {} + here.description = [] + return here + # Add an object to the room. Used during initialization. + def add(here, obj): + here.objects[obj.name] = obj + # Print a casual description. + def casualdescribe(here): + if here.seen: + print here.name + '.' + here.listobjects() + return + here.seen = 1 + here.describe() + # Print a full description, including all exits and objects seen. + def describe(here): + if not here.description: + print here.name + '.' + here.listexits() + else: + for line in here.description: print line + here.listobjects() + # List exits. + def listexits(here): + there = here.exits.keys() + if there: + if len(there) = 1: + print 'There is an exit leading', + else: + print 'There are exits leading', + for name in there[:-2]: + print name + ',', + print there[len(there)-2], 'and', + print there[len(there)-1] + '.' + # List objects + def listobjects(here): + if here.objects: + print 'I see:' + for key in here.objects.keys(): + here.objects[key].describe() + # Default parser. Returns next room (possibly the same) or nil. + def parser(here): + cmd = here.getcmd(here.prompt()) + return here.decide(cmd) + # Return default prompt string. + def prompt(here): return '> ' + # Default input routine. Returns a non-empty list of words. + def getcmd(here, prompt): + # Loop until non-empty command gotten + # EOFError and KeyboardInterrupt may be caught elsewhere + while 1: + line = raw_input(prompt) + cmd = split(line) + if cmd: + normalize(cmd) + return cmd + # Default decision routine. Override for room-specific commands. + def decide(here, cmd): + key, args = cmd[0], cmd[1:] + if not args: + if key = N: return here.north() + if key = S: return here.south() + if key = E: return here.east() + if key = W: return here.west() + if key = U: return here.up() + if key = D: return here.down() + if key = NW: return here.nw() + if key = NE: return here.ne() + if key = SW: return here.sw() + if key = SE: return here.se() + if key = LOOK: return here.look() + if key = INVENT: return here.inventory() + if key = BACK: return here.back() + if here.objects.has_key(key): + print 'What do you want to do with the', key+'?' + else: + print 'Huh?' + return + if key = GET: + for arg in args: + player.get(arg) + return + if key = PUT: + for arg in args: + player.put(arg) + # Standard commands. + def look(here): + here.describe() + def inventory(here): + player.inventory() + def back(here): + return player.back() + # Standard exits. + def north(here): return here.take_exit(N) + def south(here): return here.take_exit(S) + def west(here): return here.take_exit(W) + def east(here): return here.take_exit(E) + def up(here): return here.take_exit(U) + def down(here): return here.take_exit(D) + def nw(here): return here.take_exit(NW) + def ne(here): return here.take_exit(NE) + def sw(here): return here.take_exit(SW) + def se(here): return here.take_exit(SE) + # Subroutine for standard exits. + def take_exit(here, key): + if here.exits.has_key(key): + return here.exits[key] + print 'You cannot go in that direction.' + return here + + +# Create the objects we know about. +# Object names begin with 'o_'. + +o_lamp = Object().init('lamp') +o_python = Object().init('python') + + +# Subroutine to connect two rooms. + +def connect(rm1, rm2, dir1, dir2): + if dir1: + rm1.exits[dir1] = rm2 + if dir2: + rm2.exits[dir2] = rm1 + + +# Create the rooms and connect them together. +# Room names begin with 'r_'. + +r_front = Room().init('Front of building') +r_initial = r_front +r_front.description = [ \ + 'You are standing in front of a large, desolate building.', \ + 'Huge neon letters spell "CWI". The "I" is blinking.', \ + 'There are entrances north and west from where you are standing.', \ + ] + +r_entrance = Room().init('Entrance') +r_entrance.description = [ \ + 'You are standing in a small entrance room.', \ + 'On the east side is a window to a reception room.', \ + 'South is a door leading outside the building.', \ + 'North is a large hall.' \ + ] + +r_hall_s = Room().init('South of hall') +r_hall_s.description = [ \ + 'You are standing at the south side of a very large hall.', \ + 'There are doors leading west, southwest, south and southeast,', \ + 'and a corridor leads east.', \ + 'The hall continues to the north.' \ + ] + +r_hall_n = Room().init('North of hall') +r_hall_n.description = [ \ + 'You are stanting at the north side of a very large hall.', \ + 'There are corridors leading west, northwest, northeast,', \ + 'an elevator door north, and a door leading outside east.', \ + 'There are stairs leading up, and the hall continues to the south.' \ + ] + +r_reception = Room().init('Reception') + +r_mail = Room().init('Mail room') + +connect(r_front, r_entrance, N, S) +connect(r_entrance, r_hall_s, N, SW) +connect(r_hall_s, r_hall_n, N, S) +connect(r_hall_s, r_reception, S, N) +connect(r_hall_s, r_mail, SE, N) +connect(r_reception, r_mail, E, W) + +r_aud_front = Room().init('Front of Auditorium') +r_aud_back = Room().init('Back of Auditorium') +r_aud_tech = Room().init('Technician\'s room in Auditorium') +r_aud_proj = Room().init('Projection room in Auditorium') + +connect(r_aud_front, r_hall_s, E, W) +connect(r_aud_front, r_aud_back, S, N) +connect(r_aud_back, r_aud_proj, SE, N) +connect(r_aud_front, r_aud_tech, W, E) + +r_floor1 = Room().init('First floor') +r_floor2 = Room().init('Second floor') +r_floor3 = Room().init('Third floor') + +connect(r_hall_n, r_floor1, U, D) +connect(r_floor1, r_floor2, U, D) +connect(r_floor2, r_floor3, U, D) + + +# Drop objects here and there + +r_aud_proj.add(o_python) +r_reception.add(o_lamp) + +# Create an uninitialized player object. +# It is initialized by main(), but must be created here (as global) +# since some Room methods reference it. (Though maybe they shouldn't?) + +player = Player() + + +# Play the game from the beginning. + +def main(): + x = player.init(r_initial) + try: + player.play() + except (EOFError, KeyboardInterrupt): + pass + +main() diff --git a/lib/anywin.py b/lib/anywin.py new file mode 100644 index 0000000..6de3605 --- /dev/null +++ b/lib/anywin.py @@ -0,0 +1,14 @@ +# Module 'anywin' +# Open a file or directory in a window + +import dirwin +import filewin +import path + +def open(name): + print 'opening', name, '...' + if path.isdir(name): + w = dirwin.open(name) + else: + w = filewin.open(name) + return w diff --git a/lib/auds.py b/lib/auds.py new file mode 100644 index 0000000..53db6aa --- /dev/null +++ b/lib/auds.py @@ -0,0 +1,106 @@ +import audio + +RATE = 8192 + +# Initialize the audio stuff +audio.setrate(3) +audio.setoutgain(100) # for speaker + +play = audio.write + +def samp(n): + savegain = audio.getoutgain() + try: + audio.setoutgain(0) + x = raw_input('Hit Enter to sample ' + `n` + ' seconds: ') + return audio.read(n*RATE) + finally: + audio.setoutgain(savegain) + +def echo(s, delay, gain): + return s[:delay] + audio.add(s[delay:], audio.amplify(s, gain, gain)) + +def save(s, file): + f = open(file, 'w') + f.write(s) + +def load(file): + return loadfp(open(file, 'r')) + +def loadfp(fp): + s = '' + while 1: + buf = fp.read(16*1024) + if not buf: break + s = s + buf + return s + +def unbias(s): + if not s: return s + a = audio.chr2num(s) + sum = 0 + for i in a: sum = sum + i + bias = (sum + len(a)/2) / len(a) + print 'Bias value:', bias + if bias: + for i in range(len(a)): + a[i] = a[i] - bias + s = audio.num2chr(a) + return s + +# Stretch by a/b. +# Think of this as converting the sampling rate from a samples/sec +# to b samples/sec. Or, if the input is a bytes long, the output +# will be b bytes long. +# +def stretch(s, a, b): + y = audio.chr2num(s) + m = len(y) + out = [] + n = m * b / a + # i, j will walk through y and out (step 1) + # ib, ja are i*b, j*a and are kept as close together as possible + i, ib = 0, 0 + j, ja = 0, 0 + for j in range(n): + ja = ja+a + while ib < ja: + i = i+1 + ib = ib+b + if i >= m: + break + if ib = ja: + out.append(y[i]) + else: + out.append((y[i]*(ja-(ib-b)) + y[i-1]*(ib-ja)) / b) + return audio.num2chr(out) + +def sinus(freq): # return a 1-second sine wave + from math import sin, pi + factor = 2.0*pi*float(freq)/float(RATE) + list = range(RATE) + for i in list: + list[i] = int(sin(float(i) * factor) * 127.0) + return audio.num2chr(list) + +def softclip(s): + if '\177' not in s and '\200' not in s: + return s + num = audio.chr2num(s) + extremes = (-128, 127) + for i in range(1, len(num)-1): + if num[i] in extremes: + num[i] = (num[i-1] + num[i+1]) / 2 + return audio.num2chr(num) + +def demo(): + gday = load('gday')[1000:6000] + save(gday, 'gday0') + gg = [gday] + for i in range(1, 10): + for g in gg: play(g) + g = stretch(gday, 10, 10-i) + save(g, 'gday' + `i`) + gg.append(g) + while 1: + for g in gg: play(g) diff --git a/lib/calendar.py b/lib/calendar.py new file mode 100644 index 0000000..97ca86f --- /dev/null +++ b/lib/calendar.py @@ -0,0 +1,213 @@ +# module calendar + +############################## +# Calendar support functions # +############################## + +# This is based on UNIX ctime() et al. (also Standard C and POSIX) +# Subtle but crucial differences: +# - the order of the elements of a 'struct tm' differs, to ease sorting +# - months numbers are 1-12, not 0-11; month arrays have a dummy element 0 +# - Monday is the first day of the week (numbered 0) + +# These are really parameters of the 'time' module: +epoch = 1970 # Time began on January 1 of this year (00:00:00 UCT) +day_0 = 3 # The epoch begins on a Thursday (Monday = 0) + +# Return 1 for leap years, 0 for non-leap years +def isleap(year): + return year % 4 = 0 and (year % 100 <> 0 or year % 400 = 0) + +# Constants for months referenced later +January = 1 +February = 2 + +# Number of days per month (except for February in leap years) +mdays = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) + +# Exception raised for bad input (with string parameter for details) +error = 'calendar error' + +# Turn seconds since epoch into calendar time +def gmtime(secs): + if secs < 0: raise error, 'negative input to gmtime()' + mins, secs = divmod(secs, 60) + hours, mins = divmod(mins, 60) + days, hours = divmod(hours, 24) + wday = (days + day_0) % 7 + year = epoch + # XXX Most of the following loop can be replaced by one division + while 1: + yd = 365 + isleap(year) + if days < yd: break + days = days - yd + year = year + 1 + yday = days + month = January + while 1: + md = mdays[month] + (month = February and isleap(year)) + if days < md: break + days = days - md + month = month + 1 + return year, month, days + 1, hours, mins, secs, yday, wday + # XXX Week number also? + +# Return number of leap years in range [y1, y2) +# Assume y1 <= y2 and no funny (non-leap century) years +def leapdays(y1, y2): + return (y2+3)/4 - (y1+3)/4 + +# Inverse of gmtime(): +# Turn UCT calendar time (less yday, wday) into seconds since epoch +def mktime(year, month, day, hours, mins, secs): + days = day - 1 + for m in range(January, month): days = days + mdays[m] + if isleap(year) and month > February: days = days+1 + days = days + (year-epoch)*365 + leapdays(epoch, year) + return ((days*24 + hours)*60 + mins)*60 + secs + +# Full and abbreviated names of weekdays +day_name = ('Monday', 'Tuesday', 'Wednesday', 'Thursday') +day_name = day_name + ('Friday', 'Saturday', 'Sunday') +day_abbr = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun') + +# Full and abbreviated of months (1-based arrays!!!) +month_name = ('', 'January', 'February', 'March', 'April') +month_name = month_name + ('May', 'June', 'July', 'August') +month_name = month_name + ('September', 'October', 'November', 'December') +month_abbr = (' ', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun') +month_abbr = month_abbr + ('Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec') + +# Zero-fill string to two positions (helper for asctime()) +def dd(s): + while len(s) < 2: s = '0' + s + return s + +# Blank-fill string to two positions (helper for asctime()) +def zd(s): + while len(s) < 2: s = ' ' + s + return s + +# Turn calendar time as returned by gmtime() into a string +# (the yday parameter is for compatibility with gmtime()) +def asctime(year, month, day, hours, mins, secs, yday, wday): + s = day_abbr[wday] + ' ' + month_abbr[month] + ' ' + zd(`day`) + s = s + ' ' + dd(`hours`) + ':' + dd(`mins`) + ':' + dd(`secs`) + return s + ' ' + `year` + +# Localization: Minutes West from Greenwich +# timezone = -2*60 # Middle-European time with DST on +timezone = 5*60 # EST (sigh -- THINK time() doesn't return UCT) + +# Local time ignores DST issues for now -- adjust 'timezone' to fake it +def localtime(secs): + return gmtime(secs - timezone*60) + +# UNIX-style ctime (except it doesn't append '\n'!) +def ctime(secs): + return asctime(localtime(secs)) + +###################### +# Non-UNIX additions # +###################### + +# Calendar printing etc. + +# Return weekday (0-6 ~ Mon-Sun) for year (1970-...), month (1-12), day (1-31) +def weekday(year, month, day): + secs = mktime(year, month, day, 0, 0, 0) + days = secs / (24*60*60) + return (days + day_0) % 7 + +# Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for year, month +def monthrange(year, month): + day1 = weekday(year, month, 1) + ndays = mdays[month] + (month = February and isleap(year)) + return day1, ndays + +# Return a matrix representing a month's calendar +# Each row represents a week; days outside this month are zero +def _monthcalendar(year, month): + day1, ndays = monthrange(year, month) + rows = [] + r7 = range(7) + day = 1 - day1 + while day <= ndays: + row = [0, 0, 0, 0, 0, 0, 0] + for i in r7: + if 1 <= day <= ndays: row[i] = day + day = day + 1 + rows.append(row) + return rows + +# Caching interface to _monthcalendar +mc_cache = {} +def monthcalendar(year, month): + key = `year` + month_abbr[month] + try: + return mc_cache[key] + except RuntimeError: + mc_cache[key] = ret = _monthcalendar(year, month) + return ret + +# Center a string in a field +def center(str, width): + n = width - len(str) + if n < 0: return str + return ' '*(n/2) + str + ' '*(n-n/2) + +# XXX The following code knows that print separates items with space! + +# Print a single week (no newline) +def prweek(week, width): + for day in week: + if day = 0: print ' '*width, + else: + if width > 2: print ' '*(width-3), + if day < 10: print '', + print day, + +# Return a header for a week +def weekheader(width): + str = '' + for i in range(7): + if str: str = str + ' ' + str = str + day_abbr[i%7][:width] + return str + +# Print a month's calendar +def prmonth(year, month): + print weekheader(3) + for week in monthcalendar(year, month): + prweek(week, 3) + print + +# Spacing between month columns +spacing = ' ' + +# 3-column formatting for year calendars +def format3c(a, b, c): + print center(a, 20), spacing, center(b, 20), spacing, center(c, 20) + +# Print a year's calendar +def prcal(year): + header = weekheader(2) + format3c('', `year`, '') + for q in range(January, January+12, 3): + print + format3c(month_name[q], month_name[q+1], month_name[q+2]) + format3c(header, header, header) + data = [] + height = 0 + for month in range(q, q+3): + cal = monthcalendar(year, month) + if len(cal) > height: height = len(cal) + data.append(cal) + for i in range(height): + for cal in data: + if i >= len(cal): + print ' '*20, + else: + prweek(cal[i], 2) + print spacing, + print diff --git a/lib/clock.py b/lib/clock.py new file mode 100644 index 0000000..ec5301e --- /dev/null +++ b/lib/clock.py @@ -0,0 +1,202 @@ +# 'klok' -- A simple alarm clock + +# The alarm can be set at 5 minute intervals on a 12 hour basis. +# It is controlled with the mouse: +# - Click and drag around the circle to set the alarm. +# - Click far outside the circle to clear the alarm. +# - Click near the center to set the alarm at the last time set. +# The alarm time is indicated by a small triangle just outside the circle, +# and also by a digital time at the bottom. +# The indicators disappear when the alarm is not set. +# When the alarm goes off, it beeps every minute for five minutes, +# and the clock turns into inverse video. +# Click or activate the window to turn the ringing off. + +import stdwin +from stdwinevents import WE_MOUSE_DOWN, WE_MOUSE_MOVE, WE_MOUSE_UP, \ + WE_TIMER, WE_DRAW, WE_SIZE, WE_CLOSE, WE_ACTIVATE +import time +from math import sin, cos, atan2, pi, sqrt + +DEFWIDTH, DEFHEIGHT = 200, 200 + +mouse_events = (WE_MOUSE_DOWN, WE_MOUSE_MOVE, WE_MOUSE_UP) +origin = 0, 0 +faraway = 2000, 2000 +everywhere = origin, faraway + +class struct(): pass # A class to declare featureless objects + +G = struct() # Global variables (most set in setdimensions()) +G.tzdiff = 5*3600 # THINK computes UCT from local time assuming EST! + +A = struct() # Globals used by the alarm +A.set = 1 # True when alarm is set +A.time = 11*60 + 40 # Time when alarm must go off +A.ring = 0 # True when alarm is ringing + +def main(): + try: + realmain() + except KeyboardInterrupt: + print 'KeyboardInterrupt' + finally: + G.w = 0 + +def realmain(): + setdimensions(DEFWIDTH, DEFHEIGHT) + stdwin.setdefwinsize(G.farcorner) + G.w = stdwin.open('klok') + settimer() + while 1: + type, window, detail = stdwin.getevent() + if type = WE_DRAW: + drawproc(detail) + elif type = WE_TIMER: + settimer() + drawproc(everywhere) + elif type in mouse_events: + mouseclick(type, detail) + elif type = WE_ACTIVATE: + if A.ring: + # Turn the ringing off + A.ring = 0 + G.w.begindrawing().invert(G.mainarea) + elif type = WE_SIZE: + G.w.change(everywhere) + width, height = G.w.getwinsize() + height = height - stdwin.lineheight() + setdimensions(width, height) + elif type = WE_CLOSE: + break + +def setdimensions(width, height): + if width < height: size = width + else: size = height + halfwidth = width/2 + halfheight = height/2 + G.center = halfwidth, halfheight + G.radius = size*45/100 + G.width = width + G.height = height + G.corner = width, height + G.mainarea = origin, G.corner + G.lineheight = stdwin.lineheight() + G.farcorner = width, height + G.lineheight + G.statusarea = (0, height), G.farcorner + G.fullarea = origin, G.farcorner + +def settimer(): + now = getlocaltime() + G.times = calctime(now) + delay = 61 - now % 60 + G.w.settimer(10 * delay) + minutes = (now/60) % 720 + if A.ring: + # Is it time to stop the alarm ringing? + since = (minutes - A.time + 720) % 720 + if since >= 5: + # Stop it now + A.ring = 0 + else: + # Ring again, once every minute + stdwin.fleep() + elif A.set and minutes = A.time: + # Start the alarm ringing + A.ring = 1 + stdwin.fleep() + +def drawproc(area): + hours, minutes, seconds = G.times + d = G.w.begindrawing() + d.cliprect(area) + d.erase(everywhere) + d.circle(G.center, G.radius) + d.line(G.center, calcpoint(hours*30 + minutes/2, 0.6)) + d.line(G.center, calcpoint(minutes*6, 1.0)) + str = dd(hours) + ':' + dd(minutes) + p = (G.width - d.textwidth(str))/2, G.height * 3 / 4 + d.text(p, str) + if A.set: + drawalarm(d) + drawalarmtime(d) + if A.ring: + d.invert(G.mainarea) + +def mouseclick(type, detail): + d = G.w.begindrawing() + if A.ring: + # First turn the ringing off + A.ring = 0 + d.invert(G.mainarea) + h, v = detail[0] + ch, cv = G.center + x, y = h-ch, cv-v + dist = sqrt(x*x + y*y) / float(G.radius) + if dist > 1.2: + if A.set: + drawalarm(d) + erasealarmtime(d) + A.set = 0 + elif dist < 0.8: + if not A.set: + A.set = 1 + drawalarm(d) + drawalarmtime(d) + else: + # Convert to half-degrees (range 0..720) + alpha = atan2(y, x) + hdeg = alpha*360.0/pi + hdeg = 180.0 - hdeg + hdeg = (hdeg + 720.0) % 720.0 + atime = 5*int(hdeg/5.0 + 0.5) + if atime <> A.time or not A.set: + if A.set: + drawalarm(d) + erasealarmtime(d) + A.set = 1 + A.time = atime + drawalarm(d) + drawalarmtime(d) + +def drawalarm(d): + p1 = calcpoint(float(A.time)/2.0, 1.02) + p2 = calcpoint(float(A.time)/2.0 - 4.0, 1.1) + p3 = calcpoint(float(A.time)/2.0 + 4.0, 1.1) + d.xorline(p1, p2) + d.xorline(p2, p3) + d.xorline(p3, p1) + +def erasealarmtime(d): + d.erase(G.statusarea) + +def drawalarmtime(d): + # A.time is in the range 0..720 with origin at 12 o'clock + # Convert to hours (0..12) and minutes (12*(0..60)) + hh = A.time/60 + mm = A.time%60 + str = 'Alarm@' + dd(hh) + ':' + dd(mm) + p1 = (G.width - d.textwidth(str))/2, G.height + d.text(p1, str) + +def calctime(now): + seconds = now % 60 + minutes = (now/60) % 60 + hours = (now/3600) % 12 + return hours, minutes, seconds + +def calcpoint(degrees, size): + alpha = pi/2.0 - float(degrees) * pi/180.0 + x, y = cos(alpha), sin(alpha) + h, v = G.center + r = float(G.radius) + return h + int(x*size*r), v - int(y*size*r) + +def dd(n): + s = `n` + return '0'*(2-len(s)) + s + +def getlocaltime(): + return time.time() - G.tzdiff + +#main() diff --git a/lib/cmp.py b/lib/cmp.py new file mode 100644 index 0000000..8dc315e --- /dev/null +++ b/lib/cmp.py @@ -0,0 +1,61 @@ +# Module 'cmp' + +# Efficiently compare files, boolean outcome only (equal / not equal). + +# Tricks (used in this order): +# - Files with identical type, size & mtime are assumed to be clones +# - Files with different type or size cannot be identical +# - We keep a cache of outcomes of earlier comparisons +# - We don't fork a process to run 'cmp' but read the files ourselves + +import posix + +cache = {} + +def cmp(f1, f2): # Compare two files, use the cache if possible. + # Return 1 for identical files, 0 for different. + # Raise exceptions if either file could not be statted, read, etc. + s1, s2 = sig(posix.stat(f1)), sig(posix.stat(f2)) + if s1[0] <> 8 or s2[0] <> 8: + # Either is a not a plain file -- always report as different + return 0 + if s1 = s2: + # type, size & mtime match -- report same + return 1 + if s1[:2] <> s2[:2]: # Types or sizes differ, don't bother + # types or sizes differ -- report different + return 0 + # same type and size -- look in the cache + key = f1 + ' ' + f2 + try: + cs1, cs2, outcome = cache[key] + # cache hit + if s1 = cs1 and s2 = cs2: + # cached signatures match + return outcome + # stale cached signature(s) + except RuntimeError: + # cache miss + pass + # really compare + outcome = do_cmp(f1, f2) + cache[key] = s1, s2, outcome + return outcome + +def sig(st): # Return signature (i.e., type, size, mtime) from raw stat data + # 0-5: st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid + # 6-9: st_size, st_atime, st_mtime, st_ctime + type = st[0] / 4096 + size = st[6] + mtime = st[8] + return type, size, mtime + +def do_cmp(f1, f2): # Compare two files, really + bufsize = 8096 # Could be tuned + fp1 = open(f1, 'r') + fp2 = open(f2, 'r') + while 1: + b1 = fp1.read(bufsize) + b2 = fp2.read(bufsize) + if b1 <> b2: return 0 + if not b1: return 1 diff --git a/lib/cmpcache.py b/lib/cmpcache.py new file mode 100644 index 0000000..4aea356 --- /dev/null +++ b/lib/cmpcache.py @@ -0,0 +1,68 @@ +# Module 'cmpcache' +# +# Efficiently compare files, boolean outcome only (equal / not equal). +# +# Tricks (used in this order): +# - Use the statcache module to avoid statting files more than once +# - Files with identical type, size & mtime are assumed to be clones +# - Files with different type or size cannot be identical +# - We keep a cache of outcomes of earlier comparisons +# - We don't fork a process to run 'cmp' but read the files ourselves + +import posix +from stat import * +import statcache + + +# The cache. +# +cache = {} + + +# Compare two files, use the cache if possible. +# May raise posix.error if a stat or open of either fails. +# +def cmp(f1, f2): + # Return 1 for identical files, 0 for different. + # Raise exceptions if either file could not be statted, read, etc. + s1, s2 = sig(statcache.stat(f1)), sig(statcache.stat(f2)) + if not S_ISREG(s1[0]) or not S_ISREG(s2[0]): + # Either is a not a plain file -- always report as different + return 0 + if s1 = s2: + # type, size & mtime match -- report same + return 1 + if s1[:2] <> s2[:2]: # Types or sizes differ, don't bother + # types or sizes differ -- report different + return 0 + # same type and size -- look in the cache + key = f1 + ' ' + f2 + if cache.has_key(key): + cs1, cs2, outcome = cache[key] + # cache hit + if s1 = cs1 and s2 = cs2: + # cached signatures match + return outcome + # stale cached signature(s) + # really compare + outcome = do_cmp(f1, f2) + cache[key] = s1, s2, outcome + return outcome + +# Return signature (i.e., type, size, mtime) from raw stat data. +# +def sig(st): + return S_IFMT(st[ST_MODE]), st[ST_SIZE], st[ST_MTIME] + +# Compare two files, really. +# +def do_cmp(f1, f2): + #print ' cmp', f1, f2 # XXX remove when debugged + bufsize = 8096 # Could be tuned + fp1 = open(f1, 'r') + fp2 = open(f2, 'r') + while 1: + b1 = fp1.read(bufsize) + b2 = fp2.read(bufsize) + if b1 <> b2: return 0 + if not b1: return 1 diff --git a/lib/commands.py b/lib/commands.py new file mode 100644 index 0000000..3cb6e69 --- /dev/null +++ b/lib/commands.py @@ -0,0 +1,77 @@ +# Module 'commands' +# +# Various tools for executing commands and looking at their output and status. + +import rand +import posix +import stat +import path + + +# Get 'ls -l' status for an object into a string +# +def getstatus(file): + return getoutput('ls -ld' + mkarg(file)) + + +# Get the output from a shell command into a string. +# The exit status is ignored; a trailing newline is stripped. +# Assume the command will work with ' >tempfile 2>&1' appended. +# XXX This should use posix.popen() instead, should it exist. +# +def getoutput(cmd): + return getstatusoutput(cmd)[1] + + +# Ditto but preserving the exit status. +# Returns a pair (sts, output) +# +def getstatusoutput(cmd): + tmp = '/usr/tmp/wdiff' + `rand.rand()` + sts = -1 + try: + sts = posix.system(cmd + ' >' + tmp + ' 2>&1') + text = readfile(tmp) + finally: + altsts = posix.system('rm -f ' + tmp) + if text[-1:] = '\n': text = text[:-1] + return sts, text + + +# Return a string containing a file's contents. +# +def readfile(fn): + st = posix.stat(fn) + size = st[stat.ST_SIZE] + if not size: return '' + try: + fp = open(fn, 'r') + except: + raise posix.error, 'readfile(' + fn + '): open failed' + try: + return fp.read(size) + except: + raise posix.error, 'readfile(' + fn + '): read failed' + + +# Make command argument from directory and pathname (prefix space, add quotes). +# +def mk2arg(head, x): + return mkarg(path.cat(head, x)) + + +# Make a shell command argument from a string. +# Two strategies: enclose in single quotes if it contains none; +# otherwis, enclose in double quotes and prefix quotable characters +# with backslash. +# +def mkarg(x): + if '\'' not in x: + return ' \'' + x + '\'' + s = ' "' + for c in x: + if c in '\\$"': + s = s + '\\' + s = s + c + s = s + '"' + return s diff --git a/lib/dircache.py b/lib/dircache.py new file mode 100644 index 0000000..c14db3e --- /dev/null +++ b/lib/dircache.py @@ -0,0 +1,36 @@ +# Module 'dircache' +# +# Return a sorted list of the files in a POSIX directory, using a cache +# to avoid reading the directory more often than necessary. +# Also contains a subroutine to append slashes to directories. + +import posix +import path + +cache = {} + +def listdir(path): # List directory contents, using cache + try: + cached_mtime, list = cache[path] + del cache[path] + except RuntimeError: + cached_mtime, list = -1, [] + try: + mtime = posix.stat(path)[8] + except posix.error: + return [] + if mtime <> cached_mtime: + try: + list = posix.listdir(path) + except posix.error: + return [] + list.sort() + cache[path] = mtime, list + return list + +opendir = listdir # XXX backward compatibility + +def annotate(head, list): # Add '/' suffixes to directories + for i in range(len(list)): + if path.isdir(path.cat(head, list[i])): + list[i] = list[i] + '/' diff --git a/lib/dircmp.py b/lib/dircmp.py new file mode 100644 index 0000000..31e712c --- /dev/null +++ b/lib/dircmp.py @@ -0,0 +1,205 @@ +# Module 'dirmp' +# +# Defines a class to build directory diff tools on. + +import posix + +import path + +import dircache +import cmpcache +import statcache +from stat import * + +# Directory comparison class. +# +class dircmp(): + # + def new(dd, (a, b)): # Initialize + dd.a = a + dd.b = b + # Properties that caller may change before callingdd. run(): + dd.hide = ['.', '..'] # Names never to be shown + dd.ignore = ['RCS', 'tags'] # Names ignored in comparison + # + return dd + # + def run(dd): # Compare everything except common subdirectories + dd.a_list = filter(dircache.listdir(dd.a), dd.hide) + dd.b_list = filter(dircache.listdir(dd.b), dd.hide) + dd.a_list.sort() + dd.b_list.sort() + dd.phase1() + dd.phase2() + dd.phase3() + # + def phase1(dd): # Compute common names + dd.a_only = [] + dd.common = [] + for x in dd.a_list: + if x in dd.b_list: + dd.common.append(x) + else: + dd.a_only.append(x) + # + dd.b_only = [] + for x in dd.b_list: + if x not in dd.common: + dd.b_only.append(x) + # + def phase2(dd): # Distinguish files, directories, funnies + dd.common_dirs = [] + dd.common_files = [] + dd.common_funny = [] + # + for x in dd.common: + a_path = path.cat(dd.a, x) + b_path = path.cat(dd.b, x) + # + ok = 1 + try: + a_stat = statcache.stat(a_path) + except posix.error, why: + # print 'Can\'t stat', a_path, ':', why[1] + ok = 0 + try: + b_stat = statcache.stat(b_path) + except posix.error, why: + # print 'Can\'t stat', b_path, ':', why[1] + ok = 0 + # + if ok: + a_type = S_IFMT(a_stat[ST_MODE]) + b_type = S_IFMT(b_stat[ST_MODE]) + if a_type <> b_type: + dd.common_funny.append(x) + elif S_ISDIR(a_type): + dd.common_dirs.append(x) + elif S_ISREG(a_type): + dd.common_files.append(x) + else: + dd.common_funny.append(x) + else: + dd.common_funny.append(x) + # + def phase3(dd): # Find out differences between common files + xx = cmpfiles(dd.a, dd.b, dd.common_files) + dd.same_files, dd.diff_files, dd.funny_files = xx + # + def phase4(dd): # Find out differences between common subdirectories + # A new dircmp object is created for each common subdirectory, + # these are stored in a dictionary indexed by filename. + # The hide and ignore properties are inherited from the parent + dd.subdirs = {} + for x in dd.common_dirs: + a_x = path.cat(dd.a, x) + b_x = path.cat(dd.b, x) + dd.subdirs[x] = newdd = dircmp().new(a_x, b_x) + newdd.hide = dd.hide + newdd.ignore = dd.ignore + newdd.run() + # + def phase4_closure(dd): # Recursively call phase4() on subdirectories + dd.phase4() + for x in dd.subdirs.keys(): + dd.subdirs[x].phase4_closure() + # + def report(dd): # Print a report on the differences between a and b + # Assume that phases 1 to 3 have been executed + # Output format is purposely lousy + print 'diff', dd.a, dd.b + if dd.a_only: + print 'Only in', dd.a, ':', dd.a_only + if dd.b_only: + print 'Only in', dd.b, ':', dd.b_only + if dd.same_files: + print 'Identical files :', dd.same_files + if dd.diff_files: + print 'Differing files :', dd.diff_files + if dd.funny_files: + print 'Trouble with common files :', dd.funny_files + if dd.common_dirs: + print 'Common subdirectories :', dd.common_dirs + if dd.common_funny: + print 'Common funny cases :', dd.common_funny + # + def report_closure(dd): # Print reports on dd and on subdirs + # If phase 4 hasn't been done, no subdir reports are printed + dd.report() + try: + x = dd.subdirs + except NameError: + return # No subdirectories computed + for x in dd.subdirs.keys(): + print + dd.subdirs[x].report_closure() + # + def report_phase4_closure(dd): # Report and do phase 4 recursively + dd.report() + dd.phase4() + for x in dd.subdirs.keys(): + print + dd.subdirs[x].report_phase4_closure() + + +# Compare common files in two directories. +# Return: +# - files that compare equal +# - files that compare different +# - funny cases (can't stat etc.) +# +def cmpfiles(a, b, common): + res = ([], [], []) + for x in common: + res[cmp(path.cat(a, x), path.cat(b, x))].append(x) + return res + + +# Compare two files. +# Return: +# 0 for equal +# 1 for different +# 2 for funny cases (can't stat, etc.) +# +def cmp(a, b): + try: + if cmpcache.cmp(a, b): return 0 + return 1 + except posix.error: + return 2 + + +# Remove a list item. +# NB: This modifies the list argument. +# +def remove(list, item): + for i in range(len(list)): + if list[i] = item: + del list[i] + break + + +# Return a copy with items that occur in skip removed. +# +def filter(list, skip): + result = [] + for item in list: + if item not in skip: result.append(item) + return result + + +# Demonstration and testing. +# +def demo(): + import sys + import getopt + options, args = getopt.getopt(sys.argv[1:], 'r') + if len(args) <> 2: raise getopt.error, 'need exactly two args' + dd = dircmp().new(args[0], args[1]) + dd.run() + if ('-r', '') in options: + dd.report_phase4_closure() + else: + dd.report() + +# demo() diff --git a/lib/dirwin.py b/lib/dirwin.py new file mode 100644 index 0000000..76e0b5e --- /dev/null +++ b/lib/dirwin.py @@ -0,0 +1,29 @@ +# Module 'dirwin' + +# Directory windows, a subclass of listwin + +import gwin +import listwin +import anywin +import path +import dircache + +def action(w, string, i, detail): + (h, v), clicks, button, mask = detail + if clicks = 2: + name = path.cat(w.name, string) + try: + w2 = anywin.open(name) + w2.parent = w + except posix.error, why: + stdwin.message('Can\'t open ' + name + ': ' + why[1]) + +def open(name): + name = path.cat(name, '') + list = dircache.opendir(name)[:] + list.sort() + dircache.annotate(name, list) + w = listwin.open(name, list) + w.name = name + w.action = action + return w diff --git a/lib/dis.py b/lib/dis.py new file mode 100644 index 0000000..d13b08f --- /dev/null +++ b/lib/dis.py @@ -0,0 +1,176 @@ +# Disassembler + +import sys +import string + +def dis(): + tb = sys.last_traceback + while tb.tb_next: tb = tb.tb_next + distb(tb) + +def distb(tb): + disassemble(tb.tb_frame.f_code, tb.tb_lasti) + +def disco(co): + disassemble(co, -1) + +def disassemble(co, lasti): + code = co.co_code + labels = findlabels(code) + n = len(code) + i = 0 + while i < n: + c = code[i] + op = ord(c) + if op = SET_LINENO and i > 0: print # Extra blank line + if i = lasti: print '-->', + else: print ' ', + if i in labels: print '>>', + else: print ' ', + print string.rjust(`i`, 4), + print string.ljust(opname[op], 15), + i = i+1 + if op >= HAVE_ARGUMENT: + oparg = ord(code[i]) + ord(code[i+1])*256 + i = i+2 + print string.rjust(`oparg`, 5), + if op in hasconst: + print '(' + `co.co_consts[oparg]` + ')', + elif op in hasname: + print '(' + co.co_names[oparg] + ')', + elif op in hasjrel: + print '(to ' + `i + oparg` + ')', + print + +def findlabels(code): + labels = [] + n = len(code) + i = 0 + while i < n: + c = code[i] + op = ord(c) + i = i+1 + if op >= HAVE_ARGUMENT: + oparg = ord(code[i]) + ord(code[i+1])*256 + i = i+2 + label = -1 + if op in hasjrel: + label = i+oparg + elif op in hasjabs: + label = oparg + if label >= 0: + if label not in labels: + labels.append(label) + return labels + +hasconst = [] +hasname = [] +hasjrel = [] +hasjabs = [] + +opname = range(256) +for op in opname: opname[op] = '<' + `op` + '>' + +def def_op(name, op): + opname[op] = name + +def name_op(name, op): + opname[op] = name + hasname.append(op) + +def jrel_op(name, op): + opname[op] = name + hasjrel.append(op) + +def jabs_op(name, op): + opname[op] = name + hasjabs.append(op) + +# Instruction opcodes for compiled code + +def_op('STOP_CODE', 0) +def_op('POP_TOP', 1) +def_op('ROT_TWO', 2) +def_op('ROT_THREE', 3) +def_op('DUP_TOP', 4) + +def_op('UNARY_POSITIVE', 10) +def_op('UNARY_NEGATIVE', 11) +def_op('UNARY_NOT', 12) +def_op('UNARY_CONVERT', 13) +def_op('UNARY_CALL', 14) + +def_op('BINARY_MULTIPLY', 20) +def_op('BINARY_DIVIDE', 21) +def_op('BINARY_MODULO', 22) +def_op('BINARY_ADD', 23) +def_op('BINARY_SUBTRACT', 24) +def_op('BINARY_SUBSCR', 25) +def_op('BINARY_CALL', 26) + +def_op('SLICE+0', 30) +def_op('SLICE+1', 31) +def_op('SLICE+2', 32) +def_op('SLICE+3', 33) + +def_op('STORE_SLICE+0', 40) +def_op('STORE_SLICE+1', 41) +def_op('STORE_SLICE+2', 42) +def_op('STORE_SLICE+3', 43) + +def_op('DELETE_SLICE+0', 50) +def_op('DELETE_SLICE+1', 51) +def_op('DELETE_SLICE+2', 52) +def_op('DELETE_SLICE+3', 53) + +def_op('STORE_SUBSCR', 60) +def_op('DELETE_SUBSCR', 61) + +def_op('PRINT_EXPR', 70) +def_op('PRINT_ITEM', 71) +def_op('PRINT_NEWLINE', 72) + +def_op('BREAK_LOOP', 80) +def_op('RAISE_EXCEPTION', 81) +def_op('LOAD_LOCALS', 82) +def_op('RETURN_VALUE', 83) +def_op('REQUIRE_ARGS', 84) +def_op('REFUSE_ARGS', 85) +def_op('BUILD_FUNCTION', 86) +def_op('POP_BLOCK', 87) +def_op('END_FINALLY', 88) +def_op('BUILD_CLASS', 89) + +HAVE_ARGUMENT = 90 # Opcodes from here have an argument: + +name_op('STORE_NAME', 90) # Index in name list +name_op('DELETE_NAME', 91) # "" +def_op('UNPACK_TUPLE', 92) # Number of tuple items +def_op('UNPACK_LIST', 93) # Number of list items +# unused: 94 +name_op('STORE_ATTR', 95) # Index in name list +name_op('DELETE_ATTR', 96) # "" + +def_op('LOAD_CONST', 100) # Index in const list +hasconst.append(100) +name_op('LOAD_NAME', 101) # Index in name list +def_op('BUILD_TUPLE', 102) # Number of tuple items +def_op('BUILD_LIST', 103) # Number of list items +def_op('BUILD_MAP', 104) # Always zero for now +name_op('LOAD_ATTR', 105) # Index in name list +def_op('COMPARE_OP', 106) # Comparison operator +name_op('IMPORT_NAME', 107) # Index in name list +name_op('IMPORT_FROM', 108) # Index in name list + +jrel_op('JUMP_FORWARD', 110) # Number of bytes to skip +jrel_op('JUMP_IF_FALSE', 111) # "" +jrel_op('JUMP_IF_TRUE', 112) # "" +jabs_op('JUMP_ABSOLUTE', 113) # Target byte offset from beginning of code +jrel_op('FOR_LOOP', 114) # Number of bytes to skip + +jrel_op('SETUP_LOOP', 120) # Distance to target address +jrel_op('SETUP_EXCEPT', 121) # "" +jrel_op('SETUP_FINALLY', 122) # "" + +def_op('SET_LINENO', 127) # Current line number +SET_LINENO = 127 diff --git a/lib/dump.py b/lib/dump.py new file mode 100644 index 0000000..0510092 --- /dev/null +++ b/lib/dump.py @@ -0,0 +1,63 @@ +# Module 'dump' +# +# Print python code that reconstructs a variable. +# This only works in certain cases. +# +# It works fine for: +# - ints and floats (except NaNs and other weird things) +# - strings +# - compounds and lists, provided it works for all their elements +# - imported modules, provided their name is the module name +# +# It works for top-level dictionaries but not for dictionaries +# contained in other objects (could be made to work with some hassle +# though). +# +# It does not work for functions (all sorts), classes, class objects, +# windows, files etc. +# +# Finally, objects referenced by more than one name or contained in more +# than one other object lose their sharing property (this is bad for +# strings used as exception identifiers, for instance). + +# Dump a whole symbol table +# +def dumpsymtab(dict): + for key in dict.keys(): + dumpvar(key, dict[key]) + +# Dump a single variable +# +def dumpvar(name, x): + import sys + t = type(x) + if t = type({}): + print name, '= {}' + for key in x.keys(): + item = x[key] + if not printable(item): + print '#', + print name, '[', `key`, '] =', `item` + elif t in (type(''), type(0), type(0.0), type([]), type(())): + if not printable(x): + print '#', + print name, '=', `x` + elif t = type(sys): + print 'import', name, '#', x + else: + print '#', name, '=', x + +# check if a value is printable in a way that can be read back with input() +# +def printable(x): + t = type(x) + if t in (type(''), type(0), type(0.0)): + return 1 + if t in (type([]), type(())): + for item in x: + if not printable(item): + return 0 + return 1 + if x = {}: + return 1 + return 0 diff --git a/lib/fact.py b/lib/fact.py new file mode 100644 index 0000000..ba961c4 --- /dev/null +++ b/lib/fact.py @@ -0,0 +1,37 @@ +# Factorize numbers -- slow, could use a table of all primes <= 2*16 + +import sys +import math + +error = 'fact.error' # exception + +def fact(n): + if n < 1: raise error # fact() argument should be >= 1 + if n = 1: return [] # special case + res = [] + _fact(n, 2, res) + return res + +def _fact(n, lowest, res): + highest = int(math.sqrt(float(n+1))) + for i in range(lowest, highest+1): + if n%i = 0: + res.append(i) + _fact(n/i, i, res) + break + else: + res.append(n) + +def main(): + if len(sys.argv) > 1: + for arg in sys.argv[1:]: + n = eval(arg) + print n, fact(n) + else: + try: + while 1: + print fact(input()) + except EOFError: + pass + +main() diff --git a/lib/filewin.py b/lib/filewin.py new file mode 100644 index 0000000..ad35ea4 --- /dev/null +++ b/lib/filewin.py @@ -0,0 +1,18 @@ +# Module 'filewin' +# File windows, a subclass of textwin (which is a subclass of gwin) + +import textwin +from util import readfile + + +# FILE WINDOW + +def open_readonly(fn): # Open a file window + w = textwin.open_readonly(fn, readfile(fn)) + w.fn = fn + return w + +def open(fn): # Open a file window + w = textwin.open(fn, readfile(fn)) + w.fn = fn + return w diff --git a/lib/fnmatch.py b/lib/fnmatch.py new file mode 100644 index 0000000..8f9e318 --- /dev/null +++ b/lib/fnmatch.py @@ -0,0 +1,35 @@ +# module 'fnmatch' -- filename matching with shell patterns + +# XXX [] patterns are not supported (but recognized) + +def fnmatch(name, pat): + if '*' in pat or '?' in pat or '[' in pat: + return fnmatch1(name, pat) + return name = pat + +def fnmatch1(name, pat): + for i in range(len(pat)): + c = pat[i] + if c = '*': + restpat = pat[i+1:] + if '*' in restpat or '?' in restpat or '[' in restpat: + for i in range(i, len(name)): + if fnmatch1(name[i:], restpat): + return 1 + return 0 + else: + return name[len(name)-len(restpat):] = restpat + elif c = '?': + if len(name) <= i : return 0 + elif c = '[': + return 0 # XXX + else: + if name[i:i+1] <> c: + return 0 + return 1 + +def fnmatchlist(names, pat): + res = [] + for name in names: + if fnmatch(name, pat): res.append(name) + return res diff --git a/lib/getopt.py b/lib/getopt.py new file mode 100644 index 0000000..f343c22 --- /dev/null +++ b/lib/getopt.py @@ -0,0 +1,47 @@ +# module getopt -- Standard command line processing. + +# Function getopt.getopt() has a different interface but provides the +# same functionality as the Unix getopt() function. + +# It has two arguments: the first should be argv[1:] (it doesn't want +# the script name), the second the string of option letters as passed +# to Unix getopt() (i.e., a string of allowable option letters, with +# options requiring an argument followed by a colon). + +# It raises the exception getopt.error with a string argument if it +# detects an error. + +# It returns two items: +# (1) a list of pairs (option, option_argument) giving the options in +# the order in which they were specified. (I'd use a dictionary +# but applications may depend on option order or multiple +# occurrences.) Boolean options have '' as option_argument. +# (2) the list of remaining arguments (may be empty). + +error = 'getopt error' + +def getopt(args, options): + list = [] + while args and args[0][0] = '-' and args[0] <> '-': + if args[0] = '--': + args = args[1:] + break + optstring, args = args[0][1:], args[1:] + while optstring <> '': + opt, optstring = optstring[0], optstring[1:] + if classify(opt, options): # May raise exception as well + if optstring = '': + if not args: + raise error, 'option -' + opt + ' requires argument' + optstring, args = args[0], args[1:] + optarg, optstring = optstring, '' + else: + optarg = '' + list.append('-' + opt, optarg) + return list, args + +def classify(opt, options): # Helper to check type of option + for i in range(len(options)): + if opt = options[i] <> ':': + return options[i+1:i+2] = ':' + raise error, 'option -' + opt + ' not recognized' diff --git a/lib/glob.py b/lib/glob.py new file mode 100644 index 0000000..b711094 --- /dev/null +++ b/lib/glob.py @@ -0,0 +1,44 @@ +# Module 'glob' -- filename globbing. + +import posix +import path +import fnmatch + +def glob(pathname): + if not has_magic(pathname): return [pathname] + dirname, basename = path.split(pathname) + if dirname[-1:] = '/' and dirname <> '/': + dirname = dirname[:-1] + if has_magic(dirname): + list = glob(dirname) + else: + list = [dirname] + if not has_magic(basename): + result = [] + for dirname in list: + if basename or path.isdir(dirname): + name = path.cat(dirname, basename) + if path.exists(name): + result.append(name) + else: + result = [] + for dirname in list: + sublist = glob1(dirname, basename) + for name in sublist: + result.append(path.cat(dirname, name)) + return result + +def glob1(dirname, pattern): + if not dirname: dirname = '.' + try: + names = posix.listdir(dirname) + except posix.error: + return [] + result = [] + for name in names: + if name[0] <> '.' or pattern[0] = '.': + if fnmatch.fnmatch(name, pattern): result.append(name) + return result + +def has_magic(s): + return '*' in s or '?' in s or '[' in s diff --git a/lib/grep.py b/lib/grep.py new file mode 100644 index 0000000..66eb08d --- /dev/null +++ b/lib/grep.py @@ -0,0 +1,32 @@ +# 'grep' + +import regexp +import string + +def grep(expr, filename): + prog = regexp.compile(expr) + fp = open(filename, 'r') + lineno = 0 + while 1: + line = fp.readline() + if not line: break + lineno = lineno + 1 + res = prog.exec(line) + if res: + #print res + start, end = res[0] + if line[-1:] = '\n': line = line[:-1] + prefix = string.rjust(`lineno`, 3) + ': ' + print prefix + line + if 0: + line = line[:start] + if '\t' not in line: + prefix = ' ' * (len(prefix) + start) + else: + prefix = ' ' * len(prefix) + for c in line: + if c <> '\t': c = ' ' + prefix = prefix + c + if start = end: prefix = prefix + '\\' + else: prefix = prefix + '^'*(end-start) + print prefix diff --git a/lib/gwin.py b/lib/gwin.py new file mode 100644 index 0000000..f6291e1 --- /dev/null +++ b/lib/gwin.py @@ -0,0 +1,122 @@ +# Module 'gwin' +# Generic stdwin windows + +# This is used as a base class from which to derive other window types. +# The mainloop() function here is an event dispatcher for all window types. + +import stdwin +from stdwinevents import * + +# XXX Old version of stdwinevents, should go +import stdwinsupport +S = stdwinsupport # Shorthand + +windows = [] # List of open windows + + +# Open a window + +def open(title): # Open a generic window + w = stdwin.open(title) + stdwin.setdefwinsize(0, 0) + # Set default event handlers + w.draw = nop + w.char = nop + w.mdown = nop + w.mmove = nop + w.mup = nop + w.m2down = m2down + w.m2up = m2up + w.size = nop + w.move = nop + w.activate = w.deactivate = nop + w.timer = nop + # default command handlers + w.close = close + w.tab = tab + w.enter = enter + w.backspace = backspace + w.arrow = arrow + w.kleft = w.kup = w.kright = w.kdown = nop + windows.append(w) + return w + + +# Generic event dispatching + +def mainloop(): # Handle events until no windows left + while windows: + treatevent(stdwin.getevent()) + +def treatevent(e): # Handle a stdwin event + type, w, detail = e + if type = S.we_draw: + w.draw(w, detail) + elif type = S.we_menu: + m, item = detail + m.action[item](w, m, item) + elif type = S.we_command: + treatcommand(w, detail) + elif type = S.we_char: + w.char(w, detail) + elif type = S.we_mouse_down: + if detail[1] > 1: w.m2down(w, detail) + else: w.mdown(w, detail) + elif type = S.we_mouse_move: + w.mmove(w, detail) + elif type = S.we_mouse_up: + if detail[1] > 1: w.m2up(w, detail) + else: w.mup(w, detail) + elif type = S.we_size: + w.size(w, w.getwinsize()) + elif type = S.we_activate: + w.activate(w) + elif type = S.we_deactivate: + w.deactivate(w) + elif type = S.we_move: + w.move(w) + elif type = S.we_timer: + w.timer(w) + elif type = WE_CLOSE: + w.close(w) + +def treatcommand(w, type): # Handle a we_command event + if type = S.wc_close: + w.close(w) + elif type = S.wc_return: + w.enter(w) + elif type = S.wc_tab: + w.tab(w) + elif type = S.wc_backspace: + w.backspace(w) + elif type in (S.wc_left, S.wc_up, S.wc_right, S.wc_down): + w.arrow(w, type) + + +# Methods + +def close(w): # Close method + for i in range(len(windows)): + if windows[i] is w: + del windows[i] + break + +def arrow(w, detail): # Arrow key method + if detail = S.wc_left: + w.kleft(w) + elif detail = S.wc_up: + w.kup(w) + elif detail = S.wc_right: + w.kright(w) + elif detail = S.wc_down: + w.kdown(w) + + +# Trivial methods + +def tab(w): w.char(w, '\t') +def enter(w): w.char(w, '\n') # 'return' is a Python reserved word +def backspace(w): w.char(w, '\b') +def m2down(w, detail): w.mdown(w, detail) +def m2up(w, detail): w.mup(w, detail) +def nop(args): pass diff --git a/lib/lambda.py b/lib/lambda.py new file mode 100644 index 0000000..7d62b83 --- /dev/null +++ b/lib/lambda.py @@ -0,0 +1,151 @@ +# A bit of Lambda Calculus illustrated in Python. +# +# This does not use Python's built-in 'eval' or 'exec' functions! + + +# Currying +# +# From a function with 2 args, f(x, y), and a value for the 1st arg, +# we can create a new function with one argument fx(y) = f(x, y). +# This is called "Currying" (after the idea's inventor, a Mr. Curry). +# +# To implement this we create a class member, of which fx is a method; +# f and x are stored as data attributes of the member. + +class _CurryClass(): + def new(self, (f, x)): + self.f = f + self.x = x + return self + def fx(self, y): + return self.f(self.x, y) + +def CURRY(f, x): + # NB: f is not "simple": it has 2 arguments + return _CurryClass().new(f, x).fx + + +# Numbers in Lambda Calculus +# +# In the lambda calculus, natural numbers are represented by +# higher-order functions Ntimes(f, x) that yield f applied N +# times to x, e.g., Twice(f, x) = f(f(x)). +# As far as I understand, there is no difference in real lambda +# calculus between +# lambda f x : f(f(x)) +# and +# lambda f : f o f # 'o' means function composition +# but in Python we have to write the first as Twice(f, x) and +# the second as twice(f). + +def Never(f, x): return x +def Once(f, x): return f(x) +def Twice(f, x): return f(f(x)) +def Thrice(f, x): return f(f(f(x))) +def Fourfold(f, x): return f(f(f(f(x)))) +# (etc.) + +def never(f): return CURRY(Never, f) +def once(f): return CURRY(Once, f) +def twice(f): return CURRY(Twice, f) +def thrice(f): return CURRY(Thrice, f) +def fourfold(f): return CURRY(Fourfold, f) +# (etc.) + + +# NB: actually 'ntimes' is less concrete than 'Ntimes', as +# 'ntimes' returns a function, while 'Ntimes' returns a value +# similar to what f(x) returns. 'Ntimes' can be derived +# from 'ntimes', as follows: +# def Ntimes(f, x): return ntimes(f)(x) +# but this doesn't help us since 'ntimes' can only be defined +# using Ntimes (or a trick like the one used by CURRY). + + +# Arithmetic in Lambda Calculus +# +# We can perform simple arithmetic on the un-curried versions, e.g., +# Successor(Twice) = Thrice (2+1) +# Sum(Thrice, Twice) = Fivefold (3+2) +# Product(Thrice, Twice) = Sixfold (3*2) +# Power(Thrice, Twice) = Ninefold (3**2) +# +# First we define versions that need f and x arguments. +# They have funny argument forms so the final functions can +# use CURRY, which only works on functions of exactly 2 arguments. + +def SUCCESSOR(Ntimes, (f, x)): return f(Ntimes(f, x)) +def SUCCESSOR(Ntimes, (f, x)): return Ntimes(f, f(x)) # Same effect +def SUM(Ntimes, (Mtimes, (f, x))): return Ntimes(f, Mtimes(f, x)) +def PRODUCT(Ntimes, (Mtimes, (f, x))): return Ntimes(CURRY(Mtimes, f), x) +def POWER(Ntimes, (Mtimes, (f, x))): + return Mtimes(CURRY(CURRY, Ntimes), f)(x) + +def Successor(Ntimes): return CURRY(SUCCESSOR, Ntimes) +def Sum(Ntimes, Mtimes): return CURRY(CURRY(SUM, Ntimes), Mtimes) +def Product(Ntimes, Mtimes): return CURRY(CURRY(PRODUCT, Ntimes), Mtimes) +def Power(Ntimes, Mtimes): return CURRY(CURRY(POWER, Ntimes), Mtimes) + + +# Sorry, I don't have a clue on how to do subtraction or division... + + +# References +# +# All I know about lambda calculus is from Roger Penrose's +# The Emperor's New Mind, Chapter 2. + + +# P.S.: Here is a Lambda function in Python. +# It uses 'exec' and expects two strings to describe the arguments +# and the function expression. Example: +# lambda('x', 'x+1') +# defines the successor function. + +def lambda(args, expr): + if '\n' in args or '\n' in expr: + raise RuntimeError, 'lambda: no cheating!' + stmt = 'def func(' + args + '): return ' + expr + '\n' + print 'lambda:', stmt, + exec(stmt) + return func + + +# P.P.S.S.: Here is a way to construct Ntimes and ntimes directly. +# Example: +# GenericNtimes(4) +# is equivalent to Fourfold. + +class _GenericNtimesClass(): + def new(self, n): + self.n = n + return self + def Ntimes(self, (f, x)): + n = self.n + while n > 0: x, n = f(x), n-1 + return x + +def GenericNtimes(n): + return _GenericNtimesClass().new(n).Ntimes + + +# To construct any 'ntimes' function from the corresponding 'Ntimes', +# we use a trick as used by CURRY. For example, +# Ntimes2ntimes(Fourfold) +# yields a function equivalent to fourfold. + +class _Ntimes2ntimesClass(): + def new(self, Ntimes): + self.Ntimes = Ntimes + return self + def ntimes(self, f): + return CURRY(self.Ntimes, f) + +def Ntimes2ntimes(Ntimes): return _Ntimes2ntimesClass().new(Ntimes).ntimes + + +# This allows us to construct generic 'ntimes' functions. Example: +# generic_ntimes(3) +# is the same as thrice. + +def generic_ntimes(n): return Ntimes2ntimes(GenericNtimes(n)) diff --git a/lib/listwin.py b/lib/listwin.py new file mode 100644 index 0000000..aac127c --- /dev/null +++ b/lib/listwin.py @@ -0,0 +1,47 @@ +# Module 'listwin' +# List windows, a subclass of gwin + +import gwin +import stdwin + +def maxlinewidth(a): # Compute maximum textwidth of lines in a sequence + max = 0 + for line in a: + width = stdwin.textwidth(line) + if width > max: max = width + return max + +def action(w, string, i, detail): # Default item selection method + pass + +def mup(w, detail): # Mouse up method + (h, v), clicks, button, mask = detail + i = divmod(v, w.lineheight)[0] + if 0 <= i < len(w.data): + w.action(w, w.data[i], i, detail) + +def draw(w, ((left, top), (right, bottom))): # Text window draw method + data = w.data + d = w.begindrawing() + lh = w.lineheight + itop = top/lh + ibot = (bottom-1)/lh + 1 + if itop < 0: itop = 0 + if ibot > len(data): ibot = len(data) + for i in range(itop, ibot): d.text((0, i*lh), data[i]) + +def open(title, data): # Display a list of texts in a window + lineheight = stdwin.lineheight() + h, v = maxlinewidth(data), len(data)*lineheight + h0, v0 = h + stdwin.textwidth(' '), v + lineheight + if h0 > stdwin.textwidth(' ')*80: h0 = 0 + if v0 > stdwin.lineheight()*24: v0 = 0 + stdwin.setdefwinsize(h0, v0) + w = gwin.open(title) + w.setdocsize(h, v) + w.lineheight = lineheight + w.data = data + w.draw = draw + w.action = action + w.mup = mup + return w diff --git a/lib/localtime.py b/lib/localtime.py new file mode 100644 index 0000000..5ce6529 --- /dev/null +++ b/lib/localtime.py @@ -0,0 +1,53 @@ +# module localtime -- Time conversions + +import posix + +epoch = 1970 # 1 jan 00:00:00, UCT +day0 = 4 # day 0 was a thursday + +day_names = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat') + +month_names = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun') +month_names = month_names + ('Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec') + +month_sizes = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) + +def isleap(year): + return year % 4 = 0 and (year % 100 <> 0 or year % 400 = 0) + +def gmtime(secs): # decode time into UCT + mins, secs = divmod(secs, 60) + hours, mins = divmod(mins, 60) + days, hours = divmod(hours, 24) + wday = (day0 + days) % 7 + year = epoch + lp = isleap(year) + dpy = 365 + lp + while days >= dpy: + days = days - dpy + year = year + 1 + lp = isleap(year) + dpy = 365 + lp + yday = days + month = 0 + dpm = month_sizes[month] + (lp and month = 1) + while days >= dpm: + days = days - dpm + month = month + 1 + dpm = month_sizes[month] + (lp and month = 1) + return (year, month, days+1, hours, mins, secs, yday, wday) + +def dd(x): + s = `x` + while len(s) < 2: s = '0' + s + return s + +def zd(x): + s = `x` + while len(s) < 2: s = ' ' + s + return s + +def format(year, month, days, hours, mins, secs, yday, wday): + s = day_names[wday] + ' ' + zd(days) + ' ' + month_names[month] + ' ' + s = s + dd(hours) + ':' + dd(mins) + ':' + dd(secs) + return s diff --git a/lib/maccache.py b/lib/maccache.py new file mode 100644 index 0000000..329e514 --- /dev/null +++ b/lib/maccache.py @@ -0,0 +1,61 @@ +# Module 'maccache' +# +# Maintain a cache of listdir(), isdir(), isfile() or exists() outcomes. + +import mac +import macpath + + +# The cache. +# Keys are absolute pathnames; +# values are 0 (nothing), 1 (file) or [...] (dir). +# +cache = {} + + +# Current working directory. +# +cwd = mac.getcwd() + + +# Constants. +# +NONE = 0 +FILE = 1 +LISTTYPE = type([]) + +def _stat(name): + name = macpath.cat(cwd, name) + if cache.has_key(name): + return cache[name] + if macpath.isfile(name): + cache[name] = FILE + return FILE + try: + list = mac.listdir(name) + except: + cache[name] = NONE + return NONE + cache[name] = list + if name[-1:] = ':': cache[name[:-1]] = list + else: cache[name+':'] = list + return list + +def isdir(name): + st = _stat(name) + return type(st) = LISTTYPE + +def isfile(name): + st = _stat(name) + return st = FILE + +def exists(name): + st = _stat(name) + return st <> NONE + +def listdir(name): + st = _stat(name) + if type(st) = LISTTYPE: + return st + else: + raise RuntimeError, 'list non-directory' diff --git a/lib/macglob.py b/lib/macglob.py new file mode 100644 index 0000000..cad2c79 --- /dev/null +++ b/lib/macglob.py @@ -0,0 +1,46 @@ +# Module 'macglob' -- version of 'glob' for the Macintosh. + +# XXX At least one bug is left: a pattern like '*:' is treated +# XXX as a relative pathname (and returns as if it was ':*:'). + +import mac +import macpath +import fnmatch + +def glob(pathname): + if not has_magic(pathname): return [pathname] + dirname, basename = macpath.split(pathname) + if has_magic(dirname): + if dirname[-1:] = ':': dirname = dirname[:-1] + list = glob(dirname) + else: + list = [dirname] + if not has_magic(basename): + result = [] + for dirname in list: + if basename or macpath.isdir(dirname): + name = macpath.cat(dirname, basename) + if macpath.exists(name): + result.append(name) + else: + result = [] + for dirname in list: + sublist = glob1(dirname, basename) + for name in sublist: + result.append(macpath.cat(dirname, name)) + return result + +def glob1(dirname, pattern): + if not dirname: dirname = ':' + try: + names = mac.listdir(dirname) + except mac.error: + return [] + result = [] + for name in names: + if name[0] <> '.' or pattern[0] = '.': + if fnmatch.fnmatch(name, pattern): result.append(name) + return result + +def has_magic(s): + return '*' in s or '?' in s or '[' in s diff --git a/lib/macpath.py b/lib/macpath.py new file mode 100644 index 0000000..99ba6b8 --- /dev/null +++ b/lib/macpath.py @@ -0,0 +1,108 @@ +# module 'macpath' -- pathname (or -related) operations for the Macintosh + +import mac + +from stat import * + + +# Return true if a path is absolute. +# On the Mac, relative paths begin with a colon, +# but as a special case, paths with no colons at all are also relative. +# Anything else is absolute (the string up to the first colon is the +# volume name). + +def isabs(s): + return ':' in s and s[0] <> ':' + + +# Concatenate two pathnames. +# The result is equivalent to what the second pathname would refer to +# if the first pathname were the current directory. + +def cat(s, t): + if (not s) or isabs(t): return t + if t[:1] = ':': t = t[1:] + if ':' not in s: + s = ':' + s + if s[-1:] <> ':': + s = s + ':' + return s + t + + +# Split a pathname in two parts: the directory leading up to the final bit, +# and the basename (the filename, without colons, in that directory). +# The result (s, t) is such that cat(s, t) yields the original argument. + +def split(s): + if ':' not in s: return '', s + colon = 0 + for i in range(len(s)): + if s[i] = ':': colon = i+1 + return s[:colon], s[colon:] + + +# Normalize a pathname: get rid of '::' sequences by backing up, +# e.g., 'foo:bar::bletch' becomes 'foo:bletch'. +# Raise the exception norm_error below if backing up is impossible, +# e.g., for '::foo'. + +norm_error = 'macpath.norm_error: path cannot be normalized' + +def norm(s): + import string + if ':' not in s: + return ':' + s + f = string.splitfields(s, ':') + pre = [] + post = [] + if not f[0]: + pre = f[:1] + f = f[1:] + if not f[len(f)-1]: + post = f[-1:] + f = f[:-1] + res = [] + for seg in f: + if seg: + res.append(seg) + else: + if not res: raise norm_error, 'path starts with ::' + del res[len(res)-1] + if not (pre or res): + raise norm_error, 'path starts with volume::' + if pre: res = pre + res + if post: res = res + post + s = res[0] + for seg in res[1:]: + s = s + ':' + seg + return s + + +# Return true if the pathname refers to an existing directory. + +def isdir(s): + try: + st = mac.stat(s) + except mac.error: + return 0 + return S_ISDIR(st[ST_MODE]) + + +# Return true if the pathname refers to an existing regular file. + +def isfile(s): + try: + st = mac.stat(s) + except mac.error: + return 0 + return S_ISREG(st[ST_MODE]) + + +# Return true if the pathname refers to an existing file or directory. + +def exists(s): + try: + st = mac.stat(s) + except mac.error: + return 0 + return 1 diff --git a/lib/macshell.py b/lib/macshell.py new file mode 100644 index 0000000..c96d65b --- /dev/null +++ b/lib/macshell.py @@ -0,0 +1,399 @@ +# Macintosh 'shell' +# vi:set tabsize=4: + +# XXX string quoting in arguments +# XXX directory stack +# XXX $macros? +# XXX ^C during any command +# XXX 'sh' builtin command? +# XXX why does open require absolute path? (need to fix chdir.c) + + +import mac + +import macpath +import string +import glob +from macpath import isfile, isdir, exists +import TclUtil # For splitting/quoting mechanisms + +class Struct(): pass +G = Struct() + +def reset(): + G.debug = 0 + G.ps1 = '$ ' + G.homedir = mac.getcwd() + G.commands = mkcmdtab() + G.aliases = {} + +def mkcmdtab(): + tab = {} + tab['alias'] = do_alias + tab['cd'] = do_cd + tab['debug'] = do_debug + tab['grep'] = do_grep + tab['help'] = do_help + tab['ls'] = do_ls + tab['mkdir'] = do_mkdir + tab['mv'] = do_mv + tab['page'] = do_page + tab['pwd'] = do_pwd + tab['reset'] = do_reset + tab['rm'] = do_rm + tab['rmdir'] = do_rmdir + tab['sync'] = do_sync + tab['unalias'] = do_unalias + return tab + +def main(): + while 1: + try: + line = raw_input(G.ps1) + except EOFError: + print '[EOF]' + break + except KeyboardInterrupt: + print '[Intr]' + line = '' + if G.debug: + print 'line:', `line` + words = TclUtil.SplitList(line) + if G.debug: + print 'words:', words + if words and words[0][0] <> '#': + run(words) + +def run(words): + expandaliases(words) + cmd = words[0] + args = words[1:] + if G.commands.has_key(cmd): + if args: + try: + args = expandgloblist(args) + except glob_error, msg: + print cmd, ': glob error :', msg + return + G.commands[cmd](args) + return + if hasglobchar(cmd): + if args: + print cmd, ': cannot glob pattern with arguments' + return + try: + words = expandglobword(cmd) + except glob_error, msg: + print cmd, ': glob error :', msg + return + if len(words) > 1: + columnize(words) + return + cmd = words[0] + print cmd + if isfile(cmd): + if args: + print cmd, ': file command expects no arguments' + return + do_page([cmd]) + elif isdir(cmd): + if args: + print cmd, ': directory command expects no arguments' + return + do_cd([cmd]) + else: + print cmd, ': no such command, file or directory' + +glob_error = 'glob error' + +def expandgloblist(words): + res = [] + for word in words: + if hasglobchar(word): + res = res + expandglobword(word) + else: + res.append(word) + return res + +def expandglobword(word): + names = glob.globlist(mac.listdir(':'), word) + if not names: raise glob_error, 'no match for pattern ' + word + return names + +def hasglobchar(word): + return '*' in word or '?' in word + +def expandaliases(words): + seen = [] + cmd = words[0] + while cmd not in seen and G.aliases.has_key(cmd): + seen.append(cmd) + words[:1] = G.aliases[cmd] + cmd = words[0] + +def do_alias(args): + if not args: + listaliases() + elif len(args) = 1: + listalias(args[0]) + else: + defalias(args[0], args[1:]) + +def listaliases(): + names = G.aliases.keys() + names.sort() + for name in names: listalias(name) + +def listalias(name): + if not G.aliases.has_key(name): + print name, ': no such alias' + return + print 'alias', name, + printlist(G.aliases[name]) + print + +def defalias(name, expansion): + G.aliases[name] = expansion + +def do_cd(args): + if len(args) > 1: + print 'usage: cd [dirname]' + elif args: + chdirto(args[0]) + else: + chdirto(G.homedir) + +def chdirto(dirname): + try: + mac.chdir(dirname) + except mac.error, msg: + print dirname, ':', msg + return + +def do_debug(args): + G.debug = (not G.debug) + +def do_grep(args): + if len(args) < 2: + print 'usage: grep regexp file ...' + return + import regexp + try: + prog = regexp.compile(args[0]) + except regexp.error, msg: + print 'regexp.compile error for', args[0], ':', msg + return + for file in args[1:]: + grepfile(prog, file) + +def grepfile(prog, file): + try: + fp = open(file, 'r') + except RuntimeError, msg: + print file, ': cannot open :', msg + return + lineno = 0 + while 1: + line = fp.readline() + if not line: break + lineno = lineno+1 + if prog.exec(line): + print file+'('+`lineno`+'):', line, + +def do_help(args): + if args: + print 'usage: help' + return + names = G.commands.keys() + names.sort() + columnize(names) + +def do_ls(args): + if not args: + lsdir(':') + else: + for dirname in args: + lsdir(dirname) + +def lsdir(dirname): + if not isdir(dirname): + print dirname, ': no such directory' + return + names = mac.listdir(dirname) + lsfiles(names, dirname) + +def lsfiles(names, dirname): + names = names[:] # Make a copy so we can modify it + for i in range(len(names)): + name = names[i] + if G.debug: print i, name + if isdir(macpath.cat(dirname, name)): + names[i] = ':' + name + ':' + columnize(names) + +def columnize(list): + COLUMNS = 80-1 + n = len(list) + colwidth = maxwidth(list) + ncols = (COLUMNS + 1) / (colwidth + 1) + if ncols < 1: ncols = 1 + nrows = (n + ncols - 1) / ncols + for irow in range(nrows): + line = '' + for icol in range(ncols): + i = irow + nrows*icol + if 0 <= i < n: + word = list[i] + if i+nrows < n: + word = string.ljust(word, colwidth) + if icol > 0: + word = ' ' + word + line = line + word + print line + +def maxwidth(list): + width = 0 + for word in list: + if len(word) > width: + width = len(word) + return width + +def do_mv(args): + if len(args) <> 2: + print 'usage: mv src dst' + return + src, dst = args[0], args[1] + if not exists(src): + print src, ': source does not exist' + return + if exists(dst): + print src, ': destination already exists' + return + try: + mac.rename(src, dst) + except mac.error, msg: + print src, dst, ': rename failed:', msg + +def do_mkdir(args): + if not args: + print 'usage: mkdir name ...' + return + for name in args: + makedir(name) + +def makedir(name): + if exists(name): + print name, ': already exists' + return + try: + mac.mkdir(name, 0777) + except mac.error, msg: + print name, ': mkdir failed:', msg + +def do_page(args): + if not args: + print 'usage: page file ...' + return + for name in args: + pagefile(name) + +def pagefile(name): + if not isfile(name): + print name, ': no such file' + return + LINES = 24 - 1 + # For THINK C 3.0, make the path absolute: + # if not macpath.isabs(name): + # name = macpath.cat(mac.getcwd(), name) + try: + fp = open(name, 'r') + except: + print name, ': cannot open' + return + line = fp.readline() + while line: + for i in range(LINES): + print line, + line = fp.readline() + if not line: break + if line: + try: + more = raw_input('[more]') + except (EOFError, KeyboardInterrupt): + print + break + if string.strip(more)[:1] in ('q', 'Q'): + break + +def do_pwd(args): + if args: + print 'usage: pwd' + else: + print mac.getcwd() + +def do_reset(args): + if args: + print 'usage: reset' + else: + reset() + +def do_rm(args): + if not args: + print 'usage: rm file ...' + return + for name in args: + remove(name) + +def remove(name): + if not isfile(name): + print name, ': no such file' + return + try: + mac.unlink(name) + except mac.error, msg: + print name, ': unlink failed:', msg + +def do_rmdir(args): + if not args: + print 'usage: rmdir dir ...' + return + for name in args: + rmdir(name) + +def rmdir(name): + if not isdir(name): + print name, ': no such directory' + return + try: + mac.rmdir(name) + except mac.error, msg: + print name, ': rmdir failed:', msg + +def do_sync(args): + if args: + print 'usage: sync' + return + try: + mac.sync() + except mac.error, msg: + print 'sync failed:', msg + +def do_unalias(args): + if not args: + print 'usage: unalias name ...' + return + for name in args: + unalias(name) + +def unalias(name): + if not G.aliases.has_key(name): + print name, ': no such alias' + return + del G.aliases[name] + +def printlist(list): + for word in list: + print word, + +reset() +main() diff --git a/lib/minmax.py b/lib/minmax.py new file mode 100644 index 0000000..38e20d1 --- /dev/null +++ b/lib/minmax.py @@ -0,0 +1,6 @@ +# Module 'minmax' +# These are now built in functions. +# For compatibility, we export the builtins + +min = min +max = max diff --git a/lib/packmail.py b/lib/packmail.py new file mode 100644 index 0000000..40b5b7a --- /dev/null +++ b/lib/packmail.py @@ -0,0 +1,48 @@ +# Module 'packmail' -- create a shell script out of some files. + +import mac +import macpath +from stat import ST_MTIME + +# Pack one file +def pack(outfp, file, name): + fp = open(file, 'r') + outfp.write('sed "s/^X//" >' + name + ' <<"!"\n') + while 1: + line = fp.readline() + if not line: break + if line[-1:] <> '\n': + line = line + '\n' + outfp.write('X' + line) + outfp.write('!\n') + +# Pack some files from a directory +def packsome(outfp, dirname, names): + for name in names: + print name + file = macpath.cat(dirname, name) + pack(outfp, file, name) + +# Pack all files from a directory +def packall(outfp, dirname): + names = mac.listdir(dirname) + names.sort() + packsome(outfp, dirname, names) + +# Pack all files from a directory that are not older than a give one +def packnotolder(outfp, dirname, oldest): + names = mac.listdir(dirname) + oldest = macpath.cat(dirname, oldest) + st = mac.stat(oldest) + mtime = st[ST_MTIME] + todo = [] + for name in names: + print name, '...', + st = mac.stat(macpath.cat(dirname, name)) + if st[ST_MTIME] >= mtime: + print 'Yes.' + todo.append(name) + else: + print 'No.' + todo.sort() + packsome(outfp, dirname, todo) diff --git a/lib/panel.py b/lib/panel.py new file mode 100644 index 0000000..8b0b45c --- /dev/null +++ b/lib/panel.py @@ -0,0 +1,281 @@ +# Module 'panel' +# +# Support for the Panel library. +# Uses built-in module 'pnl'. +# Applciations should use 'panel.function' instead of 'pnl.function'; +# most 'pnl' functions are transparently exported by 'panel', +# but dopanel() is overridden and you have to use this version +# if you want to use callbacks. + + +import pnl + + +debug = 0 + + +# Test if an object is a list. +# +def is_list(x): + return type(x) = type([]) + + +# Reverse a list. +# +def reverse(list): + res = [] + for item in list: + res.insert(0, item) + return res + + +# Get an attribute of a list, which may itself be another list. +# Don't use 'prop' for name. +# +def getattrlist(list, name): + for item in list: + if item and is_list(item) and item[0] = name: + return item[1:] + return [] + + +# Get a property of a list, which may itself be another list. +# +def getproplist(list, name): + for item in list: + if item and is_list(item) and item[0] = 'prop': + if len(item) > 1 and item[1] = name: + return item[2:] + return [] + + +# Test if an actuator description contains the property 'end-of-group' +# +def is_endgroup(list): + x = getproplist(list, 'end-of-group') + return (x and x[0] = '#t') + + +# Neatly display an actuator definition given as S-expression +# the prefix string is printed before each line. +# +def show_actuator(prefix, a): + for item in a: + if not is_list(item): + print prefix, item + elif item and item[0] = 'al': + print prefix, 'Subactuator list:' + for a in item[1:]: + show_actuator(prefix + ' ', a) + elif len(item) = 2: + print prefix, item[0], '=>', item[1] + elif len(item) = 3 and item[0] = 'prop': + print prefix, 'Prop', item[1], '=>', + print item[2] + else: + print prefix, '?', item + + +# Neatly display a panel. +# +def show_panel(prefix, p): + for item in p: + if not is_list(item): + print prefix, item + elif item and item[0] = 'al': + print prefix, 'Actuator list:' + for a in item[1:]: + show_actuator(prefix + ' ', a) + elif len(item) = 2: + print prefix, item[0], '=>', item[1] + elif len(item) = 3 and item[0] = 'prop': + print prefix, 'Prop', item[1], '=>', + print item[2] + else: + print prefix, '?', item + + +# Exception raised by build_actuator or build_panel. +# +panel_error = 'panel error' + + +# Dummy callback used to initialize the callbacks. +# +def dummy_callback(arg): + pass + + +# Assign attributes to members of the target. +# Attribute names in exclist are ignored. +# The member name is the attribute name prefixed with the prefix. +# +def assign_members(target, attrlist, exclist, prefix): + for item in attrlist: + if is_list(item) and len(item) = 2 and item[0] not in exclist: + name, value = item[0], item[1] + ok = 1 + if value[0] in '-0123456789': + value = eval(value) + elif value[0] = '"': + value = value[1:-1] + elif value = 'move-then-resize': + # Strange default set by Panel Editor... + ok = 0 + else: + print 'unknown value', value, 'for', name + ok = 0 + if ok: + lhs = 'target.' + prefix + name + stmt = lhs + '=' + `value` + if debug: print 'exec', stmt + try: + exec(stmt + '\n') + except KeyboardInterrupt: # Don't catch this! + raise KeyboardInterrupt + except: + print 'assign failed:', stmt + + +# Build a real actuator from an actuator descriptior. +# Return a pair (actuator, name). +# +def build_actuator(descr): + namelist = getattrlist(descr, 'name') + if namelist: + # Assume it is a string + actuatorname = namelist[0][1:-1] + else: + actuatorname = '' + type = descr[0] + if type[:4] = 'pnl_': type = type[4:] + act = pnl.mkact(type) + act.downfunc = act.activefunc = act.upfunc = dummy_callback + # + assign_members(act, descr[1:], ['al', 'data', 'name'], '') + # + # Treat actuator-specific data + # + datalist = getattrlist(descr, 'data') + prefix = '' + if type[-4:] = 'puck': + prefix = 'puck_' + elif type = 'mouse': + prefix = 'mouse_' + assign_members(act, datalist, [], prefix) + # + return act, actuatorname + + +# Build all sub-actuators and add them to the super-actuator. +# The super-actuator must already have been added to the panel. +# Sub-actuators with defined names are added as members to the panel +# so they can be referenced as p.name. +# +# Note: I have no idea how panel.endgroup() works when applied +# to a sub-actuator. +# +def build_subactuators(panel, super_act, al): + # + # This is nearly the same loop as below in build_panel(), + # except a call is made to addsubact() instead of addact(). + # + for a in al: + act, name = build_actuator(a) + act.addsubact(super_act) + if name: + stmt = 'panel.' + name + ' = act' + if debug: print 'exec', stmt + exec(stmt + '\n') + if is_endgroup(a): + panel.endgroup() + sub_al = getattrlist(a, 'al') + if sub_al: + build_subactuators(panel, act, sub_al) + # + # Fix the actuator to which whe just added subactuators. + # This can't hurt (I hope) and is needed for the scroll actuator. + # + super_act.fixact() + + +# Build a real panel from a panel definition. +# Return a panel object p, where for each named actuator a, p.name is a +# reference to a. +# +def build_panel(descr): + # + # Sanity check + # + if (not descr) or descr[0] <> 'panel': + raise panel_error, 'panel description must start with "panel"' + # + if debug: show_panel('', descr) + # + # Create an empty panel + # + panel = pnl.mkpanel() + # + # Assign panel attributes + # + assign_members(panel, descr[1:], ['al'], '') + # + # Look for actuator list + # + al = getattrlist(descr, 'al') + # + # The order in which actuators are created is important + # because of the endgroup() operator. + # Unfortunately the Panel Editor outputs the actuator list + # in reverse order, so we reverse it here. + # + al = reverse(al) + # + for a in al: + act, name = build_actuator(a) + act.addact(panel) + if name: + stmt = 'panel.' + name + ' = act' + exec(stmt + '\n') + if is_endgroup(a): + panel.endgroup() + sub_al = getattrlist(a, 'al') + if sub_al: + build_subactuators(panel, act, sub_al) + # + return panel + + +# Wrapper around pnl.dopanel() which calls call-back functions. +# +def my_dopanel(): + # Extract only the first 4 elements to allow for future expansion + a, down, active, up = pnl.dopanel()[:4] + if down: + down.downfunc(down) + if active: + active.activefunc(active) + if up: + up.upfunc(up) + return a + + +# Create one or more panels from a description file (S-expressions) +# generated by the Panel Editor. +# +def defpanellist(file): + import panelparser + descrlist = panelparser.parse_file(open(file, 'r')) + panellist = [] + for descr in descrlist: + panellist.append(build_panel(descr)) + return panellist + + +# Import everything from built-in method pnl, so the user can always +# use panel.foo() instead of pnl.foo(). +# This gives *no* performance penalty once this module is imported. +# +from pnl import * # for export + +dopanel = my_dopanel # override pnl.dopanel diff --git a/lib/panelparser.py b/lib/panelparser.py new file mode 100644 index 0000000..5eb2f2b --- /dev/null +++ b/lib/panelparser.py @@ -0,0 +1,128 @@ +# Module 'parser' +# +# Parse S-expressions output by the Panel Editor +# (which is written in Scheme so it can't help writing S-expressions). +# +# See notes at end of file. + + +whitespace = ' \t\n' +operators = '()\'' +separators = operators + whitespace + ';' + '"' + + +# Tokenize a string. +# Return a list of tokens (strings). +# +def tokenize_string(s): + tokens = [] + while s: + c = s[:1] + if c in whitespace: + s = s[1:] + elif c = ';': + s = '' + elif c = '"': + n = len(s) + i = 1 + while i < n: + c = s[i] + i = i+1 + if c = '"': break + if c = '\\': i = i+1 + tokens.append(s[:i]) + s = s[i:] + elif c in operators: + tokens.append(c) + s = s[1:] + else: + n = len(s) + i = 1 + while i < n: + if s[i] in separators: break + i = i+1 + tokens.append(s[:i]) + s = s[i:] + return tokens + + +# Tokenize a whole file (given as file object, not as file name). +# Return a list of tokens (strings). +# +def tokenize_file(fp): + tokens = [] + while 1: + line = fp.readline() + if not line: break + tokens = tokens + tokenize_string(line) + return tokens + + +# Exception raised by parse_exr. +# +syntax_error = 'syntax error' + + +# Parse an S-expression. +# Input is a list of tokens as returned by tokenize_*(). +# Return a pair (expr, tokens) +# where expr is a list representing the s-expression, +# and tokens contains the remaining tokens. +# May raise syntax_error. +# +def parse_expr(tokens): + if (not tokens) or tokens[0] <> '(': + raise syntax_error, 'expected "("' + tokens = tokens[1:] + expr = [] + while 1: + if not tokens: + raise syntax_error, 'missing ")"' + if tokens[0] = ')': + return expr, tokens[1:] + elif tokens[0] = '(': + subexpr, tokens = parse_expr(tokens) + expr.append(subexpr) + else: + expr.append(tokens[0]) + tokens = tokens[1:] + + +# Parse a file (given as file object, not as file name). +# Return a list of parsed S-expressions found at the top level. +# +def parse_file(fp): + tokens = tokenize_file(fp) + exprlist = [] + while tokens: + expr, tokens = parse_expr(tokens) + exprlist.append(expr) + return exprlist + + +# EXAMPLE: +# +# The input +# '(hip (hop hur-ray))' +# +# passed to tokenize_string() returns the token list +# ['(', 'hip', '(', 'hop', 'hur-ray', ')', ')'] +# +# When this is passed to parse_expr() it returns the expression +# ['hip', ['hop', 'hur-ray']] +# plus an empty token list (because there are no tokens left. +# +# When a file containing the example is passed to parse_file() it returns +# a list whose only element is the output of parse_expr() above: +# [['hip', ['hop', 'hur-ray']]] + + +# TOKENIZING: +# +# Comments start with semicolon (;) and continue till the end of the line. +# +# Tokens are separated by whitespace, except the following characters +# always form a separate token (outside strings): +# ( ) ' +# Strings are enclosed in double quotes (") and backslash (\) is used +# as escape character in strings. diff --git a/lib/path.py b/lib/path.py new file mode 100644 index 0000000..be2340f --- /dev/null +++ b/lib/path.py @@ -0,0 +1,125 @@ +# Module 'path' -- common operations on POSIX pathnames + +import posix +import stat + + +# Intelligent pathname concatenation. +# Inserts a '/' unless the first part is empty or already ends in '/'. +# Ignores the first part altogether if the second part is absolute +# (begins with '/'). +# +def cat(a, b): + if b[:1] = '/': return b + if a = '' or a[-1:] = '/': return a + b + return a + '/' + b + + +# Split a path in head (empty or ending in '/') and tail (no '/'). +# The tail will be empty if the path ends in '/'. +# +def split(p): + head, tail = '', '' + for c in p: + tail = tail + c + if c = '/': + head, tail = head + tail, '' + return head, tail + + +# Return the tail (basename) part of a path. +# +def basename(p): + return split(p)[1] + + +# Return the longest prefix of all list elements. +# +def commonprefix(m): + if not m: return '' + prefix = m[0] + for item in m: + for i in range(len(prefix)): + if prefix[:i+1] <> item[:i+1]: + prefix = prefix[:i] + if i = 0: return '' + break + return prefix + + +# Does a file/directory exist? +# +def exists(path): + try: + st = posix.stat(path) + except posix.error: + return 0 + return 1 + + +# Is a path a posix directory? +# +def isdir(path): + try: + st = posix.stat(path) + except posix.error: + return 0 + return stat.S_ISDIR(st[stat.ST_MODE]) + + +# Is a path a symbolic link? +# This will always return false on systems where posix.lstat doesn't exist. +# +def islink(path): + try: + st = posix.lstat(path) + except (posix.error, NameError): + return 0 + return stat.S_ISLNK(st[stat.ST_MODE]) + + +_mounts = [] + +def _getmounts(): + import commands, string + mounts = [] + data = commands.getoutput('/etc/mount') + lines = string.splitfields(data, '\n') + for line in lines: + words = string.split(line) + if len(words) >= 3 and words[1] = 'on': + mounts.append(words[2]) + return mounts + + +# Is a path a mount point? +# This only works for normalized, absolute paths, +# and only if the mount table as printed by /etc/mount is correct. +# Sorry. +# +def ismount(path): + if not _mounts: + _mounts[:] = _getmounts() + return path in _mounts + + +# Directory tree walk. +# For each directory under top (including top itself), +# func(arg, dirname, filenames) is called, where dirname +# is the name of the directory and filenames is the list of +# files (and subdirectories etc.) in the directory. +# func may modify the filenames list, to implement a filter, +# or to impose a different order of visiting. +# +def walk(top, func, arg): + try: + names = posix.listdir(top) + except posix.error: + return + func(arg, top, names) + exceptions = ('.', '..') + for name in names: + if name not in exceptions: + name = cat(top, name) + if isdir(name): + walk(name, func, arg) diff --git a/lib/poly.py b/lib/poly.py new file mode 100644 index 0000000..a7c24ec --- /dev/null +++ b/lib/poly.py @@ -0,0 +1,55 @@ +# module 'poly' -- Polynomials + +# A polynomial is represented by a list of coefficients, e.g., +# [1, 10, 5] represents 1*x**0 + 10*x**1 + 5*x**2 (or 1 + 10x + 5x**2). +# There is no way to suppress internal zeros; trailing zeros are +# taken out by normalize(). + +def normalize(p): # Strip unnecessary zero coefficients + n = len(p) + while p: + if p[n-1]: return p[:n] + n = n-1 + return [] + +def plus(a, b): + if len(a) < len(b): a, b = b, a # make sure a is the longest + res = a[:] # make a copy + for i in range(len(b)): + res[i] = res[i] + b[i] + return normalize(res) + +def minus(a, b): + if len(a) < len(b): a, b = b, a # make sure a is the longest + res = a[:] # make a copy + for i in range(len(b)): + res[i] = res[i] - b[i] + return normalize(res) + +def one(power, coeff): # Representation of coeff * x**power + res = [] + for i in range(power): res.append(0) + return res + [coeff] + +def times(a, b): + res = [] + for i in range(len(a)): + for j in range(len(b)): + res = plus(res, one(i+j, a[i]*b[j])) + return res + +def power(a, n): # Raise polynomial a to the positive integral power n + if n = 0: return [1] + if n = 1: return a + if n/2*2 = n: + b = power(a, n/2) + return times(b, b) + return times(power(a, n-1), a) + +def der(a): # First derivative + res = a[1:] + for i in range(len(res)): + res[i] = res[i] * (i+1) + return res + +# Computing a primitive function would require rational arithmetic... diff --git a/lib/rand.py b/lib/rand.py new file mode 100644 index 0000000..0ca1a53 --- /dev/null +++ b/lib/rand.py @@ -0,0 +1,12 @@ +# Module 'rand' + +import whrandom + +def srand(seed): + whrandom.seed(seed%256, seed/256%256, seed/65536%256) + +def rand(): + return int(whrandom.random() * 32768.0) % 32768 + +def choice(seq): + return seq[rand() % len(seq)] diff --git a/lib/rect.py b/lib/rect.py new file mode 100644 index 0000000..8f61e11 --- /dev/null +++ b/lib/rect.py @@ -0,0 +1,88 @@ +# Module 'rect'. +# +# Operations on rectangles. +# There is some normalization: all results return the object 'empty' +# if their result would contain no points. + + +# Exception. +# +error = 'rect.error' + + +# The empty rectangle. +# +empty = (0, 0), (0, 0) + + +# Check if a rectangle is empty. +# +def is_empty((left, top), (right, bottom)): + return left >= right or top >= bottom + + +# Compute the intersection or two or more rectangles. +# This works with a list or tuple argument. +# +def intersect(list): + if not list: raise error, 'intersect called with empty list' + if is_empty(list[0]): return empty + (left, top), (right, bottom) = list[0] + for rect in list[1:]: + if is_empty(rect): + return empty + (l, t), (r, b) = rect + if left < l: left = l + if top < t: top = t + if right > r: right = r + if bottom > b: bottom = b + if is_empty((left, top), (right, bottom)): + return empty + return (left, top), (right, bottom) + + +# Compute the smallest rectangle containing all given rectangles. +# This works with a list or tuple argument. +# +def union(list): + (left, top), (right, bottom) = empty + for (l, t), (r, b) in list[1:]: + if not is_empty((l, t), (r, b)): + if l < left: left = l + if t < top: top = t + if r > right: right = r + if b > bottom: bottom = b + res = (left, top), (right, bottom) + if is_empty(res): + return empty + return res + + +# Check if a point is in a rectangle. +# +def pointinrect((h, v), ((left, top), (right, bottom))): + return left <= h < right and top <= v < bottom + + +# Return a rectangle that is dh, dv inside another +# +def inset(((left, top), (right, bottom)), (dh, dv)): + left = left + dh + top = top + dv + right = right - dh + bottom = bottom - dv + r = (left, top), (right, bottom) + if is_empty(r): + return empty + else: + return r + + +# Conversions between rectangles and 'geometry tuples', +# given as origin (h, v) and dimensions (width, height). +# +def rect2geom((left, top), (right, bottom)): + return (left, top), (right-left, bottom-top) + +def geom2rect((h, v), (width, height)): + return (h, v), (h+width, v+height) diff --git a/lib/selection.py b/lib/selection.py new file mode 100644 index 0000000..22a0ea9 --- /dev/null +++ b/lib/selection.py @@ -0,0 +1,72 @@ +# DAWKINS' BLIND WATCHMAKER -- "METHINKS IT IS LIKE A WEASEL" EXAMPLE +# +# Start with a random phrase. Successively: +# Breed a next generation by copying with small mutations. +# Choose the member of the next generation that most closely resembles +# the target phrase to start breeding the next generation. +# How many generations will it take before the target is reached? + +from whrandom import random + +# Parameters determining the problem space +Target = 'methinks it is like a weasel' +Alphabet = ' abcdefghijklmnopqrstuvwxyz' + +# Parameters to play with +GenerationSize = 100 +MutationChance = 1.0/28.0 + +IndexSet = range(len(Target)) # Used to speed up loops + +def choice(sequence): + n = len(sequence) + i = int(random() * float(n)) % n + return sequence[i] + +def random_phrase(): + phrase = '' + for i in IndexSet: + phrase = phrase + choice(Alphabet) + return phrase + +def mutate_phrase(phrase): + mutant = phrase + for i in range(int(0.5 + MutationChance*float(len(phrase)))): + i = choice(IndexSet) + c = choice(Alphabet) + mutant = mutant[:i] + c + mutant[i+1:] + #print `mutant` + return mutant + +def matching_factor(phrase): + factor = 0 + for i in IndexSet: + if phrase[i] = Target[i]: factor = factor + 1 + return factor + +def breed_generation(phrase): + generation = [phrase] + while len(generation) < GenerationSize: + generation.append(mutate_phrase(phrase)) + return generation + +def select_best(generation): + factor, selected = -1, '' + for phrase in generation: + f = matching_factor(phrase) + if f > factor: + factor, selected = f, phrase + return selected + +def main(): + gen = 0 + phrase = random_phrase() + print gen, `phrase` + while phrase <> Target: + next_generation = breed_generation(phrase) + #print next_generation + phrase = select_best(next_generation) + gen = gen+1 + print gen, `phrase` + +main() diff --git a/lib/shutil.py b/lib/shutil.py new file mode 100644 index 0000000..c01d889 --- /dev/null +++ b/lib/shutil.py @@ -0,0 +1,70 @@ +# Module 'shutil' -- utility functions usable in a shell-like program + +import posix +import path + +MODEBITS = 010000 # Lower 12 mode bits +# Change this to 01000 (9 mode bits) to avoid copying setuid etc. + +# Copy data from src to dst +# +def copyfile(src, dst): + fsrc = open(src, 'r') + fdst = open(dst, 'w') + while 1: + buf = fsrc.read(16*1024) + if not buf: break + fdst.write(buf) + +# Copy mode bits from src to dst +# +def copymode(src, dst): + st = posix.stat(src) + mode = divmod(st[0], MODEBITS)[1] + posix.chmod(dst, mode) + +# Copy all stat info (mode bits, atime and mtime) from src to dst +# +def copystat(src, dst): + st = posix.stat(src) + mode = divmod(st[0], MODEBITS)[1] + posix.chmod(dst, mode) + posix.utimes(dst, st[7:9]) + +# Copy data and mode bits ("cp src dst") +# +def copy(src, dst): + copyfile(src, dst) + copymode(src, dst) + +# Copy data and all stat info ("cp -p src dst") +# +def copy2(src, dst): + copyfile(src, dst) + copystat(src, dst) + +# Recursively copy a directory tree. +# The destination must not already exist. +# +def copytree(src, dst): + names = posix.listdir(src) + posix.mkdir(dst, 0777) + dot_dotdot = '.', '..' + for name in names: + if name not in dot_dotdot: + srcname = path.cat(src, name) + dstname = path.cat(dst, name) + #print 'Copying', srcname, 'to', dstname + try: + #if path.islink(srcname): + # linkto = posix.readlink(srcname) + # posix.symlink(linkto, dstname) + #elif path.isdir(srcname): + if path.isdir(srcname): + copytree(srcname, dstname) + else: + copy2(srcname, dstname) + # XXX What about devices, sockets etc.? + except posix.error, why: + print 'Could not copy', srcname, 'to', dstname, + print '(', why[1], ')' diff --git a/lib/stat.py b/lib/stat.py new file mode 100644 index 0000000..83855b6 --- /dev/null +++ b/lib/stat.py @@ -0,0 +1,57 @@ +# Module 'stat' + +# Defines constants and functions for interpreting stat/lstat struct +# as returned by posix.stat() and posix.lstat() (if it exists). + +# XXX This module may have to be adapted for UNIXoid systems whose +# <sys/stat.h> deviates from AT&T or BSD UNIX; their S_IF* constants +# may differ. + +# Suggested usage: from stat import * + +# Tuple indices for stat struct members + +ST_MODE = 0 +ST_INO = 1 +ST_DEV = 2 +ST_NLINK = 3 +ST_UID = 4 +ST_GID = 5 +ST_SIZE = 6 +ST_ATIME = 7 +ST_MTIME = 8 +ST_CTIME = 9 + +def S_IMODE(mode): + return mode%4096 +def S_IFMT(mode): + return mode - mode%4096 + +S_IFDIR = 0040000 +S_IFCHR = 0020000 +S_IFBLK = 0060000 +S_IFREG = 0100000 +S_IFIFO = 0010000 +S_IFLNK = 0120000 +S_IFSOCK = 0140000 + +def S_ISDIR(mode): + return S_IFMT(mode) = S_IFDIR + +def S_ISCHR(mode): + return S_IFMT(mode) = S_IFCHR + +def S_ISBLK(mode): + return S_IFMT(mode) = S_IFBLK + +def S_ISREG(mode): + return S_IFMT(mode) = S_IFREG + +def S_ISFIFO(mode): + return S_IFMT(mode) = S_IFIFO + +def S_ISLNK(mode): + return S_IFMT(mode) = S_IFLNK + +def S_ISSOCK(mode): + return S_IFMT(mode) = S_IFSOCK diff --git a/lib/statcache.py b/lib/statcache.py new file mode 100644 index 0000000..0eaf810 --- /dev/null +++ b/lib/statcache.py @@ -0,0 +1,86 @@ +# Module 'statcache' +# +# Maintain a cache of file stats. +# There are functions to reset the cache or to selectively remove items. + +import posix +from stat import * + +# The cache. +# Keys are pathnames, values are `posix.stat' outcomes. +# +cache = {} + + +# Stat a file, possibly out of the cache. +# +def stat(path): + if cache.has_key(path): + return cache[path] + cache[path] = ret = posix.stat(path) + return ret + + +# Reset the cache completely. +# Hack: to reset a global variable, we import this module. +# +def reset(): + import statcache + # Check that we really imported the same module + if cache is not statcache.cache: + raise 'sorry, statcache identity crisis' + statcache.cache = {} + + +# Remove a given item from the cache, if it exists. +# +def forget(path): + if cache.has_key(path): + del cache[path] + + +# Remove all pathnames with a given prefix. +# +def forget_prefix(prefix): + n = len(prefix) + for path in cache.keys(): + if path[:n] = prefix: + del cache[path] + + +# Forget about a directory and all entries in it, but not about +# entries in subdirectories. +# +def forget_dir(prefix): + if prefix[-1:] = '/' and prefix <> '/': + prefix = prefix[:-1] + forget(prefix) + if prefix[-1:] <> '/': + prefix = prefix + '/' + n = len(prefix) + for path in cache.keys(): + if path[:n] = prefix: + rest = path[n:] + if rest[-1:] = '/': rest = rest[:-1] + if '/' not in rest: + del cache[path] + + +# Remove all pathnames except with a given prefix. +# Normally used with prefix = '/' after a chdir(). +# +def forget_except_prefix(prefix): + n = len(prefix) + for path in cache.keys(): + if path[:n] <> prefix: + del cache[path] + + +# Check for directory. +# +def isdir(path): + try: + st = stat(path) + except posix.error: + return 0 + return S_ISDIR(st[ST_MODE]) diff --git a/lib/stdwinevents.py b/lib/stdwinevents.py new file mode 100644 index 0000000..fc1c1e7 --- /dev/null +++ b/lib/stdwinevents.py @@ -0,0 +1,46 @@ +# Module 'stdwinevents' -- Constants for stdwin event types +# +# Suggested usage: +# from stdwinevents import * + +# The function stdwin.getevent() returns a tuple containing: +# (type, window, detail) +# where detail may be <no value> or a value depending on type, see below: + +# Values for type: + +WE_NULL = 0 # not reported -- means 'no event' internally +WE_ACTIVATE = 1 # detail is <no object> +WE_CHAR = 2 # detail is the character +WE_COMMAND = 3 # detail is one of the WC_* constants below +WE_MOUSE_DOWN = 4 # detail is ((h, v), clicks, button, mask) +WE_MOUSE_MOVE = 5 # ditto +WE_MOUSE_UP = 6 # ditto +WE_MENU = 7 # detail is (menu, item) +WE_SIZE = 8 # detail is (width, height) [???] +WE_MOVE = 9 # not reported -- reserved for future use +WE_DRAW = 10 # detail is ((left, top), (right, bottom)) +WE_TIMER = 11 # detail is <no object> +WE_DEACTIVATE = 12 # detail is <no object> +WE_EXTERN = 13 # detail is <no object> +WE_KEY = 14 # detail is ??? +WE_LOST_SEL = 15 # detail is selection number +WE_CLOSE = 16 # detail is <no object> + +# Values for detail when type is WE_COMMAND: + +WC_CLOSE = 1 # user hit close box +WC_LEFT = 2 # left arrow key +WC_RIGHT = 3 # right arrow key +WC_UP = 4 # up arrow key +WC_DOWN = 5 # down arrow key +WC_CANCEL = 6 # not reported -- turned into KeyboardInterrupt +WC_BACKSPACE = 7 # backspace key +WC_TAB = 8 # tab key +WC_RETURN = 9 # return or enter key + +# Selection numbers + +WS_CLIPBOARD = 0 +WS_PRIMARY = 1 +WS_SECONDARY = 2 diff --git a/lib/stdwinsupport.py b/lib/stdwinsupport.py new file mode 100644 index 0000000..1a28072 --- /dev/null +++ b/lib/stdwinsupport.py @@ -0,0 +1,34 @@ +# Module 'stdwinsupport' + +import stdwin + +eventnames = ['null', 'activate', 'char', 'command'] +eventnames = eventnames + ['mouse_down', 'mouse_move', 'mouse_up', 'menu'] +eventnames = eventnames + ['size', 'move', 'draw', 'timer', 'deactivate'] + +we_null = 0 +we_activate = 1 +we_char = 2 +we_command = 3 +we_mouse_down = 4 +we_mouse_move = 5 +we_mouse_up = 6 +we_menu = 7 +we_size = 8 +we_move = 9 +we_draw = 10 +we_timer = 11 +we_deactivate = 12 + +commandnames = ['?', 'close', 'left', 'right', 'up', 'down', 'cancel'] +commandnames = commandnames + ['backspace', 'tab', 'return'] + +wc_close = 1 +wc_left = 2 +wc_right = 3 +wc_up = 4 +wc_down = 5 +wc_cancel = 6 # not reported -- turned into KeyboardInterrupt +wc_backspace = 7 +wc_tab = 8 +wc_return = 9 diff --git a/lib/string.py b/lib/string.py new file mode 100644 index 0000000..5262013 --- /dev/null +++ b/lib/string.py @@ -0,0 +1,129 @@ +# module 'string' -- A collection of string operations + +# XXX Some of these operations are incredibly slow and should be built in + +# Some strings for ctype-style character classification +whitespace = ' \t\n' +lowercase = 'abcdefghijklmnopqrstuvwxyz' +uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +letters = lowercase + uppercase +digits = '0123456789' +hexdigits = digits + 'abcdef' + 'ABCDEF' +octdigits = '01234567' + +# Case conversion helpers +_caseswap = {} +for i in range(26): + _caseswap[lowercase[i]] = uppercase[i] + _caseswap[uppercase[i]] = lowercase[i] +del i + +# convert UPPER CASE letters to lower case +def lower(s): + res = '' + for c in s: + if 'A' <= c <= 'Z': c = _caseswap[c] + res = res + c + return res + +# Convert lower case letters to UPPER CASE +def upper(s): + res = '' + for c in s: + if 'a' <= c <= 'z': c = _caseswap[c] + res = res + c + return res + +# Swap lower case letters and UPPER CASE +def swapcase(s): + res = '' + for c in s: + if 'a' <= c <= 'z' or 'A' <= c <= 'Z': c = _caseswap[c] + res = res + c + return res + +# Strip leading and trailing tabs and spaces +def strip(s): + i, j = 0, len(s) + while i < j and s[i] in whitespace: i = i+1 + while i < j and s[j-1] in whitespace: j = j-1 + return s[i:j] + +# Split a string into a list of space/tab-separated words +# NB: split(s) is NOT the same as splitfields(s, ' ')! +def split(s): + res = [] + i, n = 0, len(s) + while i < n: + while i < n and s[i] in whitespace: i = i+1 + if i = n: break + j = i + while j < n and s[j] not in whitespace: j = j+1 + res.append(s[i:j]) + i = j + return res + +# Split a list into fields separated by a given string +# NB: splitfields(s, ' ') is NOT the same as split(s)! +def splitfields(s, sep): + res = [] + ns = len(s) + nsep = len(sep) + i = j = 0 + while j+nsep <= ns: + if s[j:j+nsep] = sep: + res.append(s[i:j]) + i = j = j + nsep + else: + j = j + 1 + res.append(s[i:]) + return res + +# Find substring +index_error = 'substring not found in string.index' +def index(s, sub): + n = len(sub) + for i in range(len(s) + 1 - n): + if sub = s[i:i+n]: return i + raise index_error, (s, sub) + +# Convert string to integer +atoi_error = 'non-numeric argument to string.atoi' +def atoi(str): + s = str + if s[:1] in '+-': s = s[1:] + if not s: raise atoi_error, str + for c in s: + if c not in digits: raise atoi_error, str + return eval(str) + +# Left-justify a string +def ljust(s, width): + n = len(s) + if n >= width: return s + return s + ' '*(width-n) + +# Right-justify a string +def rjust(s, width): + n = len(s) + if n >= width: return s + return ' '*(width-n) + s + +# Center a string +def center(s, width): + n = len(s) + if n >= width: return s + return ' '*((width-n)/2) + s + ' '*(width -(width-n)/2) + +# Zero-fill a number, e.g., (12, 3) --> '012' and (-3, 3) --> '-03' +# Decadent feature: the argument may be a string or a number +# (Use of this is deprecated; it should be a string as with ljust c.s.) +def zfill(x, width): + if type(x) = type(''): s = x + else: s = `x` + n = len(s) + if n >= width: return s + sign = '' + if s[0] = '-': + sign, s = '-', s[1:] + return sign + '0'*(width-n) + s diff --git a/lib/sunaudio.py b/lib/sunaudio.py new file mode 100644 index 0000000..ed1b6e4 --- /dev/null +++ b/lib/sunaudio.py @@ -0,0 +1,54 @@ +# Module 'sunaudio' -- interpret sun audio headers + +import audio + +MAGIC = '.snd' + +error = 'sunaudio sound header conversion error' + + +# convert a 4-char value to integer + +def c2i(data): + if type(data) <> type('') or len(data) <> 4: + raise error, 'c2i: bad arg (not string[4])' + bytes = audio.chr2num(data) + for i in (1, 2, 3): + if bytes[i] < 0: + bytes[i] = bytes[i] + 256 + return ((bytes[0]*256 + bytes[1])*256 + bytes[2])*256 + bytes[3] + + +# read a sound header from an open file + +def gethdr(fp): + if fp.read(4) <> MAGIC: + raise error, 'gethdr: bad magic word' + hdr_size = c2i(fp.read(4)) + data_size = c2i(fp.read(4)) + encoding = c2i(fp.read(4)) + sample_rate = c2i(fp.read(4)) + channels = c2i(fp.read(4)) + excess = hdr_size - 24 + if excess < 0: + raise error, 'gethdr: bad hdr_size' + if excess > 0: + info = fp.read(excess) + else: + info = '' + return (data_size, encoding, sample_rate, channels, info) + + +# read and print the sound header of a named file + +def printhdr(file): + hdr = gethdr(open(file, 'r')) + data_size, encoding, sample_rate, channels, info = hdr + while info[-1:] = '\0': + info = info[:-1] + print 'File name: ', file + print 'Data size: ', data_size + print 'Encoding: ', encoding + print 'Sample rate:', sample_rate + print 'Channels: ', channels + print 'Info: ', `info` diff --git a/lib/tablewin.py b/lib/tablewin.py new file mode 100644 index 0000000..df06476 --- /dev/null +++ b/lib/tablewin.py @@ -0,0 +1,237 @@ +# Module 'tablewin' + +# Display a table, with per-item actions: + +# A1 | A2 | A3 | .... | AN +# B1 | B2 | B3 | .... | BN +# C1 | C2 | C3 | .... | CN +# .. | .. | .. | .... | .. +# Z1 | Z2 | Z3 | .... | ZN + +# Not all columns need to have the same length. +# The data structure is a list of columns; +# each column is a list of items. +# Each item is a pair of a string and an action procedure. +# The first item may be a column title. + +import stdwin +import gwin + +def open(title, data): # Public function to open a table window + # + # Set geometry parameters (one day, these may be changeable) + # + margin = stdwin.textwidth(' ') + lineheight = stdwin.lineheight() + # + # Geometry calculations + # + colstarts = [0] + totwidth = 0 + maxrows = 0 + for coldata in data: + # Height calculations + rows = len(coldata) + if rows > maxrows: maxrows = rows + # Width calculations + width = colwidth(coldata) + margin + totwidth = totwidth + width + colstarts.append(totwidth) + # + # Calculate document and window height + # + docwidth, docheight = totwidth, maxrows*lineheight + winwidth, winheight = docwidth, docheight + if winwidth > stdwin.textwidth('n')*100: winwidth = 0 + if winheight > stdwin.lineheight()*30: winheight = 0 + # + # Create the window + # + stdwin.setdefwinsize(winwidth, winheight) + w = gwin.open(title) + # + # Set properties and override methods + # + w.data = data + w.margin = margin + w.lineheight = lineheight + w.colstarts = colstarts + w.totwidth = totwidth + w.maxrows = maxrows + w.selection = (-1, -1) + w.lastselection = (-1, -1) + w.selshown = 0 + w.setdocsize(docwidth, docheight) + w.draw = draw + w.mup = mup + w.arrow = arrow + # + # Return + # + return w + +def update(w, data): # Change the data + # + # Hide selection + # + hidesel(w, w.begindrawing()) + # + # Get old geometry parameters + # + margin = w.margin + lineheight = w.lineheight + # + # Geometry calculations + # + colstarts = [0] + totwidth = 0 + maxrows = 0 + for coldata in data: + # Height calculations + rows = len(coldata) + if rows > maxrows: maxrows = rows + # Width calculations + width = colwidth(coldata) + margin + totwidth = totwidth + width + colstarts.append(totwidth) + # + # Calculate document and window height + # + docwidth, docheight = totwidth, maxrows*lineheight + # + # Set changed properties and change window size + # + w.data = data + w.colstarts = colstarts + w.totwidth = totwidth + w.maxrows = maxrows + w.change((0, 0), (10000, 10000)) + w.setdocsize(docwidth, docheight) + w.change((0, 0), (docwidth, docheight)) + # + # Show selection, or forget it if out of range + # + showsel(w, w.begindrawing()) + if not w.selshown: w.selection = (-1, -1) + +def colwidth(coldata): # Subroutine to calculate column width + maxwidth = 0 + for string, action in coldata: + width = stdwin.textwidth(string) + if width > maxwidth: maxwidth = width + return maxwidth + +def draw(w, ((left, top), (right, bottom))): # Draw method + ileft = whichcol(w, left) + iright = whichcol(w, right-1) + 1 + if iright > len(w.data): iright = len(w.data) + itop = divmod(top, w.lineheight)[0] + if itop < 0: itop = 0 + ibottom, remainder = divmod(bottom, w.lineheight) + if remainder: ibottom = ibottom + 1 + d = w.begindrawing() + if ileft <= w.selection[0] < iright: + if itop <= w.selection[1] < ibottom: + hidesel(w, d) + d.erase((left, top), (right, bottom)) + for i in range(ileft, iright): + col = w.data[i] + jbottom = len(col) + if ibottom < jbottom: jbottom = ibottom + h = w.colstarts[i] + v = itop * w.lineheight + for j in range(itop, jbottom): + string, action = col[j] + d.text((h, v), string) + v = v + w.lineheight + showsel(w, d) + +def mup(w, detail): # Mouse up method + (h, v), nclicks, button, mask = detail + icol = whichcol(w, h) + if 0 <= icol < len(w.data): + irow = divmod(v, w.lineheight)[0] + col = w.data[icol] + if 0 <= irow < len(col): + string, action = col[irow] + action(w, string, (icol, irow), detail) + +def whichcol(w, h): # Return column number (may be >= len(w.data)) + for icol in range(0, len(w.data)): + if h < w.colstarts[icol+1]: + return icol + return len(w.data) + +def arrow(w, type): + import stdwinsupport + S = stdwinsupport + if type = S.wc_left: + incr = -1, 0 + elif type = S.wc_up: + incr = 0, -1 + elif type = S.wc_right: + incr = 1, 0 + elif type = S.wc_down: + incr = 0, 1 + else: + return + icol, irow = w.lastselection + icol = icol + incr[0] + if icol < 0: icol = len(w.data)-1 + if icol >= len(w.data): icol = 0 + if 0 <= icol < len(w.data): + irow = irow + incr[1] + if irow < 0: irow = len(w.data[icol]) - 1 + if irow >= len(w.data[icol]): irow = 0 + else: + irow = 0 + if 0 <= icol < len(w.data) and 0 <= irow < len(w.data[icol]): + w.lastselection = icol, irow + string, action = w.data[icol][irow] + detail = (0, 0), 1, 1, 1 + action(w, string, (icol, irow), detail) + + +# Selection management +# TO DO: allow multiple selected entries + +def select(w, selection): # Public function to set the item selection + d = w.begindrawing() + hidesel(w, d) + w.selection = selection + showsel(w, d) + if w.selshown: lastselection = selection + +def hidesel(w, d): # Hide the selection, if shown + if w.selshown: invertsel(w, d) + +def showsel(w, d): # Show the selection, if hidden + if not w.selshown: invertsel(w, d) + +def invertsel(w, d): # Invert the selection, if valid + icol, irow = w.selection + if 0 <= icol < len(w.data) and 0 <= irow < len(w.data[icol]): + left = w.colstarts[icol] + right = w.colstarts[icol+1] + top = irow * w.lineheight + bottom = (irow+1) * w.lineheight + d.invert((left, top), (right, bottom)) + w.selshown = (not w.selshown) + + +# Demonstration + +def demo_action(w, string, (icol, irow), detail): # Action function for demo + select(w, (irow, icol)) + +def demo(): # Demonstration + da = demo_action # shorthand + col0 = [('a1', da), ('bbb1', da), ('c1', da)] + col1 = [('a2', da), ('bbb2', da)] + col2 = [('a3', da), ('b3', da), ('c3', da), ('d4', da), ('d5', da)] + col3 = [] + for i in range(1, 31): col3.append('xxx' + `i`, da) + data = [col0, col1, col2, col3] + w = open('tablewin.demo', data) + gwin.mainloop() + return w diff --git a/lib/tb.py b/lib/tb.py new file mode 100644 index 0000000..9f2c92c --- /dev/null +++ b/lib/tb.py @@ -0,0 +1,220 @@ +# Print tracebacks, with a dump of local variables. +# Also an interactive stack trace browser. + +import sys +try: + import mac + os = mac +except NameError: + import posix + os = posix +from stat import * +import string + +def br(): browser(sys.last_traceback) + +def tb(): printtb(sys.last_traceback) + +def browser(tb): + if not tb: + print 'No traceback.' + return + tblist = [] + while tb: + tblist.append(tb) + tb = tb.tb_next + ptr = len(tblist)-1 + tb = tblist[ptr] + while 1: + if tb <> tblist[ptr]: + tb = tblist[ptr] + print `ptr` + ':', + printtbheader(tb) + try: + line = raw_input('TB: ') + except KeyboardInterrupt: + print '\n[Interrupted]' + break + except EOFError: + print '\n[EOF]' + break + cmd = string.strip(line) + if cmd: + if cmd = 'quit': + break + elif cmd = 'list': + browserlist(tb) + elif cmd = 'up': + if ptr-1 >= 0: ptr = ptr-1 + else: print 'Bottom of stack.' + elif cmd = 'down': + if ptr+1 < len(tblist): ptr = ptr+1 + else: print 'Top of stack.' + elif cmd = 'locals': + printsymbols(tb.tb_frame.f_locals) + elif cmd = 'globals': + printsymbols(tb.tb_frame.f_globals) + elif cmd in ('?', 'help'): + browserhelp() + else: + browserexec(tb, cmd) + +def browserlist(tb): + filename = tb.tb_frame.f_code.co_filename + lineno = tb.tb_lineno + last = lineno + first = max(1, last-10) + for i in range(first, last+1): + if i = lineno: prefix = '***' + string.rjust(`i`, 4) + ':' + else: prefix = string.rjust(`i`, 7) + ':' + line = readfileline(filename, i) + if line[-1:] = '\n': line = line[:-1] + print prefix + line + +def browserexec(tb, cmd): + locals = tb.tb_frame.f_locals + globals = tb.tb_frame.f_globals + try: + exec(cmd+'\n', globals, locals) + except: + print '*** Exception:', + print sys.exc_type, + if sys.exc_value <> None: + print ':', sys.exc_value, + print + print 'Type help to get help.' + +def browserhelp(): + print + print ' This is the traceback browser. Commands are:' + print ' up : move one level up in the call stack' + print ' down : move one level down in the call stack' + print ' locals : print all local variables at this level' + print ' globals : print all global variables at this level' + print ' list : list source code around the failure' + print ' help : print help (what you are reading now)' + print ' quit : back to command interpreter' + print ' Typing any other 1-line statement will execute it' + print ' using the current level\'s symbol tables' + print + +def printtb(tb): + while tb: + print1tb(tb) + tb = tb.tb_next + +def print1tb(tb): + printtbheader(tb) + if tb.tb_frame.f_locals is not tb.tb_frame.f_globals: + printsymbols(tb.tb_frame.f_locals) + +def printtbheader(tb): + filename = tb.tb_frame.f_code.co_filename + lineno = tb.tb_lineno + info = '"' + filename + '"(' + `lineno` + ')' + line = readfileline(filename, lineno) + if line: + info = info + ': ' + string.strip(line) + print info + +def printsymbols(d): + keys = d.keys() + keys.sort() + for name in keys: + print ' ' + string.ljust(name, 12) + ':', + printobject(d[name], 4) + print + +def printobject(v, maxlevel): + if v = None: + print 'None', + elif type(v) in (type(0), type(0.0)): + print v, + elif type(v) = type(''): + if len(v) > 20: + print `v[:17] + '...'`, + else: + print `v`, + elif type(v) = type(()): + print '(', + printlist(v, maxlevel) + print ')', + elif type(v) = type([]): + print '[', + printlist(v, maxlevel) + print ']', + elif type(v) = type({}): + print '{', + printdict(v, maxlevel) + print '}', + else: + print v, + +def printlist(v, maxlevel): + n = len(v) + if n = 0: return + if maxlevel <= 0: + print '...', + return + for i in range(min(6, n)): + printobject(v[i], maxlevel-1) + if i+1 < n: print ',', + if n > 6: print '...', + +def printdict(v, maxlevel): + keys = v.keys() + n = len(keys) + if n = 0: return + if maxlevel <= 0: + print '...', + return + keys.sort() + for i in range(min(6, n)): + key = keys[i] + print `key` + ':', + printobject(v[key], maxlevel-1) + if i+1 < n: print ',', + if n > 6: print '...', + +_filecache = {} + +def readfileline(filename, lineno): + try: + stat = os.stat(filename) + except os.error, msg: + print 'Cannot stat', filename, '--', msg + return '' + cache_ok = 0 + if _filecache.has_key(filename): + cached_stat, lines = _filecache[filename] + if stat[ST_SIZE] = cached_stat[ST_SIZE] and \ + stat[ST_MTIME] = cached_stat[ST_MTIME]: + cache_ok = 1 + else: + print 'Stale cache entry for', filename + del _filecache[filename] + if not cache_ok: + lines = readfilelines(filename) + if not lines: + return '' + _filecache[filename] = stat, lines + if 0 <= lineno-1 < len(lines): + return lines[lineno-1] + else: + print 'Line number out of range, last line is', len(lines) + return '' + +def readfilelines(filename): + try: + fp = open(filename, 'r') + except: + print 'Cannot open', filename + return [] + lines = [] + while 1: + line = fp.readline() + if not line: break + lines.append(line) + if not lines: + print 'Empty file', filename + return lines diff --git a/lib/testall.py b/lib/testall.py new file mode 100644 index 0000000..d9fd7e5 --- /dev/null +++ b/lib/testall.py @@ -0,0 +1,416 @@ +# Module 'testall' +# +# Python test set, should exercise: +# - all lexical and grammatical constructs +# - all opcodes from "opcode.h" +# - all operations on all object types +# - all builtin functions +# Ideally also: +# - all possible exception situations (Thank God we've got 'try') +# - all boundary cases + + +TestFailed = 'testall -- test failed' # Exception + + +######################################################### +# Part 1. Test all lexical and grammatical constructs. +# This just tests whether the parser accepts them all. +######################################################### + +print '1. Parser' + +print '1.1 Tokens' + +print '1.1.1 Backslashes' + +# Backslash means line continuation: +x = 1 \ ++ 1 +if x <> 2: raise TestFailed, 'backslash for line continuation' + +# Backslash does not means continuation in comments :\ +x = 0 +if x <> 0: raise TestFailed, 'backslash ending comment' + +print '1.1.2 Number formats' + +if 0xff <> 255: raise TestFailed, 'hex number' +if 0377 <> 255: raise TestFailed, 'octal number' +x = 3.14 +x = 0.314 +x = 3e14 +x = 3E14 +x = 3e-14 + +print '1.2 Grammar' + +print 'single_input' # NEWLINE | simple_stmt | compound_stmt NEWLINE +# XXX can't test in a script -- this rule is only used when interactive + +print 'file_input' # (NEWLINE | stmt)* ENDMARKER +# Being tested as this very moment this very module + +print 'expr_input' # testlist NEWLINE +# XXX Hard to test -- used only in calls to input() + +print 'eval_input' # testlist ENDMARKER +x = eval('1, 0 or 1') + +print 'funcdef' # 'def' NAME parameters ':' suite +### parameters: '(' [fplist] ')' +### fplist: fpdef (',' fpdef)* +### fpdef: NAME | '(' fplist ')' +def f1(): pass +def f2(one_argument): pass +def f3(two, arguments): pass +def f4(two, (compound, (arguments))): pass + +### stmt: simple_stmt | compound_stmt +### simple_stmt: expr_stmt | print_stmt | pass_stmt | del_stmt | flow_stmt | import_stmt +# Tested below + +print 'expr_stmt' # (exprlist '=')* exprlist NEWLINE +1 +1, 2, 3 +x = 1 +x = 1, 2, 3 +x = y = z = 1, 2, 3 +x, y, z = 1, 2, 3 +abc = a, b, c = x, y, z = xyz = 1, 2, (3, 4) +# NB these variables are deleted below + +print 'print_stmt' # 'print' (test ',')* [test] NEWLINE +print 1, 2, 3 +print 1, 2, 3, +print +print 0 or 1, 0 or 1, +print 0 or 1 + +print 'del_stmt' # 'del' exprlist NEWLINE +del abc +del x, y, (z, xyz) + +print 'pass_stmt' # 'pass' NEWLINE +pass + +print 'flow_stmt' # break_stmt | return_stmt | raise_stmt +# Tested below + +print 'break_stmt' # 'break' NEWLINE +while 1: break + +print 'return_stmt' # 'return' [testlist] NEWLINE +def g1(): return +def g2(): return 1 +g1() +x = g2() + +print 'raise_stmt' # 'raise' expr [',' expr] NEWLINE +try: raise RuntimeError, 'just testing' +except RuntimeError: pass +try: raise KeyboardInterrupt +except KeyboardInterrupt: pass + +print 'import_stmt' # 'import' NAME (',' NAME)* NEWLINE | 'from' NAME 'import' ('*' | NAME (',' NAME)*) NEWLINE +[1] +import sys +[2] +import time, math +[3] +from time import sleep +[4] +from math import * +[5] +from sys import modules, path +[6] + +### compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef +# Tested below + +print 'if_stmt' # 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] +if 1: pass +if 1: pass +else: pass +if 0: pass +elif 0: pass +if 0: pass +elif 0: pass +elif 0: pass +elif 0: pass +else: pass + +print 'while_stmt' # 'while' test ':' suite ['else' ':' suite] +while 0: pass +while 0: pass +else: pass + +print 'for_stmt' # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] +[1] +for i in 1, 2, 3: pass +[2] +for i, j, k in (): pass +else: pass +[3] + +print 'try_stmt' # 'try' ':' suite (except_clause ':' suite)* ['finally' ':' suite] +### except_clause: 'except' [expr [',' expr]] +try: pass +try: 1/0 +except RuntimeError: pass +try: 1/0 +except EOFError: pass +except TypeError, msg: pass +except RuntimeError, msg: pass +except: pass +try: pass +finally: pass +try: 1/0 +except: pass +finally: pass + +print 'suite' # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT +if 1: pass +if 1: + pass +if 1: + # + # + # + pass + pass + # + pass + # + +print 'test' # and_test ('or' and_test)* +### and_test: not_test ('and' not_test)* +### not_test: 'not' not_test | comparison +### comparison: expr (comp_op expr)* +### comp_op: '<'|'>'|'='|'>' '='|'<' '='|'<' '>'|'in'|'not' 'in'|'is'|'is' 'not' +if 1: pass +if 1 = 1: pass +if 1 < 1 > 1 = 1 >= 1 <= 1 <> 1 in 1 not in 1 is 1 is not 1: pass +if not 1 = 1 = 1: pass +if not 1 = 1 and 1 and 1: pass +if 1 and 1 or 1 and 1 and 1 or not 1 = 1 = 1 and 1: pass + +print 'expr' # term (('+'|'-') term)* +x = 1 +x = 1 + 1 +x = 1 - 1 - 1 +x = 1 - 1 + 1 - 1 + 1 + +print 'term' # factor (('*'|'/'|'%') factor)* +x = 1 * 1 +x = 1 / 1 +x = 1 % 1 +x = 1 / 1 * 1 % 1 + +print 'factor' # ('+'|'-') factor | atom trailer* +### trailer: '(' [testlist] ')' | '[' subscript ']' | '.' NAME +### subscript: expr | [expr] ':' [expr] +x = +1 +x = -1 +x = 1 +c = sys.path[0] +x = time.time() +x = sys.modules['time'].time() +a = '01234' +c = a[0] +c = a[0:5] +c = a[:5] +c = a[0:] +c = a[:] +c = a[-5:] +c = a[:-1] +c = a[-4:-3] + +print 'atom' # '(' [testlist] ')' | '[' [testlist] ']' | '{' '}' | '`' testlist '`' | NAME | NUMBER | STRING +x = (1) +x = (1 or 2 or 3) +x = (1 or 2 or 3, 2, 3) +x = [] +x = [1] +x = [1 or 2 or 3] +x = [1 or 2 or 3, 2, 3] +x = [] +x = {} +x = `x` +x = x +x = 'x' +x = 123 + +### exprlist: expr (',' expr)* [','] +### testlist: test (',' test)* [','] +# These have been exercised enough above + +print 'classdef' # 'class' NAME parameters ['=' baselist] ':' suite +### baselist: atom arguments (',' atom arguments)* +### arguments: '(' [testlist] ')' +class B(): pass +class C1() = B(): pass +class C2() = B(): pass +class D() = C1(), C2(), B(): pass +class C(): + def meth1(self): pass + def meth2(self, arg): pass + def meth3(self, (a1, a2)): pass + + +######################################################### +# Part 2. Test all opcodes from "opcode.h" +######################################################### + +print '2. Opcodes' +print 'XXX Not yet fully implemented' + +print '2.1 try inside for loop' +n = 0 +for i in range(10): + n = n+i + try: 1/0 + except NameError: pass + except RuntimeError: pass + except TypeError: pass + finally: pass + try: pass + except: pass + try: pass + finally: pass + n = n+i +if n <> 90: + raise TestFailed, 'try inside for' + + +######################################################### +# Part 3. Test all operations on all object types +######################################################### + +print '3. Object types' +print 'XXX Not yet implemented' + + +######################################################### +# Part 4. Test all built-in functions +######################################################### + +print '4. Built-in functions' + +print 'abs' +if abs(0) <> 0: raise TestFailed, 'abs(0)' +if abs(1234) <> 1234: raise TestFailed, 'abs(1234)' +if abs(-1234) <> 1234: raise TestFailed, 'abs(-1234)' +if abs(0.0) <> 0.0: raise TestFailed, 'abs(0.0)' +if abs(3.14) <> 3.14: raise TestFailed, 'abs(3.14)' +if abs(-3.14) <> 3.14: raise TestFailed, 'abs(-3.14)' + +print 'dir' +if 'x' not in dir(): raise TestFailed, 'dir()' +if 'modules' not in dir(sys): raise TestFailed, 'dir(sys)' + +print 'divmod' +if divmod(12, 7) <> (1, 5): raise TestFailed, 'divmod(12, 7)' +if divmod(-12, 7) <> (-2, 2): raise TestFailed, 'divmod(-12, 7)' +if divmod(12, -7) <> (-2, -2): raise TestFailed, 'divmod(12, -7)' +if divmod(-12, -7) <> (1, -5): raise TestFailed, 'divmod(-12, -7)' + +print 'eval' +if eval('1+1') <> 2: raise TestFailed, 'eval(\'1+1\')' + +print 'exec' +exec('z=1+1\n') +if z <> 2: raise TestFailed, 'exec(\'z=1+1\'\\n)' + +print 'float' +if float(3.14) <> 3.14: raise TestFailed, 'float(3.14)' +if float(314) <> 314.0: raise TestFailed, 'float(314)' + +print 'input' +# Can't test in a script + +print 'int' +if int(100) <> 100: raise TestFailed, 'int(100)' +if int(3.14) <> 3: raise TestFailed, 'int(3.14)' + +print 'len' +if len('123') <> 3: raise TestFailed, 'len(\'123\')' +if len(()) <> 0: raise TestFailed, 'len(())' +if len((1, 2, 3, 4)) <> 4: raise TestFailed, 'len((1, 2, 3, 4))' +if len([1, 2, 3, 4]) <> 4: raise TestFailed, 'len([1, 2, 3, 4])' +if len({}) <> 0: raise TestFailed, 'len({})' + +print 'min' +if min('123123') <> '1': raise TestFailed, 'min(\'123123\')' +if min(1, 2, 3) <> 1: raise TestFailed, 'min(1, 2, 3)' +if min((1, 2, 3, 1, 2, 3)) <> 1: raise TestFailed, 'min((1, 2, 3, 1, 2, 3))' +if min([1, 2, 3, 1, 2, 3]) <> 1: raise TestFailed, 'min([1, 2, 3, 1, 2, 3])' + +print 'max' +if max('123123') <> '3': raise TestFailed, 'max(\'123123\')' +if max(1, 2, 3) <> 3: raise TestFailed, 'max(1, 2, 3)' +if max((1, 2, 3, 1, 2, 3)) <> 3: raise TestFailed, 'max((1, 2, 3, 1, 2, 3))' +if max([1, 2, 3, 1, 2, 3]) <> 3: raise TestFailed, 'max([1, 2, 3, 1, 2, 3])' + +print 'open' +print 'NB! This test creates a file named "@test" in the current directory.' +fp = open('@test', 'w') +fp.write('The quick brown fox jumps over the lazy dog') +fp.write('.\n') +fp.write('Dear John\n') +fp.write('XXX'*100) +fp.write('YYY'*100) +fp.close() +del fp +fp = open('@test', 'r') +if fp.readline() <> 'The quick brown fox jumps over the lazy dog.\n': + raise TestFailed, 'readline()' +if fp.readline(4) <> 'Dear': raise TestFailed, 'readline(4) # short' +if fp.readline(100) <> ' John\n': raise TestFailed, 'readline(100)' +if fp.read(300) <> 'XXX'*100: raise TestFailed, 'read(300)' +if fp.read(1000) <> 'YYY'*100: raise TestFailed, 'read(1000) # truncate' +fp.close() +del fp + +print 'range' +if range(3) <> [0, 1, 2]: raise TestFailed, 'range(3)' +if range(1, 5) <> [1, 2, 3, 4]: raise TestFailed, 'range(1, 5)' +if range(0) <> []: raise TestFailed, 'range(0)' +if range(-3) <> []: raise TestFailed, 'range(-3)' +if range(1, 10, 3) <> [1, 4, 7]: raise TestFailed, 'range(1, 10, 3)' +if range(5, -5, -3) <> [5, 2, -1, -4]: raise TestFailed, 'range(5, -5, -3)' + +print 'raw_input' +savestdin = sys.stdin +try: + sys.stdin = open('@test', 'r') + if raw_input() <> 'The quick brown fox jumps over the lazy dog.': + raise TestFailed, 'raw_input()' + if raw_input('testing\n') <> 'Dear John': + raise TestFailed, 'raw_input(\'testing\\n\')' +finally: + sys.stdin = savestdin + +print 'reload' +import string +reload(string) + +print 'type' +if type('') <> type('123') or type('') = type(()): + raise TestFailed, 'type()' + + +print 'Passed all tests.' + +try: + import mac + unlink = mac.unlink +except NameError: + try: + import posix + unlink = posix.unlink + except NameError: + pass + +unlink('@test') +print 'Unlinked @test' diff --git a/lib/textwin.py b/lib/textwin.py new file mode 100644 index 0000000..d12342f --- /dev/null +++ b/lib/textwin.py @@ -0,0 +1,119 @@ +# Module 'textwin' + +# Text windows, a subclass of gwin + +import stdwin +import stdwinsupport +import gwin + +S = stdwinsupport # Shorthand + + +def fixsize(w): + docwidth, docheight = w.text.getrect()[1] + winheight = w.getwinsize()[1] + if winheight > docheight: docheight = winheight + w.setdocsize(0, docheight) + fixeditmenu(w) + +def cut(w, m, id): + s = w.text.getfocustext() + if s: + stdwin.setcutbuffer(0, s) + w.text.replace('') + fixsize(w) + +def copy(w, m, id): + s = w.text.getfocustext() + if s: + stdwin.setcutbuffer(0, s) + fixeditmenu(w) + +def paste(w, m, id): + w.text.replace(stdwin.getcutbuffer(0)) + fixsize(w) + +def addeditmenu(w): + m = w.editmenu = w.menucreate('Edit') + m.action = [] + m.additem('Cut', 'X') + m.action.append(cut) + m.additem('Copy', 'C') + m.action.append(copy) + m.additem('Paste', 'V') + m.action.append(paste) + +def fixeditmenu(w): + m = w.editmenu + f = w.text.getfocus() + can_copy = (f[0] < f[1]) + m.enable(1, can_copy) + if not w.readonly: + m.enable(0, can_copy) + m.enable(2, (stdwin.getcutbuffer(0) <> '')) + +def draw(w, area): # Draw method + w.text.draw(area) + +def size(w, newsize): # Size method + w.text.move((0, 0), newsize) + fixsize(w) + +def close(w): # Close method + del w.text # Break circular ref + gwin.close(w) + +def char(w, c): # Char method + w.text.replace(c) + fixsize(w) + +def backspace(w): # Backspace method + void = w.text.event(S.we_command, w, S.wc_backspace) + fixsize(w) + +def arrow(w, detail): # Arrow method + w.text.arrow(detail) + fixeditmenu(w) + +def mdown(w, detail): # Mouse down method + void = w.text.event(S.we_mouse_down, w, detail) + fixeditmenu(w) + +def mmove(w, detail): # Mouse move method + void = w.text.event(S.we_mouse_move, w, detail) + +def mup(w, detail): # Mouse up method + void = w.text.event(S.we_mouse_up, w, detail) + fixeditmenu(w) + +def activate(w): # Activate method + fixeditmenu(w) + +def open(title, str): # Display a string in a window + w = gwin.open(title) + w.readonly = 0 + w.text = w.textcreate((0, 0), w.getwinsize()) + w.text.replace(str) + w.text.setfocus(0, 0) + addeditmenu(w) + fixsize(w) + w.draw = draw + w.size = size + w.close = close + w.mdown = mdown + w.mmove = mmove + w.mup = mup + w.char = char + w.backspace = backspace + w.arrow = arrow + w.activate = activate + return w + +def open_readonly(title, str): # Same with char input disabled + w = open(title, str) + w.readonly = 1 + w.char = w.backspace = gwin.nop + # Disable Cut and Paste menu item; leave Copy alone + w.editmenu.enable(0, 0) + w.editmenu.enable(2, 0) + return w diff --git a/lib/util.py b/lib/util.py new file mode 100644 index 0000000..0b7778f --- /dev/null +++ b/lib/util.py @@ -0,0 +1,30 @@ +# Module 'util' -- some useful functions that don't fit elsewhere + + +# Remove an item from a list. +# No complaints if it isn't in the list at all. +# If it occurs more than once, remove the first occurrence. +# +def remove(item, list): + for i in range(len(list)): + if list[i] = item: + del list[i] + break + + +# Return a string containing a file's contents. +# +def readfile(fn): + return readopenfile(open(fn, 'r')) + + +# Read an open file until EOF. +# +def readopenfile(fp): + BUFSIZE = 512*8 + data = '' + while 1: + buf = fp.read(BUFSIZE) + if not buf: break + data = data + buf + return data diff --git a/lib/whrandom.py b/lib/whrandom.py new file mode 100644 index 0000000..ee8dc67 --- /dev/null +++ b/lib/whrandom.py @@ -0,0 +1,74 @@ +# WICHMANN-HILL RANDOM NUMBER GENERATOR +# +# Wichmann, B. A. & Hill, I. D. (1982) +# Algorithm AS 183: +# An efficient and portable pseudo-random number generator +# Applied Statistics 31 (1982) 188-190 +# +# see also: +# Correction to Algorithm AS 183 +# Applied Statistics 33 (1984) 123 +# +# McLeod, A. I. (1985) +# A remark on Algorithm AS 183 +# Applied Statistics 34 (1985),198-200 +# +# +# USE: +# whrandom.random() yields double precision random numbers +# uniformly distributed between 0 and 1. +# +# whrandom.seed() must be called before whrandom.random() +# to seed the generator + + +# Translated by Guido van Rossum from C source provided by +# Adrian Baddeley. + + +# The seed +# +_seed = [0, 0, 0] + + +# Set the seed +# +def seed(x, y, z): + _seed[:] = [x, y, z] + + +# Return the next random number in the range [0.0 .. 1.0) +# +def random(): + from math import floor # floor() function + # + [x, y, z] = _seed + x = 171 * (x % 177) - 2 * (x/177) + y = 172 * (y % 176) - 35 * (y/176) + z = 170 * (z % 178) - 63 * (z/178) + # + if x < 0: x = x + 30269 + if y < 0: y = y + 30307 + if z < 0: z = z + 30323 + # + _seed[:] = [x, y, z] + # + term = float(x)/30269.0 + float(y)/30307.0 + float(z)/30323.0 + rand = term - floor(term) + # + if rand >= 1.0: rand = 0.0 # floor() inaccuracy? + # + return rand + + +# Initialize from the current time +# +def init(): + import time + t = time.time() + seed(t%256, t/256%256, t/65536%256) + + +# Make sure the generator is preset to a nonzero value +# +init() diff --git a/lib/zmod.py b/lib/zmod.py new file mode 100644 index 0000000..3b38df9 --- /dev/null +++ b/lib/zmod.py @@ -0,0 +1,94 @@ +# module 'zmod' + +# Compute properties of mathematical "fields" formed by taking +# Z/n (the whole numbers modulo some whole number n) and an +# irreducible polynomial (i.e., a polynomial with only complex zeros), +# e.g., Z/5 and X**2 + 2. +# +# The field is formed by taking all possible linear combinations of +# a set of d base vectors (where d is the degree of the polynomial). +# +# Note that this procedure doesn't yield a field for all combinations +# of n and p: it may well be that some numbers have more than one +# inverse and others have none. This is what we check. +# +# Remember that a field is a ring where each element has an inverse. +# A ring has commutative addition and multiplication, a zero and a one: +# 0*x = x*0 = 0, 0+x = x+0 = x, 1*x = x*1 = x. Also, the distributive +# property holds: a*(b+c) = a*b + b*c. +# (XXX I forget if this is an axiom or follows from the rules.) + +import poly + + +# Example N and polynomial + +N = 5 +P = poly.plus(poly.one(0, 2), poly.one(2, 1)) # 2 + x**2 + + +# Return x modulo y. Returns >= 0 even if x < 0. + +def mod(x, y): + return divmod(x, y)[1] + + +# Normalize a polynomial modulo n and modulo p. + +def norm(a, n, p): + a = poly.modulo(a, p) + a = a[:] + for i in range(len(a)): a[i] = mod(a[i], n) + a = poly.normalize(a) + return a + + +# Make a list of all n^d elements of the proposed field. + +def make_all(mat): + all = [] + for row in mat: + for a in row: + all.append(a) + return all + +def make_elements(n, d): + if d = 0: return [poly.one(0, 0)] + sub = make_elements(n, d-1) + all = [] + for a in sub: + for i in range(n): + all.append(poly.plus(a, poly.one(d-1, i))) + return all + +def make_inv(all, n, p): + x = poly.one(1, 1) + inv = [] + for a in all: + inv.append(norm(poly.times(a, x), n, p)) + return inv + +def checkfield(n, p): + all = make_elements(n, len(p)-1) + inv = make_inv(all, n, p) + all1 = all[:] + inv1 = inv[:] + all1.sort() + inv1.sort() + if all1 = inv1: print 'BINGO!' + else: + print 'Sorry:', n, p + print all + print inv + +def rj(s, width): + if type(s) <> type(''): s = `s` + n = len(s) + if n >= width: return s + return ' '*(width - n) + s + +def lj(s, width): + if type(s) <> type(''): s = `s` + n = len(s) + if n >= width: return s + return s + ' '*(width - n) diff --git a/python.man b/python.man new file mode 100644 index 0000000..f222b55 --- /dev/null +++ b/python.man @@ -0,0 +1,79 @@ +.TH PYTHON "19 February 1991" +.SH NAME +python \(en an extensible interpreted programming language +.SH SYNOPSIS +.B python +[ +.I X11-options +] [ +.I script +[ +.I arguments +] ] +.SH DESCRIPTION +Python is an extensible interpreted programming language that +combines remarkable power with very clear syntax. +For an introduction to programming in Python you are referred to the +Python Tutorial. +.PP +The interpreter operates somewhat like the UNIX shell: when called with +standard input connected to a tty device, it reads and executes commands +interactively until an EOF is read; +when called with a file name argument or with a file as standard +input, it reads and executes a +.I script +from that file. +If available, the script name and additional arguments thereafter are +passed to the script in the variable +.I sys.argv , +which is a list of strings. +In interactive mode, the primary prompt is `>>>'; the second prompt +(which appears when a command is not complete) is `...'. +.SH FILES AND DIRECTORIES +.IP /usr/local/lib/python +This might be the directory containing the library of standard modules. +(Installation-dependent.) +.SH ENVIRONMENT VARIABLES +.IP PYTHONPATH +Sets the search path for module files. +The format is the same as the shell's $PATH: one or more directory +pathnames separated by colons. +Non-existant directories are silently ignored. +The default search path is installation dependent, but always begins +with `.', (for example, +.I .:/usr/local/lib/python ). +.SH SEE ALSO +Python Tutorial +.br +Python Library Reference +.SH AUTHOR +.nf +Guido van Rossum +CWI, dept. CST +Kruislaan 413 +1098 SJ Amsterdam +The Netherlands +.PP +E-mail: [email protected] +.fi +.SH COPYRIGHT +Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +Netherlands. +.IP " " +All Rights Reserved +.PP +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. diff --git a/shar/python-0.9.1-01-21.shar b/shar/python-0.9.1-01-21.shar new file mode 100644 index 0000000..75c124e --- /dev/null +++ b/shar/python-0.9.1-01-21.shar @@ -0,0 +1,1952 @@ +: This is a shell archive. +: Extract with 'sh this_file'. +: Extract this part first since it makes all directories +echo 'Start of pack.out, part 01 out of 21:' +echo -n 'Making directories ... ' +err="no" +test -d 'demo' || mkdir 'demo' || err="yes" +test -d 'demo/scripts' || mkdir 'demo/scripts' || err="yes" +test -d 'demo/sgi' || mkdir 'demo/sgi' || err="yes" +test -d 'demo/sgi/audio' || mkdir 'demo/sgi/audio' || err="yes" +test -d 'demo/sgi/audio_stdwin' || mkdir 'demo/sgi/audio_stdwin' || err="yes" +test -d 'demo/sgi/gl' || mkdir 'demo/sgi/gl' || err="yes" +test -d 'demo/sgi/gl_panel' || mkdir 'demo/sgi/gl_panel' || err="yes" +test -d 'demo/sgi/gl_panel/apanel' || mkdir 'demo/sgi/gl_panel/apanel' || err="yes" +test -d 'demo/sgi/gl_panel/flying' || mkdir 'demo/sgi/gl_panel/flying' || err="yes" +test -d 'demo/sgi/gl_panel/nurbs' || mkdir 'demo/sgi/gl_panel/nurbs' || err="yes" +test -d 'demo/sgi/gl_panel/twoview' || mkdir 'demo/sgi/gl_panel/twoview' || err="yes" +test -d 'demo/stdwin' || mkdir 'demo/stdwin' || err="yes" +test -d 'doc' || mkdir 'doc' || err="yes" +test -d 'lib' || mkdir 'lib' || err="yes" +test -d 'src' || mkdir 'src' || err="yes" +echo 'done' +if test "$err" = "yes" +then echo "didn't make it." +fi +if test -s 'README' +then echo '*** I will not over-write existing file README' +else +echo 'x - README' +sed 's/^X//' > 'README' << 'EOF' +XThis is Python, an extensible interpreted programming language that +Xcombines remarkable power with very clear syntax. +X +XThis is version 0.9 (the first beta release), patchlevel 1. +X +XPython can be used instead of shell, Awk or Perl scripts, to write +Xprototypes of real applications, or as an extension language of large +Xsystems, you name it. There are built-in modules that interface to +Xthe operating system and to various window systems: X11, the Mac +Xwindow system (you need STDWIN for these two), and Silicon Graphics' +XGL library. It runs on most modern versions of UNIX, on the Mac, and +XI wouldn't be surprised if it ran on MS-DOS unchanged. I developed it +Xmostly on an SGI IRIS workstation (using IRIX 3.1 and 3.2) and on the +XMac, but have tested it also on SunOS (4.1) and BSD 4.3 (tahoe). +X +XBuilding and installing Python is easy (but do read the Makefile). +XA UNIX style manual page and extensive documentation (in LaTeX format) +Xare provided. (In the beta release, the documentation is still under +Xdevelopment.) +X +XPlease try it out and send me your comments (on anything -- the +Xlanguage design, implementation, portability, installation, +Xdocumentation) and the modules you wrote for it, to make the first +Xreal release better. If you needed to hack the source to get it to +Xcompile and run on a particular machine, send me the fixes -- I'll try +Xto incorporate them into the next patch. If you can't get it to work +Xat all, send me a *detailed* description of the problem and I may look +Xinto it. +X +XIf you want to profit of the X11 or Mac window interface, you'll need +XSTDWIN. This is a portable window system interface by the same +Xauthor. The versions of STDWIN floating around on some archives are +Xnot sufficiently up-to-date for use with Python. I will distribute +Xthe latest and greatest STDWIN version at about the same time as Python. +X +XI am the author of Python: +X +X Guido van Rossum +X CWI, dept. CST +X Kruislaan 413 +X 1098 SJ Amsterdam +X The Netherlands +X +X E-mail: [email protected] +X +XThe Python source is copyrighted, but you can freely use and copy it +Xas long as you don't change or remove the copyright: +X +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +EOF +fi +if test -s 'python.man' +then echo '*** I will not over-write existing file python.man' +else +echo 'x - python.man' +sed 's/^X//' > 'python.man' << 'EOF' +X.TH PYTHON "19 February 1991" +X.SH NAME +Xpython \(en an extensible interpreted programming language +X.SH SYNOPSIS +X.B python +X[ +X.I X11-options +X] [ +X.I script +X[ +X.I arguments +X] ] +X.SH DESCRIPTION +XPython is an extensible interpreted programming language that +Xcombines remarkable power with very clear syntax. +XFor an introduction to programming in Python you are referred to the +XPython Tutorial. +X.PP +XThe interpreter operates somewhat like the UNIX shell: when called with +Xstandard input connected to a tty device, it reads and executes commands +Xinteractively until an EOF is read; +Xwhen called with a file name argument or with a file as standard +Xinput, it reads and executes a +X.I script +Xfrom that file. +XIf available, the script name and additional arguments thereafter are +Xpassed to the script in the variable +X.I sys.argv , +Xwhich is a list of strings. +XIn interactive mode, the primary prompt is `>>>'; the second prompt +X(which appears when a command is not complete) is `...'. +X.SH FILES AND DIRECTORIES +X.IP /usr/local/lib/python +XThis might be the directory containing the library of standard modules. +X(Installation-dependent.) +X.SH ENVIRONMENT VARIABLES +X.IP PYTHONPATH +XSets the search path for module files. +XThe format is the same as the shell's $PATH: one or more directory +Xpathnames separated by colons. +XNon-existant directories are silently ignored. +XThe default search path is installation dependent, but always begins +Xwith `.', (for example, +X.I .:/usr/local/lib/python ). +X.SH SEE ALSO +XPython Tutorial +X.br +XPython Library Reference +X.SH AUTHOR +X.nf +XGuido van Rossum +XCWI, dept. CST +XKruislaan 413 +X1098 SJ Amsterdam +XThe Netherlands +X.PP +XE-mail: [email protected] +X.fi +X.SH COPYRIGHT +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X.IP " " +XAll Rights Reserved +X.PP +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +EOF +fi +if test -s 'demo/sgi/gl_panel/nurbs/nurbs.py' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/nurbs/nurbs.py' +else +echo 'x - demo/sgi/gl_panel/nurbs/nurbs.py' +sed 's/^X//' > 'demo/sgi/gl_panel/nurbs/nurbs.py' << 'EOF' +X#! /ufs/guido/bin/sgi/python +X +X# Fancy NURBS demo. Require Z buffer and Panel Library. +X +Xfrom gl import * +Xfrom GL import * +Xfrom DEVICE import * +Xfrom nurbsdata import * +Ximport panel +X +X# +X# flags = trim_f, invis_f, cpvis_f, tpvis_f, axvis_f, freeze_f +X# +XTRIM = 0 +XVIS = 1 +XCPVIS = 2 +XTPVIS = 3 +XAXVIS = 4 +XFREEZE = 5 +Xflags = [0, 1, 0, 0, 0, 0] +X +Xdef draw_axis () : +X cpack (0x0) +X zero = (0.0, 0.0, 0.0) +X # +X one = (1.0, 0.0, 0.0) +X smallline (zero, one) +X cmov (1.0, 0.0, 0.0) +X charstr ('x') +X # +X one = (0.0, 1.0, 0.0) +X smallline (zero, one) +X cmov (0.0, 1.0, 0.0) +X charstr ('y') +X # +X one = (0.0, 0.0, 1.0) +X smallline (zero, one) +X cmov (0.0, 0.0, 1.0) +X charstr ('z') +X +XDELTA = 0.1 +X +Xdef cross (p) : +X p0 = [p[0], p[1], p[2]] +X p1 = [p[0], p[1], p[2]] +X for i in range (0, 3) : +X p0[i] = p0[i] + DELTA +X p1[i] = p1[i] - DELTA +X smallline (p0, p1) +X p0[i] = p0[i] - DELTA +X p1[i] = p1[i] + DELTA +X +Xdef smallline (p0, p1) : +X bgnline () +X v3f (p0) +X v3f (p1) +X endline () +X +Xdef draw_pts (pnts, color) : +X linewidth (2) +X cpack (color) +X for i in pnts : +X cross (i) +X +Xdef init_windows(): +X foreground() +X wid = winopen('nurbs') +X wintitle('NURBS Surface') +X doublebuffer() +X RGBmode() +X gconfig() +X lsetdepth(0x000, 0x7fffff) +X zbuffer( TRUE ) +X +Xdef init_view(): +X mmode(MPROJECTION) +X ortho( -5., 5., -5., 5., -5., 5. ) +X # +X mmode(MVIEWING) +X loadmatrix(idmat) +X # +X lmbind(MATERIAL, 1) +X +Xdef set_scene(flags): +X # +X lmbind(MATERIAL, 0) +X RGBcolor(150,150,150) +X lmbind(MATERIAL, 1) +X clear() +X zclear() +X # +X if not flags[FREEZE] : +X rotate( 100, 'y' ) +X rotate( 100, 'z' ) +X +Xdef draw_trim_surface(flags): +X pnts = ctlpoints +X if flags[VIS] : +X bgnsurface() +X nurbssurface(surfknots,surfknots,pnts,ORDER,ORDER,N_XYZ) +X if flags[TRIM]: +X bgntrim() +X nurbscurve(trimknots,trimpoints,ORDER-1,N_STW) +X endtrim() +X endsurface() +X # +X if flags[CPVIS] : +X for i in pnts : +X draw_pts (i, RED) +X # +X if flags[TPVIS] : +X tpts = trimpoints +X draw_pts (tpts, YELLOW) +X # +X if flags[AXVIS] : +X draw_axis () +X # +X swapbuffers() +X +Xdef make_lights(): +X lmdef(DEFLMODEL,1,[]) +X lmdef(DEFLIGHT,1,[]) +X # +X # define material #1 +X # +X a = [] +X a = a + [EMISSION, 0.0, 0.0, 0.0] +X a = a + [AMBIENT, 0.1, 0.1, 0.1] +X a = a + [DIFFUSE, 0.6, 0.3, 0.3] +X a = a + [SPECULAR, 0.0, 0.6, 0.0] +X a = a + [SHININESS, 2.0] +X a = a + [LMNULL] +X lmdef(DEFMATERIAL, 1, a) +X # +X # turn on lighting +X # +X lmbind(LIGHT0, 1) +X lmbind(LMODEL, 1) +X +Xdef main(): +X init_windows() +X make_lights() +X init_view() +X # +X panel.needredraw() +X panels = panel.defpanellist('nurbs.s') +X p = panels[0] +X # +X def cbtrim (a) : +X flags[TRIM:TRIM+1] = [int (a.val)] +X p.trim.upfunc = cbtrim +X # +X def cbquit (a) : +X import sys +X sys.exit (1) +X p.quit.upfunc = cbquit +X # +X def cbmotion (a) : +X flags[FREEZE:FREEZE+1] = [int (a.val)] +X p.motion.upfunc = cbmotion +X # +X def cbxyzaxis (a) : +X flags[AXVIS:AXVIS+1] = [int (a.val)] +X p.xyzaxis.upfunc = cbxyzaxis +X # +X def cbtrimpnts (a) : +X flags[TPVIS:TPVIS+1] = [int (a.val)] +X p.trimpnts.upfunc = cbtrimpnts +X # +X def cbcntlpnts (a) : +X flags[CPVIS:CPVIS+1] = [int (a.val)] +X p.cntlpnts.upfunc = cbcntlpnts +X # +X def cbnurb (a) : +X flags[VIS:VIS+1] = [int (a.val)] +X p.nurb.upfunc = cbnurb +X # +X set_scene(flags) +X setnurbsproperty( N_ERRORCHECKING, 1.0 ) +X setnurbsproperty( N_PIXEL_TOLERANCE, 50.0 ) +X draw_trim_surface(flags) +X # +X while 1: +X act = panel.dopanel() +X # +X wid = panel.userredraw () +X if wid : +X winset (wid) +X reshapeviewport() +X set_scene(flags) +X draw_trim_surface(flags) +X # +X set_scene(flags) +X draw_trim_surface(flags) +X +Xmain() +EOF +chmod +x 'demo/sgi/gl_panel/nurbs/nurbs.py' +fi +if test -s 'doc/tut.tex' +then echo '*** I will not over-write existing file doc/tut.tex' +else +echo 'x - doc/tut.tex' +sed 's/^X//' > 'doc/tut.tex' << 'EOF' +X% Format this file with latex. +X +X%\documentstyle[garamond,11pt,myformat]{article} +X\documentstyle[11pt,myformat]{article} +X +X\title{\bf +X Python Tutorial \\ +X (DRAFT) +X} +X +X\author{ +X Guido van Rossum \\ +X Dept. CST, CWI, Kruislaan 413 \\ +X 1098 SJ Amsterdam, The Netherlands \\ +X E-mail: {\tt [email protected]} +X} +X +X\begin{document} +X +X\pagenumbering{roman} +X +X\maketitle +X +X\begin{abstract} +X +X\noindent +X\Python\ is a simple, yet powerful programming language that bridges the +Xgap between C and shell programming, and is thus ideally suited for rapid +Xprototyping. +XIts syntax is put together from constructs borrowed from a variety of other +Xlanguages; most prominent are influences from ABC, C, Modula-3 and Icon. +X +XThe \Python\ interpreter is easily extended with new functions and data +Xtypes implemented in C. +X\Python\ is also suitable as an extension language for highly +Xcustomizable C applications such as editors or window managers. +X +X\Python\ is available for various operating systems, amongst which +Xseveral flavors of \UNIX, Amoeba, and the Apple Macintosh O.S. +X +XThis tutorial introduces the reader informally to the basic concepts and +Xfeatures of the \Python\ language and system. +XIt helps to have a \Python\ interpreter handy for hands-on experience, +Xbut as the examples are self-contained, the tutorial can be read +Xoff-line as well. +X +XFor a description of standard objects and modules, see the Library +XReference document. +XThe Language Reference document (XXX not yet existing) +Xgives a more formal reference to the language. +X +X\end{abstract} +X +X\pagebreak +X +X\tableofcontents +X +X\pagebreak +X +X\pagenumbering{arabic} +X +X\section{Whetting Your Appetite} +X +XIf you ever wrote a large shell script, you probably know this feeling: +Xyou'd love to add yet another feature, but it's already so slow, and so +Xbig, and so complicated; or the feature involves a system call or other +Xfuncion that is only accessible from C \ldots +XUsually the problem at hand isn't serious enough to warrant rewriting +Xthe script in C; perhaps because the problem requires variable-length +Xstrings or other data types (like sorted lists of file names) that +Xare easy in the shell but lots of work to implement in C; or perhaps +Xjust because you're not sufficiently familiar with C. +X +XIn all such cases, \Python\ is just the language for you. +X\Python\ is simple to use, but it is a real programming language, offering +Xmuch more structure and support for large programs than the shell has. +XOn the other hand, it also offers much more error checking than C, and, +Xbeing a +X{\em very-high-level language}, +Xit has high-level data types built in, such as flexible arrays and +Xdictionaries that would cost you days to implement efficiently in C. +XBecause of its more general data types \Python\ is applicable to a +Xmuch larger problem domain than +X{\em Awk} +Xor even +X{\em Perl}, +Xyet most simple things are at least as easy in \Python\ as in those +Xlanguages. +X +X\Python\ allows you to split up your program in modules that can be reused +Xin other \Python\ programs. +XIt comes with a large collection of standard modules that you can use as +Xthe basis for your programs --- or as examples to start learning to +Xprogram in \Python. +XThere are also built-in modules that provide things like file I/O, +Xsystem calls, and even a generic interface to window systems (STDWIN). +X +X\Python\ is an interpreted language, which saves you considerable time +Xduring program development because no compilation and linking is +Xnecessary. +XThe interpreter can be used interactively, which makes it easy to +Xexperiment with features of the language, to write throw-away programs, +Xor to test functions during bottom-up program development. +XIt is also a handy desk calculator. +X +X\Python\ allows writing very compact and readable programs. +XPrograms written in \Python\ are typically much shorter than equivalent C +Xprograms: +XNo declarations are necessary (all type checking is +Xdynamic); statement grouping is done by indentation instead of begin/end +Xbrackets; and the high-level data types allow you to express complex +Xoperations in a single statement. +X +X\Python\ is +X{\em extensible}: +Xif you know how to program in C it is easy to add a new built-in module +Xto the interpreter, either to perform critical operations at maximum +Xspeed, or to link \Python\ programs to libraries that may be only available +Xin binary form (such as a vendor-specific graphics library). +XOnce you are really hooked, you can link the \Python\ interpreter into an +Xapplication written in C and use it as an extension or command language. +X +X\subsection{Where From Here} +X +XNow that you are all excited about \Python, you'll want to examine it in +Xsome more detail. +XSince the best introduction to a language is using it, you are invited +Xhere to do so. +X +XIn the next section, the mechanics of using the interpreter are +Xexplained. +XThis is rather mundane information, but essential for trying out the +Xexamples shown later. +XThe rest of the tutorial introduces various features of the \Python\ +Xlanguage and system though examples, beginning with simple expressions, +Xstatements and data types, through functions and modules, and finally +Xtouching upon advanced concepts like exceptions and classes. +X +X\section{Using the Python Interpreter} +X +XThe \Python\ interpreter is usually installed as +X{\tt /usr/local/python} +Xon those machines where it is available; putting +X{\tt /usr/local} +Xin your \UNIX\ shell's search path makes it possible to start it by +Xtyping the command +X\bcode\begin{verbatim} +Xpython +X\end{verbatim}\ecode +Xto the shell. +XSince the choice of the directory where the interpreter lives is an +Xinstallation option, other places instead of +X{\tt /usr/local} +Xare possible; check with your local \Python\ guru or system +Xadministrator.% +X\footnote{ +X At CWI, at the time of writing, the interpreter can be found in +X the following places: +X On the Amoeba Ultrix machines, use the standard path, +X {\tt /usr/local/python}. +X On the Sun file servers, use +X {\tt /ufs/guido/bin/}{\em arch}{\tt /python}, +X where {\em arch} can be {\tt sgi} or {\tt sun4}. +X On piring, use {\tt /userfs3/amoeba/bin/python}. +X (If you can't find a binary advertised here, get in touch with me.) +X} +X +XThe interpreter operates somewhat like the \UNIX\ shell: when called with +Xstandard input connected to a tty device, it reads and executes commands +Xinteractively; when called with a file name argument or with a file as +Xstandard input, it reads and executes a +X{\em script} +Xfrom that file.% +X\footnote{ +X There is a difference between ``{\tt python file}'' and +X ``{\tt python $<$file}''. In the latter case {\tt input()} and +X {\tt raw\_input()} are satisfied from {\em file}, which has +X already been read until the end by the parser, so they will read +X EOF immediately. In the former case (which is usually what +X you want) they are satisfied from whatever file or device is +X connected to standard input of the \Python\ interpreter. +X} +XIf available, the script name and additional arguments thereafter are +Xpassed to the script in the variable +X{\tt sys.argv}, +Xwhich is a list of strings. +X +XWhen standard input is a tty, the interpreter is said to be in +X{\em interactive\ mode}. +XIn this mode it prompts for the next command with the +X{\em primary\ prompt}, +Xusually three greater-than signs ({\tt >>>}); for continuation lines +Xit prompts with the +X{\em secondary\ prompt}, +Xby default three dots ({\tt ...}). +XTyping an EOF (Control-D) at the primary prompt causes the interpreter +Xto exit with a zero exit status. +X +XWhen an error occurs in interactive mode, the interpreter prints a +Xmessage and a stack trace and returns to the primary prompt; with input +Xfrom a file, it exits with a nonzero exit status. +X(Exceptions handled by an +X{\tt except} +Xclause in a +X{\tt try} +Xstatement are not errors in this context.) +XSome errors are unconditionally fatal and cause an exit with a nonzero +Xexit; this applies to internal inconsistencies and some cases of running +Xout of memory. +XAll error messages are written to the standard error stream; normal +Xoutput from the executed commands is written to standard output. +X +XTyping an interrupt (normally Control-C or DEL) to the primary or +Xsecondary prompt cancels the input and returns to the primary prompt. +XTyping an interrupt while a command is being executed raises the +X{\tt KeyboardInterrupt} +Xexception, which may be handled by a +X{\tt try} +Xstatement. +X +XWhen a module named +X{\tt foo} +Xis imported, the interpreter searches for a file named +X{\tt foo.py} +Xin a list of directories specified by the environment variable +X{\tt PYTHONPATH}. +XIt has the same syntax as the \UNIX\ shell variable +X{\tt PATH}, +Xi.e., a list of colon-separated directory names. +XWhen +X{\tt PYTHONPATH} +Xis not set, an installation-dependent default path is used, usually +X{\tt .:/usr/local/lib/python}.% +X\footnote{ +X Modules are really searched in the list of directories given by +X the variable {\tt sys.path} which is initialized from +X {\tt PYTHONPATH} or from the installation-dependent default. +X See the section on Standard Modules later. +X} +X +XOn BSD'ish \UNIX\ systems, \Python\ scripts can be made directly executable, +Xlike shell scripts, by putting the line +X\bcode\begin{verbatim} +X#! /usr/local/python +X\end{verbatim}\ecode +X(assuming that's the name of the interpreter) at the beginning of the +Xscript and giving the file an executable mode. +X(The +X{\tt \#!} +Xmust be the first two characters of the file.) +X +X\subsection{Interactive Input Editing and History Substitution} +X +XSome versions of the \Python\ interpreter support editing of the current +Xinput line and history substitution, similar to facilities found in the +XKorn shell and the GNU Bash shell. +XThis is implemented using the +X{\em GNU\ Readline} +Xlibrary, which supports Emacs-style and vi-style editing. +XThis library has its own documentation which I won't duplicate here; +Xhowever, the basics are easily explained. +X +XIf supported,% +X\footnote{ +X Perhaps the quickest check to see whether command line editing +X is supported is typing Control-P to the first \Python\ prompt +X you get. If it beeps, you have command line editing. +X If not, you can skip the rest of this section. +X} +Xinput line editing is active whenever the interpreter prints a primary +Xor secondary prompt. +XThe current line can be edited using the conventional Emacs control +Xcharacters. +XThe most important of these are: +XC-A (Control-A) moves the cursor to the beginning of the line, C-E to +Xthe end, C-B moves it one position to the left, C-F to the right. +XBackspace erases the character to the left of the cursor, C-D the +Xcharacter to its right. +XC-K kills (erases) the rest of the line to the right of the cursor, C-Y +Xyanks back the last killed string. +XC-underscore undoes the last change you made; it can be repeated for +Xcumulative effect. +X +XHistory substitution works as follows. +XAll non-empty input lines issued are saved in a history buffer, +Xand when a new prompt is given you are positioned on a new line at the +Xbottom of this buffer. +XC-P moves one line up (back) in the history buffer, C-N moves one down. +XAny line in the history buffer can be edited; an asterisk appears in +Xfront of the prompt to mark a line as modified. +XPressing the Return key passes the current line to the interpreter. +XC-R starts an incremental reverse search; C-S starts a forward search. +X +XThe key bindings and some other parameters of the Readline library can +Xbe customized by placing commands in an initialization file called +X{\tt \$HOME/.initrc}. +XKey bindings have the form +X\bcode\begin{verbatim} +Xkey-name: function-name +X\end{verbatim}\ecode +Xand options can be set with +X\bcode\begin{verbatim} +Xset option-name value +X\end{verbatim}\ecode +XExample: +X\bcode\begin{verbatim} +X# I prefer vi-style editing: +Xset editing-mode vi +X# Edit using a single line: +Xset horizontal-scroll-mode On +X# Rebind some keys: +XMeta-h: backward-kill-word +XControl-u: universal-argument +X\end{verbatim}\ecode +XNote that the default binding for TAB in \Python\ is to insert a TAB +Xinstead of Readline's default filename completion function. +XIf you insist, you can override this by putting +X\bcode\begin{verbatim} +XTAB: complete +X\end{verbatim}\ecode +Xin your +X{\tt \$HOME/.inputrc}. +X(Of course, this makes it hard to type indented continuation lines.) +X +XThis facility is an enormous step forward compared to previous versions of +Xthe interpreter; however, some wishes are left: +XIt would be nice if the proper indentation were suggested on +Xcontinuation lines (the parser knows if an indent token is required +Xnext). +XThe completion mechanism might use the interpreter's symbol table. +XA function to check (or even suggest) matching parentheses, quotes +Xetc. would also be useful. +X +X\section{An Informal Introduction to Python} +X +XIn the following examples, input and output are distinguished by the +Xpresence or absence of prompts ({\tt >>>} and {\tt ...}): to repeat the +Xexample, you must type everything after the prompt, when the prompt +Xappears; everything on lines that do not begin with a prompt is output +Xfrom the interpreter. +XNote that a secondary prompt on a line by itself in an example means you +Xmust type a blank line; this is used to end a multi-line command. +X +X\subsection{Using Python as a Calculator} +X +XLet's try some simple \Python\ commands. +XStart the interpreter and wait for the primary prompt, +X{\tt >>>}. +XThe interpreter acts as a simple calculator: you can type an expression +Xat it and it will write the value. +XExpression syntax is straightforward: the operators +X{\tt +}, +X{\tt -}, +X{\tt *} +Xand +X{\tt /} +Xwork just as in most other languages (e.g., Pascal or C); parentheses +Xcan be used for grouping. +XFor example: +X\bcode\begin{verbatim} +X>>> # This is a comment +X>>> 2+2 +X4 +X>>> +X>>> (50-5+5*6+25)/4 +X25 +X>>> # Division truncates towards zero: +X>>> 7/3 +X2 +X>>> +X\end{verbatim}\ecode +XAs in C, the equal sign ({\tt =}) is used to assign a value to a variable. +XThe value of an assignment is not written: +X\bcode\begin{verbatim} +X>>> width = 20 +X>>> height = 5*9 +X>>> width * height +X900 +X>>> +X\end{verbatim}\ecode +XThere is some support for floating point, but you can't mix floating +Xpoint and integral numbers in expression (yet): +X\bcode\begin{verbatim} +X>>> 10.0 / 3.3 +X3.0303030303 +X>>> +X\end{verbatim}\ecode +XBesides numbers, \Python\ can also manipulate strings, enclosed in single +Xquotes: +X\bcode\begin{verbatim} +X>>> 'foo bar' +X'foo bar' +X>>> 'doesn\'t' +X'doesn\'t' +X>>> +X\end{verbatim}\ecode +XStrings are written inside quotes and with quotes and other funny +Xcharacters escaped by backslashes, to show the precise value. +X(There is also a way to write strings without quotes and escapes.) +XStrings can be concatenated (glued together) with the +X{\tt +} +Xoperator, and repeated with~{\tt *}: +X\bcode\begin{verbatim} +X>>> word = 'Help' + 'A' +X>>> word +X'HelpA' +X>>> '<' + word*5 + '>' +X'<HelpAHelpAHelpAHelpAHelpA>' +X>>> +X\end{verbatim}\ecode +XStrings can be subscripted; as in C, the first character of a string has +Xsubscript 0. +XThere is no separate character type; a character is simply a string of +Xsize one. +XAs in Icon, substrings can be specified with the +X{\em slice} +Xnotation: two subscripts (indices) separated by a colon. +X\bcode\begin{verbatim} +X>>> word[4] +X'A' +X>>> word[0:2] +X'He' +X>>> word[2:4] +X'lp' +X>>> # Slice indices have useful defaults: +X>>> word[:2] # Take first two characters +X'He' +X>>> word[2:] # Drop first two characters +X'lpA' +X>>> # A useful invariant: s[:i] + s[i:] = s +X>>> word[:3] + word[3:] +X'HelpA' +X>>> +X\end{verbatim}\ecode +XDegenerate cases are handled gracefully: an index that is too large is +Xreplaced by the string size, an upper bound smaller than the lower bound +Xreturns an empty string. +X\bcode\begin{verbatim} +X>>> word[1:100] +X'elpA' +X>>> word[10:] +X'' +X>>> word[2:1] +X'' +X>>> +X\end{verbatim}\ecode +XSlice indices (but not simple subscripts) may be negative numbers, to +Xstart counting from the right. +XFor example: +X\bcode\begin{verbatim} +X>>> word[-2:] # Take last two characters +X'pA' +X>>> word[:-2] # Drop last two characters +X'Hel' +X>>> # But -0 does not count from the right! +X>>> word[-0:] # (since -0 equals 0) +X'HelpA' +X>>> +X\end{verbatim}\ecode +XThe best way to remember how slices work is to think of the indices as +Xpointing +X{\em between} +Xcharacters, with the left edge of the first character numbered 0. +XThen the right edge of the last character of a string of +X{\tt n} +Xcharacters has index +X{\tt n}, +Xfor example: +X\bcode\begin{verbatim} +X +---+---+---+---+---+ +X | H | e | l | p | A | +X +---+---+---+---+---+ +X 0 1 2 3 4 5 +X-5 -4 -3 -2 -1 +X\end{verbatim}\ecode +XThe first row of numbers gives the position of the indices 0...5 in the +Xstring; the second row gives the corresponding negative indices. +XFor nonnegative indices, the length of a slice is the difference of the +Xindices, if both are within bounds, +Xe.g., +Xthe length of +X{\tt word[1:3]} +Xis 3--1 = 2. +X +XFinally, the built-in function {\tt len()} computes the length of a +Xstring: +X\bcode\begin{verbatim} +X>>> s = 'supercalifragilisticexpialidocious' +X>>> len(s) +X34 +X>>> +X\end{verbatim}\ecode +X\Python\ knows a number of +X{\em compound} +Xdata types, used to group together other values. +XThe most versatile is the +X{\em list}, +Xwhich can be written as a list of comma-separated values between square +Xbrackets: +X\bcode\begin{verbatim} +X>>> a = ['foo', 'bar', 100, 1234] +X>>> a +X['foo', 'bar', 100, 1234] +X>>> +X\end{verbatim}\ecode +XAs for strings, list subscripts start at 0: +X\bcode\begin{verbatim} +X>>> a[0] +X'foo' +X>>> a[3] +X1234 +X>>> +X\end{verbatim}\ecode +XLists can be sliced and concatenated like strings: +X\bcode\begin{verbatim} +X>>> a[1:3] +X['bar', 100] +X>>> a[:2] + ['bletch', 2*2] +X['foo', 'bar', 'bletch', 4] +X>>> +X\end{verbatim}\ecode +XUnlike strings, which are +X{\em immutable}, +Xit is possible to change individual elements of a list: +X\bcode\begin{verbatim} +X>>> a +X['foo', 'bar', 100, 1234] +X>>> a[2] = a[2] + 23 +X>>> a +X['foo', 'bar', 123, 1234] +X>>> +X\end{verbatim}\ecode +XAssignment to slices is also possible, and this may even change the size +Xof the list: +X\bcode\begin{verbatim} +X>>> # Replace some items: +X>>> a[0:2] = [1, 12] +X>>> a +X[1, 12, 123, 1234] +X>>> # Remove some: +X>>> a[0:2] = [] +X>>> a +X[123, 1234] +X>>> # Insert some: +X>>> a[1:1] = ['bletch', 'xyzzy'] +X>>> a +X[123, 'bletch', 'xyzzy', 1234] +X>>> +X\end{verbatim}\ecode +XThe built-in function {\tt len()} also applies to lists: +X\bcode\begin{verbatim} +X>>> len(a) +X4 +X>>> +X\end{verbatim}\ecode +X +X\subsection{Tuples and Sequences} +X +XXXX To Be Done. +X +X\subsection{First Steps Towards Programming} +X +XOf course, we can use \Python\ for more complicated tasks than adding two +Xand two together. +XFor instance, we can write an initial subsequence of the +X{\em Fibonacci} +Xseries as follows: +X\bcode\begin{verbatim} +X>>> # Fibonacci series: +X>>> # the sum of two elements defines the next +X>>> a, b = 0, 1 +X>>> while b < 100: +X... print b +X... a, b = b, a+b +X... +X1 +X1 +X2 +X3 +X5 +X8 +X13 +X21 +X34 +X55 +X89 +X>>> +X\end{verbatim}\ecode +XThis example introduces several new features. +X\begin{itemize} +X\item +XThe first line contains a +X{\em multiple\ assignment}: +Xthe variables +X{\tt a} +Xand +X{\tt b} +Xsimultaneously get the new values 0 and 1. +XOn the last line this is used again, demonstrating that the expressions +Xon the right-hand side are all evaluated first before any of the +Xassignments take place. +X\item +XThe +X{\tt while} +Xloop executes as long as the condition (here: $b < 100$) remains true. +XIn \Python, as in C, any non-zero integer value is true; zero is false. +XThe condition may also be a string or list value, in fact any sequence; +Xanything with a non-zero length is true, empty sequences are false. +XThe test used in the example is a simple comparison. +XThe standard comparison operators are written as +X{\tt <}, +X{\tt >}, +X{\tt =}, +X{\tt <=}, +X{\tt >=} +Xand +X{\tt <>}.% +X\footnote{ +X The ambiguity of using {\tt =} +X for both assignment and equality is resolved by disallowing +X unparenthesized conditions at the right hand side of assignments. +X} +X\item +XThe +X{\em body} +Xof the loop is +X{\em indented}: indentation is \Python's way of grouping statements. +X\Python\ does not (yet!) provide an intelligent input line editing +Xfacility, so you have to type a tab or space(s) for each indented line. +XIn practice you will prepare more complicated input for \Python\ with a +Xtext editor; most text editors have an auto-indent facility. +XWhen a compound statement is entered interactively, it must be +Xfollowed by a blank line to indicate completion (since the parser +Xcannot guess when you have typed the last line). +X\item +XThe +X{\tt print} +Xstatement writes the value of the expression(s) it is given. +XIt differs from just writing the expression you want to write (as we did +Xearlier in the calculator examples) in the way it handles multiple +Xexpressions and strings. +XStrings are written without quotes and a space is inserted between +Xitems, so you can format things nicely, like this: +X\bcode\begin{verbatim} +X>>> i = 256*256 +X>>> print 'The value of i is', i +XThe value of i is 65536 +X>>> +X\end{verbatim}\ecode +XA trailing comma avoids the newline after the output: +X\bcode\begin{verbatim} +X>>> a, b = 0, 1 +X>>> while b < 1000: +X... print b, +X... a, b = b, a+b +X... +X1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 +X>>> +X\end{verbatim}\ecode +XNote that the interpreter inserts a newline before it prints the next +Xprompt if the last line was not completed. +X\end{itemize} +X +X\subsection{More Control Flow Tools} +X +XBesides the {\tt while} statement just introduced, \Python\ knows the +Xusual control flow statements known from other languages, with some +Xtwists. +X +X\subsubsection{If Statements} +X +XPerhaps the most well-known statement type is the {\tt if} statement. +XFor example: +X\bcode\begin{verbatim} +X>>> if x < 0: +X... x = 0 +X... print 'Negative changed to zero' +X... elif x = 0: +X... print 'Zero' +X... elif x = 1: +X... print 'Single' +X... else: +X... print 'More' +X... +X\end{verbatim}\ecode +XThere can be zero or more {\tt elif} parts, and the {\tt else} part is +Xoptional. +XThe keyword `{\tt elif}' is short for `{\tt else if}', and is useful to +Xavoid excessive indentation. +XAn {\tt if...elif...elif...} sequence is a substitute for the +X{\em switch} or {\em case} statements found in other languages. +X +X\subsubsection{For Statements} +X +XThe {\tt for} statement in \Python\ differs a bit from what you may be +Xused to in C or Pascal. +XRather than always iterating over an arithmetic progression of numbers +X(as Pascal), or leaving the user completely free in the iteration test +Xand step (as C), \Python's {\tt for} statement iterates over the items +Xof any sequence (e.g., a list or a string). +XFor example (no pun intended): +X\bcode\begin{verbatim} +X>>> # Measure some strings: +X>>> a = ['cat', 'window', 'defenestrate'] +X>>> for x in a: +X... print x, len(x) +X... +Xcat 3 +Xwindow 6 +Xdefenestrate 12 +X>>> +X\end{verbatim}\ecode +X +X\subsubsection{The {\tt range()} Function} +X +XIf you do need to iterate over a sequence of numbers, the built-in +Xfunction {\tt range()} comes in handy. +XIt generates lists containing arithmetic progressions, +Xe.g.: +X\bcode\begin{verbatim} +X>>> range(10) +X[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +X>>> +X\end{verbatim}\ecode +XThe given end point is never part of the generated list; +X{\tt range(10)} generates a list of 10 values, +Xexactly the legal indices for items of a sequence of length 10. +XIt is possible to let the range start at another number, or to specify a +Xdifferent increment (even negative): +X\bcode\begin{verbatim} +X>>> range(5, 10) +X[5, 6, 7, 8, 9] +X>>> range(0, 10, 3) +X[0, 3, 6, 9] +X>>> range(-10, -100, -30) +X[-10, -40, -70] +X>>> +X\end{verbatim}\ecode +XTo iterate over the indices of a sequence, combine {\tt range()} +Xand {\tt len()} as follows: +X\bcode\begin{verbatim} +X>>> a = ['Mary', 'had', 'a', 'little', 'boy'] +X>>> for i in range(len(a)): +X... print i, a[i] +X... +X0 Mary +X1 had +X2 a +X3 little +X4 boy +X>>> +X\end{verbatim}\ecode +X +X\subsubsection{Break Statements and Else Clauses on Loops} +X +XThe {\tt break} statement breaks out of the smallest enclosing {\tt for} +Xor {\tt while} loop. +XLoop statements may have an {\tt else} clause; it is executed when the +Xloop terminates through exhaustion of the list (with {\tt for}) or when +Xthe condition becomes false (with {\tt while}) but not when the loop is +Xterminated by a {\tt break} statement. +XThis is exemplified by the following loop, which searches for a list +Xitem of value 0: +X\bcode\begin{verbatim} +X>>> for n in range(2, 10): +X... for x in range(2, n): +X... if n % x = 0: +X... print n, 'equals', x, '*', n/x +X... break +X... else: +X... print n, 'is a prime number' +X... +X2 is a prime number +X3 is a prime number +X4 equals 2 * 2 +X5 is a prime number +X6 equals 2 * 3 +X7 is a prime number +X8 equals 2 * 4 +X9 equals 3 * 3 +X>>> +X\end{verbatim}\ecode +X +X\subsubsection{Pass Statements} +X +XThe {\tt pass} statement does nothing. +XIt can be used when a statement is required syntactically but the +Xprogram requires no action. +XFor example: +X\bcode\begin{verbatim} +X>>> while 1: +X... pass # Busy-wait for keyboard interrupt +X... +X\end{verbatim}\ecode +X +X\subsubsection{Conditions Revisited} +X +XXXX To Be Done. +X +X\subsection{Defining Functions} +X +XWe can create a function that writes the Fibonacci series to an +Xarbitrary boundary: +X\bcode\begin{verbatim} +X>>> def fib(n): # write Fibonacci series up to n +X... a, b = 0, 1 +X... while b <= n: +X... print b, +X... a, b = b, a+b +X... +X>>> # Now call the function we just defined: +X>>> fib(2000) +X1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 +X>>> +X\end{verbatim}\ecode +XThe keyword +X{\tt def} +Xintroduces a function +X{\em definition}. +XIt must be followed by the function name and the parenthesized list of +Xformal parameters. +XThe statements that form the body of the function starts at the next +Xline, indented by a tab stop. +XThe +X{\em execution} +Xof a function introduces a new symbol table used for the local variables +Xof the function. +XMore precisely, all variable assignments in a function store the value +Xin the local symbol table; variable references first look in the local +Xsymbol table, then in the global symbol table, and then in the table of +Xbuilt-in names. +XThus, the global symbol table is +X{\em read-only} +Xwithin a function. +XThe actual parameters (arguments) to a function call are introduced in +Xthe local symbol table of the called function when it is called; +Xthus, arguments are passed using +X{\em call\ by\ value}.% +X\footnote{ +X Actually, {\em call by object reference} would be a better +X description, since if a mutable object is passed, the caller +X will see any changes the callee makes to it (e.g., items +X inserted into a list). +X} +XWhen a function calls another function, a new local symbol table is +Xcreated for that call. +X +XA function definition introduces the function name in the global symbol +Xtable. +XThe value has a type that is recognized by the interpreter as a +Xuser-defined function. +XThis value can be assigned to another name which can then also be used +Xas a function. +XThis serves as a general renaming mechanism: +X\bcode\begin{verbatim} +X>>> fib +X<function object at 10042ed0> +X>>> f = fib +X>>> f(100) +X1 1 2 3 5 8 13 21 34 55 89 +X>>> +X\end{verbatim}\ecode +XYou might object that +X{\tt fib} +Xis not a function but a procedure. +XIn \Python, as in C, procedures are just functions that don't return a +Xvalue. +XIn fact, technically speaking, procedures do return a value, albeit a +Xrather boring one. +XThis value is called {\tt None} (it's a built-in name). +XWriting the value {\tt None} is normally suppressed by the interpreter +Xif it would be the only value written. +XYou can see it if you really want to: +X\bcode\begin{verbatim} +X>>> print fib(0) +XNone +X>>> +X\end{verbatim}\ecode +XIt is simple to write a function that returns a list of the numbers of +Xthe Fibonacci series, instead of printing it: +X\bcode\begin{verbatim} +X>>> def fib2(n): # return Fibonacci series up to n +X... result = [] +X... a, b = 0, 1 +X... while b <= n: +X... result.append(b) # see below +X... a, b = b, a+b +X... return result +X... +X>>> f100 = fib2(100) # call it +X>>> f100 # write the result +X[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] +X>>> +X\end{verbatim}\ecode +XThis example, as usual, demonstrates some new \Python\ features: +X\begin{itemize} +X\item +XThe +X{\tt return} +Xstatement returns with a value from a function. +X{\tt return} +Xwithout an expression argument is used to return from the middle of a +Xprocedure (falling off the end also returns from a proceduce). +X\item +XThe statement +X{\tt ret.append(b)} +Xcalls a +X{\em method} +Xof the list object +X{\tt ret}. +XA method is a function that `belongs' to an object and is named +X{\tt obj.methodname}, +Xwhere +X{\tt obj} +Xis some object (this may be an expression), and +X{\tt methodname} +Xis the name of a method that is defined by the object's type. +XDifferent types define different methods. +XMethods of different types may have the same name without causing +Xambiguity. +XSee the section on classes, later, to find out how you can define your +Xown object types and methods. +XThe method +X{\tt append} +Xshown in the example, is defined for list objects; it adds a new element +Xat the end of the list. +XIn this case it is equivalent to +X{\tt ret = ret + [b]}, +Xbut more efficient.% +X\footnote{ +X There is a subtle semantic difference if the object +X is referenced from more than one place. +X} +X\end{itemize} +XThe list object type has two more methods: +X\begin{description} +X\item[{\tt insert(i, x)}] +XInserts an item at a given position. +XThe first argument is the index of the element before which to insert, +Xso {\tt a.insert(0, x)} inserts at the front of the list, and +X{\tt a.insert(len(a), x)} is equivalent to {\tt a.append(x)}. +X\item[{\tt sort()}] +XSorts the elements of the list. +X\end{description} +XFor example: +X\bcode\begin{verbatim} +X>>> a = [10, 100, 1, 1000] +X>>> a.insert(2, -1) +X>>> a +X[10, 100, -1, 1, 1000] +X>>> a.sort() +X>>> a +X[-1, 1, 10, 100, 1000] +X>>> # Strings are sorted according to ASCII: +X>>> b = ['Mary', 'had', 'a', 'little', 'boy'] +X>>> b.sort() +X>>> b +X['Mary', 'a', 'boy', 'had', 'little'] +X>>> +X\end{verbatim}\ecode +X +X\subsection{Modules} +X +XIf you quit from the \Python\ interpreter and enter it again, the +Xdefinitions you have made (functions and variables) are lost. +XTherefore, if you want to write a somewhat longer program, you are +Xbetter off using a text editor to prepare the input for the interpreter +Xand run it with that file as input instead. +XThis is known as creating a +X{\em script}. +XAs your program gets longer, you may want to split it into several files +Xfor easier maintenance. +XYou may also want to use a handy function that you've written in several +Xprograms without copying its definition into each program. +XTo support this, \Python\ has a way to put definitions in a file and use +Xthem in a script or in an interactive instance of the interpreter. +XSuch a file is called a +X{\em module}; +Xdefinitions from a module can be +X{\em imported} +Xinto other modules or into the +X{\em main} +Xmodule (the collection of variables that you have access to in +Xa script and in calculator mode). +X +XA module is a file containing \Python\ definitions and statements. +XThe file name is the module name with the suffix +X{\tt .py} +Xappended. +XFor instance, use your favorite text editor to create a file called +X{\tt fibo.py} +Xin the current directory with the following contents: +X\bcode\begin{verbatim} +X# Fibonacci numbers module +X +Xdef fib(n): # write Fibonacci series up to n +X a, b = 0, 1 +X while b <= n: +X print b, +X a, b = b, a+b +X +Xdef fib2(n): # return Fibonacci series up to n +X ret = [] +X a, b = 0, 1 +X while b <= n: +X ret.append(b) +X a, b = b, a+b +X return ret +X\end{verbatim}\ecode +XNow enter the \Python\ interpreter and import this module with the +Xfollowing command: +X\bcode\begin{verbatim} +X>>> import fibo +X>>> +X\end{verbatim}\ecode +XThis does not enter the names of the functions defined in +X{\tt fibo} +Xdirectly in the symbol table; it only enters the module name +X{\tt fibo} +Xthere. +XUsing the module name you can access the functions: +X\bcode\begin{verbatim} +X>>> fibo.fib(1000) +X1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 +X>>> fibo.fib2(100) +X[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] +X>>> +X\end{verbatim}\ecode +XIf you intend to use a function often you can assign it to a local name: +X\bcode\begin{verbatim} +X>>> fib = fibo.fib +X>>> fib(500) +X1 1 2 3 5 8 13 21 34 55 89 144 233 377 +X>>> +X\end{verbatim}\ecode +X +X\subsubsection{More on Modules} +X +XA module can contain executable statements as well as function +Xdefinitions. +XThese statements are intended to initialize the module. +XThey are executed only the +X{\em first} +Xtime the module is imported somewhere.% +X\footnote{ +X In fact function definitions are also `statements' that are +X `executed'; the execution enters the function name in the +X module's global symbol table. +X} +X +XEach module has its own private symbol table, which is used as the +Xglobal symbol table by all functions defined in the module. +XThus, the author of a module can use global variables in the module +Xwithout worrying about accidental clashes with a user's global +Xvariables. +XOn the other hand, if you know what you are doing you can touch a +Xmodule's global variables with the same notation used to refer to its +Xfunctions, +X{\tt modname.itemname}. +X +XModules can import other modules. +XIt is customary but not required to place all +X{\tt import} +Xstatements at the beginning of a module (or script, for that matter). +XThe imported module names are placed in the importing module's global +Xsymbol table. +X +XThere is a variant of the +X{\tt import} +Xstatement that imports names from a module directly into the importing +Xmodule's symbol table. +XFor example: +X\bcode\begin{verbatim} +X>>> from fibo import fib, fib2 +X>>> fib(500) +X1 1 2 3 5 8 13 21 34 55 89 144 233 377 +X>>> +X\end{verbatim}\ecode +XThis does not introduce the module name from which the imports are taken +Xin the local symbol table (so in the example, {\tt fibo} is not +Xdefined). +X +XThere is even a variant to import all names that a module defines: +X\bcode\begin{verbatim} +X>>> from fibo import * +X>>> fib(500) +X1 1 2 3 5 8 13 21 34 55 89 144 233 377 +X>>> +X\end{verbatim}\ecode +XThis imports all names except those beginning with an underscore +X({\tt \_}). +X +X\subsubsection{Standard Modules} +X +X\Python\ comes with a library of standard modules, described in a separate +Xdocument (Python Library and Module Reference). +XSome modules are built into the interpreter; these provide access to +Xoperations that are not part of the core of the language but are +Xnevertheless built in, either for efficiency or to provide access to +Xoperating system primitives such as system calls. +XThe set of such modules is a configuration option; e.g., the +X{\tt amoeba} +Xmodule is only provided on systems that somehow support Amoeba +Xprimitives. +XOne particular module deserves some attention: +X{\tt sys}, +Xwhich is built into every \Python\ interpreter. +XThe variables +X{\tt sys.ps1} +Xand +X{\tt sys.ps2} +Xdefine the strings used as primary and secondary prompts: +X\bcode\begin{verbatim} +X>>> import sys +X>>> sys.ps1 +X'>>> ' +X>>> sys.ps2 +X'... ' +X>>> sys.ps1 = 'C> ' +XC> print 'Yuck!' +XYuck! +XC> +X\end{verbatim}\ecode +XThese two variables are only defined if the interpreter is in +Xinteractive mode. +X +XThe variable +X{\tt sys.path} +Xis a list of strings that determine the interpreter's search path for +Xmodules. +XIt is initialized to a default path taken from the environment variable +X{\tt PYTHONPATH}, +Xor from a built-in default if +X{\tt PYTHONPATH} +Xis not set. +XYou can modify it using standard list operations, e.g.: +X\bcode\begin{verbatim} +X>>> import sys +X>>> sys.path.append('/ufs/guido/lib/python') +X>>> +X\end{verbatim}\ecode +X +X\subsection{Errors and Exceptions} +X +XUntil now error messages haven't yet been mentioned, but if you have +Xtried out the examples you have probably seen some. +XThere are (at least) two distinguishable kinds of errors: +X{\em syntax\ errors} +Xand +X{\em exceptions}. +X +X\subsubsection{Syntax Errors} +X +XSyntax errors, also known as parsing errors, are perhaps the most common +Xkind of complaint you get while you are still learning \Python: +X\bcode\begin{verbatim} +X>>> while 1 print 'Hello world' +XParsing error: file <stdin>, line 1: +Xwhile 1 print 'Hello world' +X ^ +XUnhandled exception: run-time error: syntax error +X>>> +X\end{verbatim}\ecode +XThe parser repeats the offending line and displays a little `arrow' +Xpointing at the earliest point in the line where the error was detected. +XThe error is caused by (or at least detected at) the token +X{\em preceding} +Xthe arrow: in the example, the error is detected at the keyword +X{\tt print}, since a colon ({\tt :}) is missing before it. +XFile name and line number are printed so you know where to look in case +Xthe input came from a script. +X +X\subsubsection{Exceptions} +X +XEven if a statement or expression is syntactically correct, it may cause +Xan error when an attempt is made to execute it: +X\bcode\small\begin{verbatim} +X>>> 10 * (1/0) +XUnhandled exception: run-time error: integer division by zero +XStack backtrace (innermost last): +X File "<stdin>", line 1 +X>>> 4 + foo*3 +XUnhandled exception: undefined name: foo +XStack backtrace (innermost last): +X File "<stdin>", line 1 +X>>> '2' + 2 +XUnhandled exception: type error: illegal argument type for built-in operation +XStack backtrace (innermost last): +X File "<stdin>", line 1 +X>>> +X\end{verbatim}\ecode +XErrors detected during execution are called +X{\em exceptions} +Xand are not unconditionally fatal: you will soon learn how to handle +Xthem in \Python\ programs. +XMost exceptions are not handled by programs, however, and result +Xin error messages as shown here. +X +XThe first line of the error message indicates what happened. +XExceptions come in different types, and the type is printed as part of +Xthe message: the types in the example are +X{\tt run-time error}, +X{\tt undefined name} +Xand +X{\tt type error}. +XThe rest of the line is a detail whose interpretation depends on the +Xexception type. +X +XThe rest of the error message shows the context where the +Xexception happened. +XIn general it contains a stack backtrace listing source lines; however, +Xit will not display lines read from standard input. +X +XHere is a summary of the most common exceptions: +X\begin{itemize} +X\item +X{\em Run-time\ errors} +Xare generally caused by wrong data used by the program; this can be the +Xprogrammer's fault or caused by bad input. +XThe detail states the cause of the error in more detail. +X\item +X{\em Undefined\ name} +Xerrors are more serious: these are usually caused by misspelled +Xidentifiers.% +X\footnote{ +X The parser does not check whether names used in a program are at +X all defined elsewhere in the program, so such checks are +X postponed until run-time. The same holds for type checking. +X} +XThe detail is the offending identifier. +X\item +X{\em Type\ errors} +Xare also pretty serious: this is another case of using wrong data (or +Xbetter, using data the wrong way), but here the error can be glanced +Xfrom the object type(s) alone. +XThe detail shows in what context the error was detected. +X\end{itemize} +X +X\subsubsection{Handling Exceptions} +X +XIt is possible to write programs that handle selected exceptions. +XLook at the following example, which prints a table of inverses of +Xsome floating point numbers: +X\bcode\begin{verbatim} +X>>> numbers = [0.3333, 2.5, 0.0, 10.0] +X>>> for x in numbers: +X... print x, +X... try: +X... print 1.0 / x +X... except RuntimeError: +X... print '*** has no inverse ***' +X... +X0.3333 3.00030003 +X2.5 0.4 +X0 *** has no inverse *** +X10 0.1 +X>>> +X\end{verbatim}\ecode +XThe {\tt try} statement works as follows. +X\begin{itemize} +X\item +XFirst, the +X{\em try\ clause} +X(the statement(s) between the {\tt try} and {\tt except} keywords) is +Xexecuted. +X\item +XIf no exception occurs, the +X{\em except\ clause} +Xis skipped and execution of the {\tt try} statement is finished. +X\item +XIf an exception occurs during execution of the try clause, and its +Xtype matches the exception named after the {\tt except} keyword, the +Xrest of the try clause is skipped, the except clause is executed, and +Xthen execution continues after the {\tt try} statement. +X\item +XIf an exception occurs which does not match the exception named in the +Xexcept clause, it is passed on to outer try statements; if no handler is +Xfound, it is an +X{\em unhandled\ exception} +Xand execution stops with a message as shown above. +X\end{itemize} +XA {\tt try} statement may have more than one except clause, to specify +Xhandlers for different exceptions. +XAt most one handler will be executed. +XHandlers only handle exceptions that occur in the corresponding try +Xclause, not in other handlers of the same {\tt try} statement. +XAn except clause may name multiple exceptions as a parenthesized list, +Xe.g.: +X\bcode\begin{verbatim} +X... except (RuntimeError, TypeError, NameError): +X... pass +X\end{verbatim}\ecode +XThe last except clause may omit the exception name(s), to serve as a +Xwildcard. +XUse this with extreme caution! +X +XWhen an exception occurs, it may have an associated value, also known as +Xthe exceptions's +X{\em argument}. +XThe presence and type of the argument depend on the exception type. +XFor exception types which have an argument, the except clause may +Xspecify a variable after the exception name (or list) to receive the +Xargument's value, as follows: +X\bcode\begin{verbatim} +X>>> try: +X... foo() +X... except NameError, x: +X... print 'name', x, 'undefined' +X... +Xname foo undefined +X>>> +X\end{verbatim}\ecode +XIf an exception has an argument, it is printed as the third part +X(`detail') of the message for unhandled exceptions. +X +XStandard exception names are built-in identifiers (not reserved +Xkeywords). +XThese are in fact string objects whose +X{\em object\ identity} +X(not their value!) identifies the exceptions.% +X\footnote{ +X There should really be a separate exception type; it is pure +X laziness that exceptions are identified by strings, and this may +X be fixed in the future. +X} +XThe string is printed as the second part of the message for unhandled +Xexceptions. +XTheir names and values are: +X\bcode\begin{verbatim} +XEOFError 'end-of-file read' +XKeyboardInterrupt 'keyboard interrupt' +XMemoryError 'out of memory' * +XNameError 'undefined name' * +XRuntimeError 'run-time error' * +XSystemError 'system error' * +XTypeError 'type error' * +X\end{verbatim}\ecode +XThe meanings should be clear enough. +XThose exceptions with a {\tt *} in the third column have an argument. +X +XException handlers don't just handle exceptions if they occur +Ximmediately in the try clause, but also if they occur inside functions +Xthat are called (even indirectly) in the try clause. +XFor example: +X\bcode\begin{verbatim} +X>>> def this_fails(): +X... x = 1/0 +X... +X>>> try: +X... this_fails() +X... except RuntimeError, detail: +X... print 'Handling run-time error:', detail +X... +XHandling run-time error: domain error or zero division +X>>> +X\end{verbatim}\ecode +X +X\subsubsection{Raising Exceptions} +X +XThe {\tt raise} statement allows the programmer to force a specified +Xexception to occur. +XFor example: +X\bcode\begin{verbatim} +X>>> raise NameError, 'Hi There!' +XUnhandled exception: undefined name: Hi There! +XStack backtrace (innermost last): +X File "<stdin>", line 1 +X>>> +X\end{verbatim}\ecode +XThe first argument to {\tt raise} names the exception to be raised. +XThe optional second argument specifies the exception's argument. +X +X\subsubsection{User-defined Exceptions} +X +XPrograms may name their own exceptions by assigning a string to a +Xvariable. +XFor example: +X\bcode\begin{verbatim} +X>>> my_exc = 'nobody likes me!' +X>>> try: +X... raise my_exc, 2*2 +X... except my_exc, val: +X... print 'My exception occured, value:', val +X... +XMy exception occured, value: 4 +X>>> raise my_exc, 1 +XUnhandled exception: nobody likes me!: 1 +XStack backtrace (innermost last): +X File "<stdin>", line 7 +X>>> +X\end{verbatim}\ecode +XMany standard modules use this to report errors that may occur in +Xfunctions they define. +X +X\subsubsection{Defining Clean-up Actions} +X +XThe {\tt try} statement has another optional clause which is intended to +Xdefine clean-up actions that must be executed under all circumstances. +XFor example: +X\bcode\begin{verbatim} +X>>> try: +X... raise KeyboardInterrupt +X... finally: +X... print 'Goodbye, world!' +X... +XGoodbye, world! +XUnhandled exception: keyboard interrupt +XStack backtrace (innermost last): +X File "<stdin>", line 2 +X>>> +X\end{verbatim}\ecode +XThe +X{\em finally\ clause} +Xmust follow the except clauses(s), if any. +XIt is executed whether or not an exception occurred. +XIf the exception is handled, the finally clause is executed after the +Xhandler (and even if another exception occurred in the handler). +XIt is also executed when the {\tt try} statement is left via a +X{\tt break} or {\tt return} statement. +X +X\subsection{Classes} +X +XClasses in \Python\ make it possible to play the game of encapsulation in a +Xsomewhat different way than it is played with modules. +XClasses are an advanced topic and are probably best skipped on the first +Xencounter with \Python. +X +X\subsubsection{Prologue} +X +X\Python's class mechanism is not particularly elegant, but quite powerful. +XIt is a mixture of the class mechanisms found in C++ and Modula-3. +XAs is true for modules, classes in \Python\ do not put an absolute barrier +Xbetween definition and user, but rather rely on the politeness of the +Xuser not to ``break into the definition.'' +XThe most important features of classes are retained with full power, +Xhowever: the class inheritance mechanism allows multiple base classes, +Xa derived class can override any method of its base class(es), a method +Xcan call the method of a base class with the same name. +XObjects can contain an arbitrary amount of private data. +X +XIn C++ terminology, all class members (including data members) are +X{\em public}, +Xand all member functions (methods) are +X{\em virtual}. +XThere are no special constructors or destructors. +XAs in Modula-3, there are no shorthands for referencing the object's +Xmembers from its methods: the method function is declared with an +Xexplicit first argument representing the object, which is provided +Ximplicitly by the call. +XAs in Smalltalk, classes themselves are objects, albeit in the wider +Xsense of the word: in \Python, all data types are objects. +XThis provides semantics for renaming or aliasing. +XBut, just like in C++ or Modula-3, the built-in types cannot be used as +Xbase classes for extension by the user. +XAlso, like Modula-3 but unlike C++, the built-in operators with special +Xsyntax (arithmetic operators, subscripting etc.) cannot be redefined for +Xclass members.% +X\footnote{ +X They can be redefined for new object types implemented in C in +X extensions to the interpreter, however. It would require only a +X naming convention and a relatively small change to the +X interpreter to allow operator overloading for classes, so +X perhaps someday... +X} +X +X\subsubsection{A Simple Example} +X +XConsider the following example, which defines a class {\tt Set} +Xrepresenting a (finite) mathematical set with operations to add and +Xremove elements, a membership test, and a request for the size of the +Xset. +X\bcode\begin{verbatim} +Xclass Set(): +X def new(self): +X self.elements = [] +X return self +X def add(self, e): +X if e not in self.elements: +X self.elements.append(e) +X def remove(self, e): +X if e in self.elements: +X for i in range(len(self.elements)): +X if self.elements[i] = e: +X del self.elements[i] +X break +X def is_element(self, e): +X return e in self.elements +X def size(self): +X return len(self.elements) +X\end{verbatim}\ecode +XNote that the class definition looks like a big compound statement, +Xwith all the function definitons indented repective to the +X{\tt class} +Xkeyword. +X +XLet's assume that this +X{\em class\ definition} +Xis the only contents of the module file +X{\tt SetClass.py}. +XWe can then use it in a \Python\ program as follows: +X\bcode\begin{verbatim} +X>>> from SetClass import Set +X>>> a = Set().new() # create a Set object +X>>> a.add(2) +X>>> a.add(3) +X>>> a.add(1) +X>>> a.add(1) +X>>> if a.is_element(3): print '3 is in the set' +X... +X3 is in the set +X>>> if not a.is_element(4): print '4 is not in the set' +X... +X4 is not in the set +X>>> print 'a has', a.size(), 'elements' +Xa has 3 elements +X>>> a.remove(1) +X>>> print 'now a has', a.size(), 'elements' +X>>> +Xnow a has 2 elements +X>>> +X\end{verbatim}\ecode +XFrom the example we learn in the first place that the functions defined +Xin the class (e.g., +X{\tt add}) +Xcan be called using the +X{\em member} +Xnotation for the object +X{\tt a}. +XThe member function is called with one less argument than it is defined: +Xthe object is implicitly passed as the first argument. +XThus, the call +X{\tt a.add(2)} +Xis equivalent to +X{\tt Set.add(a, 2)}. +X +XXXX This section is not complete yet! +X +X\section{XXX P.M.} +X +X\begin{itemize} +X\item The {\tt del} statement. +X\item The {\tt dir()} function. +X\item Tuples. +X\item Dictionaries. +X\item Objects and types in general. +X\item Backquotes. +X\item And/Or/Not. +X\end{itemize} +X +X\end{document} +EOF +fi +echo 'Part 01 out of 21 of pack.out complete.' +exit 0 diff --git a/shar/python-0.9.1-01.patch b/shar/python-0.9.1-01.patch new file mode 100644 index 0000000..b27b7f6 --- /dev/null +++ b/shar/python-0.9.1-01.patch @@ -0,0 +1,163 @@ +Here is official patch #1 for Python. It fixes an embarrassing bug in +patchlevel.h, fixes the testall.py module to work non-interactively, and +adds some comments and a fix to the Makefile. +IMPORTANT NOTE: Use "patch -p <thisfile" in the top level directory of +the Python distribution. + +--Guido van Rossum <[email protected]> + +*** /usr/people/guido/python-dist/src/Makefile Tue Feb 19 13:42:10 1991 +--- src/Makefile Wed Feb 20 13:37:32 1991 +*************** +*** 65,74 **** +# Installation Options +# ==================== + +! # You may want to change PYTHONPATH to reflect where you install the +! # Python module library. + +! PYTHONPATH= .:/usr/local/lib/python:/ufs/guido/lib/python + + +# For "Pure" BSD Systems +--- 65,76 ---- +# 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 +*************** +*** 248,257 **** +# about 70K to the Python text size and about 260K to the unstripped +# binary size. +# +! # Note: the file 'glmodule.c' is created by a Python script. If you +! # lost the file and have no working Python interpreter, turn off the GL +! # and Panel options, rebuild the Python interpreter, use it to create +! # glmodule.c, and then turn the options back on. +# +# Uncomment the following block to use the GL option. + +--- 250,265 ---- +# 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. + +*************** +*** 270,276 **** +# 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. +# +# Uncomment and edit the following block to use the Panel option. +# - Edit the PANELDIR definition to point to the top-level directory +--- 278,286 ---- +# 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 +*************** +*** 335,341 **** +tupleobject.c typeobject.c + +CONFIGDEFS= $(STDW_USE) $(AM_USE) $(AUDIO_USE) $(GL_USE) $(PANEL_USE) \ +! '-DPYTHONPATH="$(PYTHONPATH)"' + +CONFIGINCLS= $(STDW_INCL) + +--- 345,351 ---- +tupleobject.c typeobject.c + +CONFIGDEFS= $(STDW_USE) $(AM_USE) $(AUDIO_USE) $(GL_USE) $(PANEL_USE) \ +! '-DPYTHONPATH="$(DEFPYTHONPATH)"' + +CONFIGINCLS= $(STDW_INCL) + +*************** +*** 480,486 **** +# The rules for doing so are given here. + +# Build "glmodule.c", the GL interface. +! # Ignore the messages emitted by the cgen script. +# Also ignore the warnings emitted while compiling glmodule.c; it works. + +glmodule.c: cstubs cgen +--- 490,499 ---- +# 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 +*** /usr/people/guido/python-dist/src/patchlevel.h Tue Feb 19 13:44:44 1991 +--- src/patchlevel.h Wed Feb 20 12:57:39 1991 +*************** +*** 1 **** +! 1 +--- 1 ---- +! #define PATCHLEVEL 1 +*** /usr/people/guido/python-dist/lib/testall.py Wed Dec 26 15:40:20 1990 +--- lib/testall.py Wed Feb 20 12:59:22 1991 +*************** +*** 122,128 **** +[4] +from math import * +[5] +! from sys import modules, ps1, ps2 +[6] + +### compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef +--- 122,128 ---- +[4] +from math import * +[5] +! from sys import modules, path +[6] + +### compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef +*************** +*** 213,219 **** +x = +1 +x = -1 +x = 1 +! c = sys.ps1[0] +x = time.time() +x = sys.modules['time'].time() +a = '01234' +--- 213,219 ---- +x = +1 +x = -1 +x = 1 +! c = sys.path[0] +x = time.time() +x = sys.modules['time'].time() +a = '01234'
\ No newline at end of file diff --git a/shar/python-0.9.1-03-21.shar b/shar/python-0.9.1-03-21.shar new file mode 100644 index 0000000..b2f6af5 --- /dev/null +++ b/shar/python-0.9.1-03-21.shar @@ -0,0 +1,2944 @@ +: This is a shell archive. +: Extract with 'sh this_file'. +: +: Extract part 01 first since it makes all directories +echo 'Start of pack.out, part 03 out of 21:' +if test -s 'src/compile.c' +then echo '*** I will not over-write existing file src/compile.c' +else +echo 'x - src/compile.c' +sed 's/^X//' > 'src/compile.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Compile an expression node to intermediate code */ +X +X/* XXX TO DO: +X XXX Compute maximum needed stack sizes while compiling +X XXX Generate simple jump for break/return outside 'try...finally' +X XXX Include function name in code (and module names?) +X*/ +X +X#include "allobjects.h" +X +X#include "node.h" +X#include "token.h" +X#include "graminit.h" +X#include "compile.h" +X#include "opcode.h" +X#include "structmember.h" +X +X#include <ctype.h> +X +X#define OFF(x) offsetof(codeobject, x) +X +Xstatic struct memberlist code_memberlist[] = { +X {"co_code", T_OBJECT, OFF(co_code)}, +X {"co_consts", T_OBJECT, OFF(co_consts)}, +X {"co_names", T_OBJECT, OFF(co_names)}, +X {"co_filename", T_OBJECT, OFF(co_filename)}, +X {NULL} /* Sentinel */ +X}; +X +Xstatic object * +Xcode_getattr(co, name) +X codeobject *co; +X char *name; +X{ +X return getmember((char *)co, code_memberlist, name); +X} +X +Xstatic void +Xcode_dealloc(co) +X codeobject *co; +X{ +X XDECREF(co->co_code); +X XDECREF(co->co_consts); +X XDECREF(co->co_names); +X XDECREF(co->co_filename); +X DEL(co); +X} +X +Xtypeobject Codetype = { +X OB_HEAD_INIT(&Typetype) +X 0, +X "code", +X sizeof(codeobject), +X 0, +X code_dealloc, /*tp_dealloc*/ +X 0, /*tp_print*/ +X code_getattr, /*tp_getattr*/ +X 0, /*tp_setattr*/ +X 0, /*tp_compare*/ +X 0, /*tp_repr*/ +X 0, /*tp_as_number*/ +X 0, /*tp_as_sequence*/ +X 0, /*tp_as_mapping*/ +X}; +X +Xstatic codeobject *newcodeobject PROTO((object *, object *, object *, char *)); +X +Xstatic codeobject * +Xnewcodeobject(code, consts, names, filename) +X object *code; +X object *consts; +X object *names; +X char *filename; +X{ +X codeobject *co; +X int i; +X /* Check argument types */ +X if (code == NULL || !is_stringobject(code) || +X consts == NULL || !is_listobject(consts) || +X names == NULL || !is_listobject(names)) { +X err_badcall(); +X return NULL; +X } +X /* Make sure the list of names contains only strings */ +X for (i = getlistsize(names); --i >= 0; ) { +X object *v = getlistitem(names, i); +X if (v == NULL || !is_stringobject(v)) { +X err_badcall(); +X return NULL; +X } +X } +X co = NEWOBJ(codeobject, &Codetype); +X if (co != NULL) { +X INCREF(code); +X co->co_code = (stringobject *)code; +X INCREF(consts); +X co->co_consts = consts; +X INCREF(names); +X co->co_names = names; +X if ((co->co_filename = newstringobject(filename)) == NULL) { +X DECREF(co); +X co = NULL; +X } +X } +X return co; +X} +X +X +X/* Data structure used internally */ +Xstruct compiling { +X object *c_code; /* string */ +X object *c_consts; /* list of objects */ +X object *c_names; /* list of strings (names) */ +X int c_nexti; /* index into c_code */ +X int c_errors; /* counts errors occurred */ +X int c_infunction; /* set when compiling a function */ +X int c_loops; /* counts nested loops */ +X char *c_filename; /* filename of current node */ +X}; +X +X/* Prototypes */ +Xstatic int com_init PROTO((struct compiling *, char *)); +Xstatic void com_free PROTO((struct compiling *)); +Xstatic void com_done PROTO((struct compiling *)); +Xstatic void com_node PROTO((struct compiling *, struct _node *)); +Xstatic void com_addbyte PROTO((struct compiling *, int)); +Xstatic void com_addint PROTO((struct compiling *, int)); +Xstatic void com_addoparg PROTO((struct compiling *, int, int)); +Xstatic void com_addfwref PROTO((struct compiling *, int, int *)); +Xstatic void com_backpatch PROTO((struct compiling *, int)); +Xstatic int com_add PROTO((struct compiling *, object *, object *)); +Xstatic int com_addconst PROTO((struct compiling *, object *)); +Xstatic int com_addname PROTO((struct compiling *, object *)); +Xstatic void com_addopname PROTO((struct compiling *, int, node *)); +X +Xstatic int +Xcom_init(c, filename) +X struct compiling *c; +X char *filename; +X{ +X if ((c->c_code = newsizedstringobject((char *)NULL, 0)) == NULL) +X goto fail_3; +X if ((c->c_consts = newlistobject(0)) == NULL) +X goto fail_2; +X if ((c->c_names = newlistobject(0)) == NULL) +X goto fail_1; +X c->c_nexti = 0; +X c->c_errors = 0; +X c->c_infunction = 0; +X c->c_loops = 0; +X c->c_filename = filename; +X return 1; +X +X fail_1: +X DECREF(c->c_consts); +X fail_2: +X DECREF(c->c_code); +X fail_3: +X return 0; +X} +X +Xstatic void +Xcom_free(c) +X struct compiling *c; +X{ +X XDECREF(c->c_code); +X XDECREF(c->c_consts); +X XDECREF(c->c_names); +X} +X +Xstatic void +Xcom_done(c) +X struct compiling *c; +X{ +X if (c->c_code != NULL) +X resizestring(&c->c_code, c->c_nexti); +X} +X +Xstatic void +Xcom_addbyte(c, byte) +X struct compiling *c; +X int byte; +X{ +X int len; +X if (byte < 0 || byte > 255) { +X fprintf(stderr, "XXX compiling bad byte: %d\n", byte); +X abort(); +X err_setstr(SystemError, "com_addbyte: byte out of range"); +X c->c_errors++; +X } +X if (c->c_code == NULL) +X return; +X len = getstringsize(c->c_code); +X if (c->c_nexti >= len) { +X if (resizestring(&c->c_code, len+1000) != 0) { +X c->c_errors++; +X return; +X } +X } +X getstringvalue(c->c_code)[c->c_nexti++] = byte; +X} +X +Xstatic void +Xcom_addint(c, x) +X struct compiling *c; +X int x; +X{ +X com_addbyte(c, x & 0xff); +X com_addbyte(c, x >> 8); /* XXX x should be positive */ +X} +X +Xstatic void +Xcom_addoparg(c, op, arg) +X struct compiling *c; +X int op; +X int arg; +X{ +X com_addbyte(c, op); +X com_addint(c, arg); +X} +X +Xstatic void +Xcom_addfwref(c, op, p_anchor) +X struct compiling *c; +X int op; +X int *p_anchor; +X{ +X /* Compile a forward reference for backpatching */ +X int here; +X int anchor; +X com_addbyte(c, op); +X here = c->c_nexti; +X anchor = *p_anchor; +X *p_anchor = here; +X com_addint(c, anchor == 0 ? 0 : here - anchor); +X} +X +Xstatic void +Xcom_backpatch(c, anchor) +X struct compiling *c; +X int anchor; /* Must be nonzero */ +X{ +X unsigned char *code = (unsigned char *) getstringvalue(c->c_code); +X int target = c->c_nexti; +X int lastanchor = 0; +X int dist; +X int prev; +X for (;;) { +X /* Make the JUMP instruction at anchor point to target */ +X prev = code[anchor] + (code[anchor+1] << 8); +X dist = target - (anchor+2); +X code[anchor] = dist & 0xff; +X code[anchor+1] = dist >> 8; +X if (!prev) +X break; +X lastanchor = anchor; +X anchor -= prev; +X } +X} +X +X/* Handle constants and names uniformly */ +X +Xstatic int +Xcom_add(c, list, v) +X struct compiling *c; +X object *list; +X object *v; +X{ +X int n = getlistsize(list); +X int i; +X for (i = n; --i >= 0; ) { +X object *w = getlistitem(list, i); +X if (cmpobject(v, w) == 0) +X return i; +X } +X if (addlistitem(list, v) != 0) +X c->c_errors++; +X return n; +X} +X +Xstatic int +Xcom_addconst(c, v) +X struct compiling *c; +X object *v; +X{ +X return com_add(c, c->c_consts, v); +X} +X +Xstatic int +Xcom_addname(c, v) +X struct compiling *c; +X object *v; +X{ +X return com_add(c, c->c_names, v); +X} +X +Xstatic void +Xcom_addopname(c, op, n) +X struct compiling *c; +X int op; +X node *n; +X{ +X object *v; +X int i; +X char *name; +X if (TYPE(n) == STAR) +X name = "*"; +X else { +X REQ(n, NAME); +X name = STR(n); +X } +X if ((v = newstringobject(name)) == NULL) { +X c->c_errors++; +X i = 255; +X } +X else { +X i = com_addname(c, v); +X DECREF(v); +X } +X com_addoparg(c, op, i); +X} +X +Xstatic object * +Xparsenumber(s) +X char *s; +X{ +X extern long strtol(); +X extern double atof(); +X char *end = s; +X long x; +X x = strtol(s, &end, 0); +X if (*end == '\0') +X return newintobject(x); +X if (*end == '.' || *end == 'e' || *end == 'E') +X return newfloatobject(atof(s)); +X err_setstr(RuntimeError, "bad number syntax"); +X return NULL; +X} +X +Xstatic object * +Xparsestr(s) +X char *s; +X{ +X object *v; +X int len; +X char *buf; +X char *p; +X int c; +X if (*s != '\'') { +X err_badcall(); +X return NULL; +X } +X s++; +X len = strlen(s); +X if (s[--len] != '\'') { +X err_badcall(); +X return NULL; +X } +X if (strchr(s, '\\') == NULL) +X return newsizedstringobject(s, len); +X v = newsizedstringobject((char *)NULL, len); +X p = buf = getstringvalue(v); +X while (*s != '\0' && *s != '\'') { +X if (*s != '\\') { +X *p++ = *s++; +X continue; +X } +X s++; +X switch (*s++) { +X /* XXX This assumes ASCII! */ +X case '\\': *p++ = '\\'; break; +X case '\'': *p++ = '\''; break; +X case 'b': *p++ = '\b'; break; +X case 'f': *p++ = '\014'; break; /* FF */ +X case 't': *p++ = '\t'; break; +X case 'n': *p++ = '\n'; break; +X case 'r': *p++ = '\r'; break; +X case 'v': *p++ = '\013'; break; /* VT */ +X case 'E': *p++ = '\033'; break; /* ESC, not C */ +X case 'a': *p++ = '\007'; break; /* BEL, not classic C */ +X case '0': case '1': case '2': case '3': +X case '4': case '5': case '6': case '7': +X c = s[-1] - '0'; +X if ('0' <= *s && *s <= '7') { +X c = (c<<3) + *s++ - '0'; +X if ('0' <= *s && *s <= '7') +X c = (c<<3) + *s++ - '0'; +X } +X *p++ = c; +X break; +X case 'x': +X if (isxdigit(*s)) { +X sscanf(s, "%x", &c); +X *p++ = c; +X do { +X s++; +X } while (isxdigit(*s)); +X break; +X } +X /* FALLTHROUGH */ +X default: *p++ = '\\'; *p++ = s[-1]; break; +X } +X } +X resizestring(&v, (int)(p - buf)); +X return v; +X} +X +Xstatic void +Xcom_list_constructor(c, n) +X struct compiling *c; +X node *n; +X{ +X int len; +X int i; +X object *v, *w; +X if (TYPE(n) != testlist) +X REQ(n, exprlist); +X /* exprlist: expr (',' expr)* [',']; likewise for testlist */ +X len = (NCH(n) + 1) / 2; +X for (i = 0; i < NCH(n); i += 2) +X com_node(c, CHILD(n, i)); +X com_addoparg(c, BUILD_LIST, len); +X} +X +Xstatic void +Xcom_atom(c, n) +X struct compiling *c; +X node *n; +X{ +X node *ch; +X object *v; +X int i; +X REQ(n, atom); +X ch = CHILD(n, 0); +X switch (TYPE(ch)) { +X case LPAR: +X if (TYPE(CHILD(n, 1)) == RPAR) +X com_addoparg(c, BUILD_TUPLE, 0); +X else +X com_node(c, CHILD(n, 1)); +X break; +X case LSQB: +X if (TYPE(CHILD(n, 1)) == RSQB) +X com_addoparg(c, BUILD_LIST, 0); +X else +X com_list_constructor(c, CHILD(n, 1)); +X break; +X case LBRACE: +X com_addoparg(c, BUILD_MAP, 0); +X break; +X case BACKQUOTE: +X com_node(c, CHILD(n, 1)); +X com_addbyte(c, UNARY_CONVERT); +X break; +X case NUMBER: +X if ((v = parsenumber(STR(ch))) == NULL) { +X c->c_errors++; +X i = 255; +X } +X else { +X i = com_addconst(c, v); +X DECREF(v); +X } +X com_addoparg(c, LOAD_CONST, i); +X break; +X case STRING: +X if ((v = parsestr(STR(ch))) == NULL) { +X c->c_errors++; +X i = 255; +X } +X else { +X i = com_addconst(c, v); +X DECREF(v); +X } +X com_addoparg(c, LOAD_CONST, i); +X break; +X case NAME: +X com_addopname(c, LOAD_NAME, ch); +X break; +X default: +X fprintf(stderr, "node type %d\n", TYPE(ch)); +X err_setstr(SystemError, "com_atom: unexpected node type"); +X c->c_errors++; +X } +X} +X +Xstatic void +Xcom_slice(c, n, op) +X struct compiling *c; +X node *n; +X int op; +X{ +X if (NCH(n) == 1) { +X com_addbyte(c, op); +X } +X else if (NCH(n) == 2) { +X if (TYPE(CHILD(n, 0)) != COLON) { +X com_node(c, CHILD(n, 0)); +X com_addbyte(c, op+1); +X } +X else { +X com_node(c, CHILD(n, 1)); +X com_addbyte(c, op+2); +X } +X } +X else { +X com_node(c, CHILD(n, 0)); +X com_node(c, CHILD(n, 2)); +X com_addbyte(c, op+3); +X } +X} +X +Xstatic void +Xcom_apply_subscript(c, n) +X struct compiling *c; +X node *n; +X{ +X REQ(n, subscript); +X if (NCH(n) == 1 && TYPE(CHILD(n, 0)) != COLON) { +X /* It's a single subscript */ +X com_node(c, CHILD(n, 0)); +X com_addbyte(c, BINARY_SUBSCR); +X } +X else { +X /* It's a slice: [expr] ':' [expr] */ +X com_slice(c, n, SLICE); +X } +X} +X +Xstatic void +Xcom_call_function(c, n) +X struct compiling *c; +X node *n; /* EITHER testlist OR ')' */ +X{ +X if (TYPE(n) == RPAR) { +X com_addbyte(c, UNARY_CALL); +X } +X else { +X com_node(c, n); +X com_addbyte(c, BINARY_CALL); +X } +X} +X +Xstatic void +Xcom_select_member(c, n) +X struct compiling *c; +X node *n; +X{ +X com_addopname(c, LOAD_ATTR, n); +X} +X +Xstatic void +Xcom_apply_trailer(c, n) +X struct compiling *c; +X node *n; +X{ +X REQ(n, trailer); +X switch (TYPE(CHILD(n, 0))) { +X case LPAR: +X com_call_function(c, CHILD(n, 1)); +X break; +X case DOT: +X com_select_member(c, CHILD(n, 1)); +X break; +X case LSQB: +X com_apply_subscript(c, CHILD(n, 1)); +X break; +X default: +X err_setstr(SystemError, +X "com_apply_trailer: unknown trailer type"); +X c->c_errors++; +X } +X} +X +Xstatic void +Xcom_factor(c, n) +X struct compiling *c; +X node *n; +X{ +X int i; +X REQ(n, factor); +X if (TYPE(CHILD(n, 0)) == PLUS) { +X com_factor(c, CHILD(n, 1)); +X com_addbyte(c, UNARY_POSITIVE); +X } +X else if (TYPE(CHILD(n, 0)) == MINUS) { +X com_factor(c, CHILD(n, 1)); +X com_addbyte(c, UNARY_NEGATIVE); +X } +X else { +X com_atom(c, CHILD(n, 0)); +X for (i = 1; i < NCH(n); i++) +X com_apply_trailer(c, CHILD(n, i)); +X } +X} +X +Xstatic void +Xcom_term(c, n) +X struct compiling *c; +X node *n; +X{ +X int i; +X int op; +X REQ(n, term); +X com_factor(c, CHILD(n, 0)); +X for (i = 2; i < NCH(n); i += 2) { +X com_factor(c, CHILD(n, i)); +X switch (TYPE(CHILD(n, i-1))) { +X case STAR: +X op = BINARY_MULTIPLY; +X break; +X case SLASH: +X op = BINARY_DIVIDE; +X break; +X case PERCENT: +X op = BINARY_MODULO; +X break; +X default: +X err_setstr(SystemError, +X "com_term: term operator not *, / or %"); +X c->c_errors++; +X op = 255; +X } +X com_addbyte(c, op); +X } +X} +X +Xstatic void +Xcom_expr(c, n) +X struct compiling *c; +X node *n; +X{ +X int i; +X int op; +X REQ(n, expr); +X com_term(c, CHILD(n, 0)); +X for (i = 2; i < NCH(n); i += 2) { +X com_term(c, CHILD(n, i)); +X switch (TYPE(CHILD(n, i-1))) { +X case PLUS: +X op = BINARY_ADD; +X break; +X case MINUS: +X op = BINARY_SUBTRACT; +X break; +X default: +X err_setstr(SystemError, +X "com_expr: expr operator not + or -"); +X c->c_errors++; +X op = 255; +X } +X com_addbyte(c, op); +X } +X} +X +Xstatic enum cmp_op +Xcmp_type(n) +X node *n; +X{ +X REQ(n, comp_op); +X /* comp_op: '<' | '>' | '=' | '>' '=' | '<' '=' | '<' '>' +X | 'in' | 'not' 'in' | 'is' | 'is' not' */ +X if (NCH(n) == 1) { +X n = CHILD(n, 0); +X switch (TYPE(n)) { +X case LESS: return LT; +X case GREATER: return GT; +X case EQUAL: return EQ; +X case NAME: if (strcmp(STR(n), "in") == 0) return IN; +X if (strcmp(STR(n), "is") == 0) return IS; +X } +X } +X else if (NCH(n) == 2) { +X int t2 = TYPE(CHILD(n, 1)); +X switch (TYPE(CHILD(n, 0))) { +X case LESS: if (t2 == EQUAL) return LE; +X if (t2 == GREATER) return NE; +X break; +X case GREATER: if (t2 == EQUAL) return GE; +X break; +X case NAME: if (strcmp(STR(CHILD(n, 1)), "in") == 0) +X return NOT_IN; +X if (strcmp(STR(CHILD(n, 0)), "is") == 0) +X return IS_NOT; +X } +X } +X return BAD; +X} +X +Xstatic void +Xcom_comparison(c, n) +X struct compiling *c; +X node *n; +X{ +X int i; +X enum cmp_op op; +X int anchor; +X REQ(n, comparison); /* comparison: expr (comp_op expr)* */ +X com_expr(c, CHILD(n, 0)); +X if (NCH(n) == 1) +X return; +X +X /**************************************************************** +X The following code is generated for all but the last +X comparison in a chain: +X +X label: on stack: opcode: jump to: +X +X a <code to load b> +X a, b DUP_TOP +X a, b, b ROT_THREE +X b, a, b COMPARE_OP +X b, 0-or-1 JUMP_IF_FALSE L1 +X b, 1 POP_TOP +X b +X +X We are now ready to repeat this sequence for the next +X comparison in the chain. +X +X For the last we generate: +X +X b <code to load c> +X b, c COMPARE_OP +X 0-or-1 +X +X If there were any jumps to L1 (i.e., there was more than one +X comparison), we generate: +X +X 0-or-1 JUMP_FORWARD L2 +X L1: b, 0 ROT_TWO +X 0, b POP_TOP +X 0 +X L2: +X ****************************************************************/ +X +X anchor = 0; +X +X for (i = 2; i < NCH(n); i += 2) { +X com_expr(c, CHILD(n, i)); +X if (i+2 < NCH(n)) { +X com_addbyte(c, DUP_TOP); +X com_addbyte(c, ROT_THREE); +X } +X op = cmp_type(CHILD(n, i-1)); +X if (op == BAD) { +X err_setstr(SystemError, +X "com_comparison: unknown comparison op"); +X c->c_errors++; +X } +X com_addoparg(c, COMPARE_OP, op); +X if (i+2 < NCH(n)) { +X com_addfwref(c, JUMP_IF_FALSE, &anchor); +X com_addbyte(c, POP_TOP); +X } +X } +X +X if (anchor) { +X int anchor2 = 0; +X com_addfwref(c, JUMP_FORWARD, &anchor2); +X com_backpatch(c, anchor); +X com_addbyte(c, ROT_TWO); +X com_addbyte(c, POP_TOP); +X com_backpatch(c, anchor2); +X } +X} +X +Xstatic void +Xcom_not_test(c, n) +X struct compiling *c; +X node *n; +X{ +X REQ(n, not_test); /* 'not' not_test | comparison */ +X if (NCH(n) == 1) { +X com_comparison(c, CHILD(n, 0)); +X } +X else { +X com_not_test(c, CHILD(n, 1)); +X com_addbyte(c, UNARY_NOT); +X } +X} +X +Xstatic void +Xcom_and_test(c, n) +X struct compiling *c; +X node *n; +X{ +X int i; +X int anchor; +X REQ(n, and_test); /* not_test ('and' not_test)* */ +X anchor = 0; +X i = 0; +X for (;;) { +X com_not_test(c, CHILD(n, i)); +X if ((i += 2) >= NCH(n)) +X break; +X com_addfwref(c, JUMP_IF_FALSE, &anchor); +X com_addbyte(c, POP_TOP); +X } +X if (anchor) +X com_backpatch(c, anchor); +X} +X +Xstatic void +Xcom_test(c, n) +X struct compiling *c; +X node *n; +X{ +X int i; +X int anchor; +X REQ(n, test); /* and_test ('and' and_test)* */ +X anchor = 0; +X i = 0; +X for (;;) { +X com_and_test(c, CHILD(n, i)); +X if ((i += 2) >= NCH(n)) +X break; +X com_addfwref(c, JUMP_IF_TRUE, &anchor); +X com_addbyte(c, POP_TOP); +X } +X if (anchor) +X com_backpatch(c, anchor); +X} +X +Xstatic void +Xcom_list(c, n) +X struct compiling *c; +X node *n; +X{ +X /* exprlist: expr (',' expr)* [',']; likewise for testlist */ +X if (NCH(n) == 1) { +X com_node(c, CHILD(n, 0)); +X } +X else { +X int i; +X int len; +X len = (NCH(n) + 1) / 2; +X for (i = 0; i < NCH(n); i += 2) +X com_node(c, CHILD(n, i)); +X com_addoparg(c, BUILD_TUPLE, len); +X } +X} +X +X +X/* Begin of assignment compilation */ +X +Xstatic void com_assign_name PROTO((struct compiling *, node *, int)); +Xstatic void com_assign PROTO((struct compiling *, node *, int)); +X +Xstatic void +Xcom_assign_attr(c, n, assigning) +X struct compiling *c; +X node *n; +X int assigning; +X{ +X com_addopname(c, assigning ? STORE_ATTR : DELETE_ATTR, n); +X} +X +Xstatic void +Xcom_assign_slice(c, n, assigning) +X struct compiling *c; +X node *n; +X int assigning; +X{ +X com_slice(c, n, assigning ? STORE_SLICE : DELETE_SLICE); +X} +X +Xstatic void +Xcom_assign_subscript(c, n, assigning) +X struct compiling *c; +X node *n; +X int assigning; +X{ +X com_node(c, n); +X com_addbyte(c, assigning ? STORE_SUBSCR : DELETE_SUBSCR); +X} +X +Xstatic void +Xcom_assign_trailer(c, n, assigning) +X struct compiling *c; +X node *n; +X int assigning; +X{ +X char *name; +X REQ(n, trailer); +X switch (TYPE(CHILD(n, 0))) { +X case LPAR: /* '(' [exprlist] ')' */ +X err_setstr(TypeError, "can't assign to function call"); +X c->c_errors++; +X break; +X case DOT: /* '.' NAME */ +X com_assign_attr(c, CHILD(n, 1), assigning); +X break; +X case LSQB: /* '[' subscript ']' */ +X n = CHILD(n, 1); +X REQ(n, subscript); /* subscript: expr | [expr] ':' [expr] */ +X if (NCH(n) > 1 || TYPE(CHILD(n, 0)) == COLON) +X com_assign_slice(c, n, assigning); +X else +X com_assign_subscript(c, CHILD(n, 0), assigning); +X break; +X default: +X err_setstr(TypeError, "unknown trailer type"); +X c->c_errors++; +X } +X} +X +Xstatic void +Xcom_assign_tuple(c, n, assigning) +X struct compiling *c; +X node *n; +X int assigning; +X{ +X int i; +X if (TYPE(n) != testlist) +X REQ(n, exprlist); +X if (assigning) +X com_addoparg(c, UNPACK_TUPLE, (NCH(n)+1)/2); +X for (i = 0; i < NCH(n); i += 2) +X com_assign(c, CHILD(n, i), assigning); +X} +X +Xstatic void +Xcom_assign_list(c, n, assigning) +X struct compiling *c; +X node *n; +X int assigning; +X{ +X int i; +X if (assigning) +X com_addoparg(c, UNPACK_LIST, (NCH(n)+1)/2); +X for (i = 0; i < NCH(n); i += 2) +X com_assign(c, CHILD(n, i), assigning); +X} +X +Xstatic void +Xcom_assign_name(c, n, assigning) +X struct compiling *c; +X node *n; +X int assigning; +X{ +X REQ(n, NAME); +X com_addopname(c, assigning ? STORE_NAME : DELETE_NAME, n); +X} +X +Xstatic void +Xcom_assign(c, n, assigning) +X struct compiling *c; +X node *n; +X int assigning; +X{ +X /* Loop to avoid trivial recursion */ +X for (;;) { +X switch (TYPE(n)) { +X +X case exprlist: +X case testlist: +X if (NCH(n) > 1) { +X com_assign_tuple(c, n, assigning); +X return; +X } +X n = CHILD(n, 0); +X break; +X +X case test: +X case and_test: +X case not_test: +X if (NCH(n) > 1) { +X err_setstr(TypeError, +X "can't assign to operator"); +X c->c_errors++; +X return; +X } +X n = CHILD(n, 0); +X break; +X +X case comparison: +X if (NCH(n) > 1) { +X err_setstr(TypeError, +X "can't assign to operator"); +X c->c_errors++; +X return; +X } +X n = CHILD(n, 0); +X break; +X +X case expr: +X if (NCH(n) > 1) { +X err_setstr(TypeError, +X "can't assign to operator"); +X c->c_errors++; +X return; +X } +X n = CHILD(n, 0); +X break; +X +X case term: +X if (NCH(n) > 1) { +X err_setstr(TypeError, +X "can't assign to operator"); +X c->c_errors++; +X return; +X } +X n = CHILD(n, 0); +X break; +X +X case factor: /* ('+'|'-') factor | atom trailer* */ +X if (TYPE(CHILD(n, 0)) != atom) { /* '+' | '-' */ +X err_setstr(TypeError, +X "can't assign to operator"); +X c->c_errors++; +X return; +X } +X if (NCH(n) > 1) { /* trailer present */ +X int i; +X com_node(c, CHILD(n, 0)); +X for (i = 1; i+1 < NCH(n); i++) { +X com_apply_trailer(c, CHILD(n, i)); +X } /* NB i is still alive */ +X com_assign_trailer(c, +X CHILD(n, i), assigning); +X return; +X } +X n = CHILD(n, 0); +X break; +X +X case atom: +X switch (TYPE(CHILD(n, 0))) { +X case LPAR: +X n = CHILD(n, 1); +X if (TYPE(n) == RPAR) { +X /* XXX Should allow () = () ??? */ +X err_setstr(TypeError, +X "can't assign to ()"); +X c->c_errors++; +X return; +X } +X break; +X case LSQB: +X n = CHILD(n, 1); +X if (TYPE(n) == RSQB) { +X err_setstr(TypeError, +X "can't assign to []"); +X c->c_errors++; +X return; +X } +X com_assign_list(c, n, assigning); +X return; +X case NAME: +X com_assign_name(c, CHILD(n, 0), assigning); +X return; +X default: +X err_setstr(TypeError, +X "can't assign to constant"); +X c->c_errors++; +X return; +X } +X break; +X +X default: +X fprintf(stderr, "node type %d\n", TYPE(n)); +X err_setstr(SystemError, "com_assign: bad node"); +X c->c_errors++; +X return; +X +X } +X } +X} +X +Xstatic void +Xcom_expr_stmt(c, n) +X struct compiling *c; +X node *n; +X{ +X REQ(n, expr_stmt); /* exprlist ('=' exprlist)* NEWLINE */ +X com_node(c, CHILD(n, NCH(n)-2)); +X if (NCH(n) == 2) { +X com_addbyte(c, PRINT_EXPR); +X } +X else { +X int i; +X for (i = 0; i < NCH(n)-3; i+=2) { +X if (i+2 < NCH(n)-3) +X com_addbyte(c, DUP_TOP); +X com_assign(c, CHILD(n, i), 1/*assign*/); +X } +X } +X} +X +Xstatic void +Xcom_print_stmt(c, n) +X struct compiling *c; +X node *n; +X{ +X int i; +X REQ(n, print_stmt); /* 'print' (test ',')* [test] NEWLINE */ +X for (i = 1; i+1 < NCH(n); i += 2) { +X com_node(c, CHILD(n, i)); +X com_addbyte(c, PRINT_ITEM); +X } +X if (TYPE(CHILD(n, NCH(n)-2)) != COMMA) +X com_addbyte(c, PRINT_NEWLINE); +X /* XXX Alternatively, LOAD_CONST '\n' and then PRINT_ITEM */ +X} +X +Xstatic void +Xcom_return_stmt(c, n) +X struct compiling *c; +X node *n; +X{ +X REQ(n, return_stmt); /* 'return' [testlist] NEWLINE */ +X if (!c->c_infunction) { +X err_setstr(TypeError, "'return' outside function"); +X c->c_errors++; +X } +X if (NCH(n) == 2) +X com_addoparg(c, LOAD_CONST, com_addconst(c, None)); +X else +X com_node(c, CHILD(n, 1)); +X com_addbyte(c, RETURN_VALUE); +X} +X +Xstatic void +Xcom_raise_stmt(c, n) +X struct compiling *c; +X node *n; +X{ +X REQ(n, raise_stmt); /* 'raise' expr [',' expr] NEWLINE */ +X com_node(c, CHILD(n, 1)); +X if (NCH(n) > 3) +X com_node(c, CHILD(n, 3)); +X else +X com_addoparg(c, LOAD_CONST, com_addconst(c, None)); +X com_addbyte(c, RAISE_EXCEPTION); +X} +X +Xstatic void +Xcom_import_stmt(c, n) +X struct compiling *c; +X node *n; +X{ +X int i; +X REQ(n, import_stmt); +X /* 'import' NAME (',' NAME)* NEWLINE | +X 'from' NAME 'import' ('*' | NAME (',' NAME)*) NEWLINE */ +X if (STR(CHILD(n, 0))[0] == 'f') { +X /* 'from' NAME 'import' ... */ +X REQ(CHILD(n, 1), NAME); +X com_addopname(c, IMPORT_NAME, CHILD(n, 1)); +X for (i = 3; i < NCH(n); i += 2) +X com_addopname(c, IMPORT_FROM, CHILD(n, i)); +X com_addbyte(c, POP_TOP); +X } +X else { +X /* 'import' ... */ +X for (i = 1; i < NCH(n); i += 2) { +X com_addopname(c, IMPORT_NAME, CHILD(n, i)); +X com_addopname(c, STORE_NAME, CHILD(n, i)); +X } +X } +X} +X +Xstatic void +Xcom_if_stmt(c, n) +X struct compiling *c; +X node *n; +X{ +X int i; +X int anchor = 0; +X REQ(n, if_stmt); +X /*'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] */ +X for (i = 0; i+3 < NCH(n); i+=4) { +X int a = 0; +X node *ch = CHILD(n, i+1); +X if (i > 0) +X com_addoparg(c, SET_LINENO, ch->n_lineno); +X com_node(c, CHILD(n, i+1)); +X com_addfwref(c, JUMP_IF_FALSE, &a); +X com_addbyte(c, POP_TOP); +X com_node(c, CHILD(n, i+3)); +X com_addfwref(c, JUMP_FORWARD, &anchor); +X com_backpatch(c, a); +X com_addbyte(c, POP_TOP); +X } +X if (i+2 < NCH(n)) +X com_node(c, CHILD(n, i+2)); +X com_backpatch(c, anchor); +X} +X +Xstatic void +Xcom_while_stmt(c, n) +X struct compiling *c; +X node *n; +X{ +X int break_anchor = 0; +X int anchor = 0; +X int begin; +X REQ(n, while_stmt); /* 'while' test ':' suite ['else' ':' suite] */ +X com_addfwref(c, SETUP_LOOP, &break_anchor); +X begin = c->c_nexti; +X com_addoparg(c, SET_LINENO, n->n_lineno); +X com_node(c, CHILD(n, 1)); +X com_addfwref(c, JUMP_IF_FALSE, &anchor); +X com_addbyte(c, POP_TOP); +X c->c_loops++; +X com_node(c, CHILD(n, 3)); +X c->c_loops--; +X com_addoparg(c, JUMP_ABSOLUTE, begin); +X com_backpatch(c, anchor); +X com_addbyte(c, POP_TOP); +X com_addbyte(c, POP_BLOCK); +X if (NCH(n) > 4) +X com_node(c, CHILD(n, 6)); +X com_backpatch(c, break_anchor); +X} +X +Xstatic void +Xcom_for_stmt(c, n) +X struct compiling *c; +X node *n; +X{ +X object *v; +X int break_anchor = 0; +X int anchor = 0; +X int begin; +X REQ(n, for_stmt); +X /* 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] */ +X com_addfwref(c, SETUP_LOOP, &break_anchor); +X com_node(c, CHILD(n, 3)); +X v = newintobject(0L); +X if (v == NULL) +X c->c_errors++; +X com_addoparg(c, LOAD_CONST, com_addconst(c, v)); +X XDECREF(v); +X begin = c->c_nexti; +X com_addoparg(c, SET_LINENO, n->n_lineno); +X com_addfwref(c, FOR_LOOP, &anchor); +X com_assign(c, CHILD(n, 1), 1/*assigning*/); +X c->c_loops++; +X com_node(c, CHILD(n, 5)); +X c->c_loops--; +X com_addoparg(c, JUMP_ABSOLUTE, begin); +X com_backpatch(c, anchor); +X com_addbyte(c, POP_BLOCK); +X if (NCH(n) > 8) +X com_node(c, CHILD(n, 8)); +X com_backpatch(c, break_anchor); +X} +X +X/* Although 'execpt' and 'finally' clauses can be combined +X syntactically, they are compiled separately. In fact, +X try: S +X except E1: S1 +X except E2: S2 +X ... +X finally: Sf +X is equivalent to +X try: +X try: S +X except E1: S1 +X except E2: S2 +X ... +X finally: Sf +X meaning that the 'finally' clause is entered even if things +X go wrong again in an exception handler. Note that this is +X not the case for exception handlers: at most one is entered. +X +X Code generated for "try: S finally: Sf" is as follows: +X +X SETUP_FINALLY L +X <code for S> +X POP_BLOCK +X LOAD_CONST <nil> +X L: <code for Sf> +X END_FINALLY +X +X The special instructions use the block stack. Each block +X stack entry contains the instruction that created it (here +X SETUP_FINALLY), the level of the value stack at the time the +X block stack entry was created, and a label (here L). +X +X SETUP_FINALLY: +X Pushes the current value stack level and the label +X onto the block stack. +X POP_BLOCK: +X Pops en entry from the block stack, and pops the value +X stack until its level is the same as indicated on the +X block stack. (The label is ignored.) +X END_FINALLY: +X Pops a variable number of entries from the *value* stack +X and re-raises the exception they specify. The number of +X entries popped depends on the (pseudo) exception type. +X +X The block stack is unwound when an exception is raised: +X when a SETUP_FINALLY entry is found, the exception is pushed +X onto the value stack (and the exception condition is cleared), +X and the interpreter jumps to the label gotten from the block +X stack. +X +X Code generated for "try: S except E1, V1: S1 except E2, V2: S2 ...": +X (The contents of the value stack is shown in [], with the top +X at the right; 'tb' is trace-back info, 'val' the exception's +X associated value, and 'exc' the exception.) +X +X Value stack Label Instruction Argument +X [] SETUP_EXCEPT L1 +X [] <code for S> +X [] POP_BLOCK +X [] JUMP_FORWARD L0 +X +X [tb, val, exc] L1: DUP ) +X [tb, val, exc, exc] <evaluate E1> ) +X [tb, val, exc, exc, E1] COMPARE_OP EXC_MATCH ) only if E1 +X [tb, val, exc, 1-or-0] JUMP_IF_FALSE L2 ) +X [tb, val, exc, 1] POP ) +X [tb, val, exc] POP +X [tb, val] <assign to V1> (or POP if no V1) +X [tb] POP +X [] <code for S1> +X JUMP_FORWARD L0 +X +X [tb, val, exc, 0] L2: POP +X [tb, val, exc] DUP +X .............................etc....................... +X +X [tb, val, exc, 0] Ln+1: POP +X [tb, val, exc] END_FINALLY # re-raise exception +X +X [] L0: <next statement> +X +X Of course, parts are not generated if Vi or Ei is not present. +X*/ +X +Xstatic void +Xcom_try_stmt(c, n) +X struct compiling *c; +X node *n; +X{ +X int finally_anchor = 0; +X int except_anchor = 0; +X REQ(n, try_stmt); +X /* 'try' ':' suite (except_clause ':' suite)* ['finally' ':' suite] */ +X +X if (NCH(n) > 3 && TYPE(CHILD(n, NCH(n)-3)) != except_clause) { +X /* Have a 'finally' clause */ +X com_addfwref(c, SETUP_FINALLY, &finally_anchor); +X } +X if (NCH(n) > 3 && TYPE(CHILD(n, 3)) == except_clause) { +X /* Have an 'except' clause */ +X com_addfwref(c, SETUP_EXCEPT, &except_anchor); +X } +X com_node(c, CHILD(n, 2)); +X if (except_anchor) { +X int end_anchor = 0; +X int i; +X node *ch; +X com_addbyte(c, POP_BLOCK); +X com_addfwref(c, JUMP_FORWARD, &end_anchor); +X com_backpatch(c, except_anchor); +X for (i = 3; +X i < NCH(n) && TYPE(ch = CHILD(n, i)) == except_clause; +X i += 3) { +X /* except_clause: 'except' [expr [',' expr]] */ +X if (except_anchor == 0) { +X err_setstr(TypeError, +X "default 'except:' must be last"); +X c->c_errors++; +X break; +X } +X except_anchor = 0; +X com_addoparg(c, SET_LINENO, ch->n_lineno); +X if (NCH(ch) > 1) { +X com_addbyte(c, DUP_TOP); +X com_node(c, CHILD(ch, 1)); +X com_addoparg(c, COMPARE_OP, EXC_MATCH); +X com_addfwref(c, JUMP_IF_FALSE, &except_anchor); +X com_addbyte(c, POP_TOP); +X } +X com_addbyte(c, POP_TOP); +X if (NCH(ch) > 3) +X com_assign(c, CHILD(ch, 3), 1/*assigning*/); +X else +X com_addbyte(c, POP_TOP); +X com_addbyte(c, POP_TOP); +X com_node(c, CHILD(n, i+2)); +X com_addfwref(c, JUMP_FORWARD, &end_anchor); +X if (except_anchor) { +X com_backpatch(c, except_anchor); +X com_addbyte(c, POP_TOP); +X } +X } +X com_addbyte(c, END_FINALLY); +X com_backpatch(c, end_anchor); +X } +X if (finally_anchor) { +X node *ch; +X com_addbyte(c, POP_BLOCK); +X com_addoparg(c, LOAD_CONST, com_addconst(c, None)); +X com_backpatch(c, finally_anchor); +X ch = CHILD(n, NCH(n)-1); +X com_addoparg(c, SET_LINENO, ch->n_lineno); +X com_node(c, ch); +X com_addbyte(c, END_FINALLY); +X } +X} +X +Xstatic void +Xcom_suite(c, n) +X struct compiling *c; +X node *n; +X{ +X REQ(n, suite); +X /* simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT */ +X if (NCH(n) == 1) { +X com_node(c, CHILD(n, 0)); +X } +X else { +X int i; +X for (i = 0; i < NCH(n); i++) { +X node *ch = CHILD(n, i); +X if (TYPE(ch) == stmt) +X com_node(c, ch); +X } +X } +X} +X +Xstatic void +Xcom_funcdef(c, n) +X struct compiling *c; +X node *n; +X{ +X object *v; +X REQ(n, funcdef); /* funcdef: 'def' NAME parameters ':' suite */ +X v = (object *)compile(n, c->c_filename); +X if (v == NULL) +X c->c_errors++; +X else { +X int i = com_addconst(c, v); +X com_addoparg(c, LOAD_CONST, i); +X com_addbyte(c, BUILD_FUNCTION); +X com_addopname(c, STORE_NAME, CHILD(n, 1)); +X DECREF(v); +X } +X} +X +Xstatic void +Xcom_bases(c, n) +X struct compiling *c; +X node *n; +X{ +X int i, nbases; +X REQ(n, baselist); +X /* +X baselist: atom arguments (',' atom arguments)* +X arguments: '(' [testlist] ')' +X */ +X for (i = 0; i < NCH(n); i += 3) +X com_node(c, CHILD(n, i)); +X com_addoparg(c, BUILD_TUPLE, (NCH(n)+1) / 3); +X} +X +Xstatic void +Xcom_classdef(c, n) +X struct compiling *c; +X node *n; +X{ +X object *v; +X REQ(n, classdef); +X /* +X classdef: 'class' NAME parameters ['=' baselist] ':' suite +X baselist: atom arguments (',' atom arguments)* +X arguments: '(' [testlist] ')' +X */ +X if (NCH(n) == 7) +X com_bases(c, CHILD(n, 4)); +X else +X com_addoparg(c, LOAD_CONST, com_addconst(c, None)); +X v = (object *)compile(n, c->c_filename); +X if (v == NULL) +X c->c_errors++; +X else { +X int i = com_addconst(c, v); +X com_addoparg(c, LOAD_CONST, i); +X com_addbyte(c, BUILD_FUNCTION); +X com_addbyte(c, UNARY_CALL); +X com_addbyte(c, BUILD_CLASS); +X com_addopname(c, STORE_NAME, CHILD(n, 1)); +X DECREF(v); +X } +X} +X +Xstatic void +Xcom_node(c, n) +X struct compiling *c; +X node *n; +X{ +X switch (TYPE(n)) { +X +X /* Definition nodes */ +X +X case funcdef: +X com_funcdef(c, n); +X break; +X case classdef: +X com_classdef(c, n); +X break; +X +X /* Trivial parse tree nodes */ +X +X case stmt: +X case flow_stmt: +X com_node(c, CHILD(n, 0)); +X break; +X +X case simple_stmt: +X case compound_stmt: +X com_addoparg(c, SET_LINENO, n->n_lineno); +X com_node(c, CHILD(n, 0)); +X break; +X +X /* Statement nodes */ +X +X case expr_stmt: +X com_expr_stmt(c, n); +X break; +X case print_stmt: +X com_print_stmt(c, n); +X break; +X case del_stmt: /* 'del' exprlist NEWLINE */ +X com_assign(c, CHILD(n, 1), 0/*delete*/); +X break; +X case pass_stmt: +X break; +X case break_stmt: +X if (c->c_loops == 0) { +X err_setstr(TypeError, "'break' outside loop"); +X c->c_errors++; +X } +X com_addbyte(c, BREAK_LOOP); +X break; +X case return_stmt: +X com_return_stmt(c, n); +X break; +X case raise_stmt: +X com_raise_stmt(c, n); +X break; +X case import_stmt: +X com_import_stmt(c, n); +X break; +X case if_stmt: +X com_if_stmt(c, n); +X break; +X case while_stmt: +X com_while_stmt(c, n); +X break; +X case for_stmt: +X com_for_stmt(c, n); +X break; +X case try_stmt: +X com_try_stmt(c, n); +X break; +X case suite: +X com_suite(c, n); +X break; +X +X /* Expression nodes */ +X +X case testlist: +X com_list(c, n); +X break; +X case test: +X com_test(c, n); +X break; +X case and_test: +X com_and_test(c, n); +X break; +X case not_test: +X com_not_test(c, n); +X break; +X case comparison: +X com_comparison(c, n); +X break; +X case exprlist: +X com_list(c, n); +X break; +X case expr: +X com_expr(c, n); +X break; +X case term: +X com_term(c, n); +X break; +X case factor: +X com_factor(c, n); +X break; +X case atom: +X com_atom(c, n); +X break; +X +X default: +X fprintf(stderr, "node type %d\n", TYPE(n)); +X err_setstr(SystemError, "com_node: unexpected node type"); +X c->c_errors++; +X } +X} +X +Xstatic void com_fplist PROTO((struct compiling *, node *)); +X +Xstatic void +Xcom_fpdef(c, n) +X struct compiling *c; +X node *n; +X{ +X REQ(n, fpdef); /* fpdef: NAME | '(' fplist ')' */ +X if (TYPE(CHILD(n, 0)) == LPAR) +X com_fplist(c, CHILD(n, 1)); +X else +X com_addopname(c, STORE_NAME, CHILD(n, 0)); +X} +X +Xstatic void +Xcom_fplist(c, n) +X struct compiling *c; +X node *n; +X{ +X REQ(n, fplist); /* fplist: fpdef (',' fpdef)* */ +X if (NCH(n) == 1) { +X com_fpdef(c, CHILD(n, 0)); +X } +X else { +X int i; +X com_addoparg(c, UNPACK_TUPLE, (NCH(n)+1)/2); +X for (i = 0; i < NCH(n); i += 2) +X com_fpdef(c, CHILD(n, i)); +X } +X} +X +Xstatic void +Xcom_file_input(c, n) +X struct compiling *c; +X node *n; +X{ +X int i; +X REQ(n, file_input); /* (NEWLINE | stmt)* ENDMARKER */ +X for (i = 0; i < NCH(n); i++) { +X node *ch = CHILD(n, i); +X if (TYPE(ch) != ENDMARKER && TYPE(ch) != NEWLINE) +X com_node(c, ch); +X } +X} +X +X/* Top-level compile-node interface */ +X +Xstatic void +Xcompile_funcdef(c, n) +X struct compiling *c; +X node *n; +X{ +X node *ch; +X REQ(n, funcdef); /* funcdef: 'def' NAME parameters ':' suite */ +X ch = CHILD(n, 2); /* parameters: '(' [fplist] ')' */ +X ch = CHILD(ch, 1); /* ')' | fplist */ +X if (TYPE(ch) == RPAR) +X com_addbyte(c, REFUSE_ARGS); +X else { +X com_addbyte(c, REQUIRE_ARGS); +X com_fplist(c, ch); +X } +X c->c_infunction = 1; +X com_node(c, CHILD(n, 4)); +X c->c_infunction = 0; +X com_addoparg(c, LOAD_CONST, com_addconst(c, None)); +X com_addbyte(c, RETURN_VALUE); +X} +X +Xstatic void +Xcompile_node(c, n) +X struct compiling *c; +X node *n; +X{ +X com_addoparg(c, SET_LINENO, n->n_lineno); +X +X switch (TYPE(n)) { +X +X case single_input: /* One interactive command */ +X /* NEWLINE | simple_stmt | compound_stmt NEWLINE */ +X com_addbyte(c, REFUSE_ARGS); +X n = CHILD(n, 0); +X if (TYPE(n) != NEWLINE) +X com_node(c, n); +X com_addoparg(c, LOAD_CONST, com_addconst(c, None)); +X com_addbyte(c, RETURN_VALUE); +X break; +X +X case file_input: /* A whole file, or built-in function exec() */ +X com_addbyte(c, REFUSE_ARGS); +X com_file_input(c, n); +X com_addoparg(c, LOAD_CONST, com_addconst(c, None)); +X com_addbyte(c, RETURN_VALUE); +X break; +X +X case expr_input: /* Built-in function eval() */ +X com_addbyte(c, REFUSE_ARGS); +X com_node(c, CHILD(n, 0)); +X com_addbyte(c, RETURN_VALUE); +X break; +X +X case eval_input: /* Built-in function input() */ +X com_addbyte(c, REFUSE_ARGS); +X com_node(c, CHILD(n, 0)); +X com_addbyte(c, RETURN_VALUE); +X break; +X +X case funcdef: /* A function definition */ +X compile_funcdef(c, n); +X break; +X +X case classdef: /* A class definition */ +X /* 'class' NAME parameters ['=' baselist] ':' suite */ +X com_addbyte(c, REFUSE_ARGS); +X com_node(c, CHILD(n, NCH(n)-1)); +X com_addbyte(c, LOAD_LOCALS); +X com_addbyte(c, RETURN_VALUE); +X break; +X +X default: +X fprintf(stderr, "node type %d\n", TYPE(n)); +X err_setstr(SystemError, "compile_node: unexpected node type"); +X c->c_errors++; +X } +X} +X +Xcodeobject * +Xcompile(n, filename) +X node *n; +X char *filename; +X{ +X struct compiling sc; +X codeobject *co; +X if (!com_init(&sc, filename)) +X return NULL; +X compile_node(&sc, n); +X com_done(&sc); +X if (sc.c_errors == 0) +X co = newcodeobject(sc.c_code, sc.c_consts, sc.c_names, filename); +X else +X co = NULL; +X com_free(&sc); +X return co; +X} +EOF +fi +if test -s 'src/graminit.c' +then echo '*** I will not over-write existing file src/graminit.c' +else +echo 'x - src/graminit.c' +sed 's/^X//' > 'src/graminit.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X#include "pgenheaders.h" +X#include "grammar.h" +Xstatic arc arcs_0_0[3] = { +X {2, 1}, +X {3, 1}, +X {4, 2}, +X}; +Xstatic arc arcs_0_1[1] = { +X {0, 1}, +X}; +Xstatic arc arcs_0_2[1] = { +X {2, 1}, +X}; +Xstatic state states_0[3] = { +X {3, arcs_0_0}, +X {1, arcs_0_1}, +X {1, arcs_0_2}, +X}; +Xstatic arc arcs_1_0[3] = { +X {2, 0}, +X {6, 0}, +X {7, 1}, +X}; +Xstatic arc arcs_1_1[1] = { +X {0, 1}, +X}; +Xstatic state states_1[2] = { +X {3, arcs_1_0}, +X {1, arcs_1_1}, +X}; +Xstatic arc arcs_2_0[1] = { +X {9, 1}, +X}; +Xstatic arc arcs_2_1[1] = { +X {2, 2}, +X}; +Xstatic arc arcs_2_2[1] = { +X {0, 2}, +X}; +Xstatic state states_2[3] = { +X {1, arcs_2_0}, +X {1, arcs_2_1}, +X {1, arcs_2_2}, +X}; +Xstatic arc arcs_3_0[1] = { +X {9, 1}, +X}; +Xstatic arc arcs_3_1[1] = { +X {7, 2}, +X}; +Xstatic arc arcs_3_2[1] = { +X {0, 2}, +X}; +Xstatic state states_3[3] = { +X {1, arcs_3_0}, +X {1, arcs_3_1}, +X {1, arcs_3_2}, +X}; +Xstatic arc arcs_4_0[1] = { +X {12, 1}, +X}; +Xstatic arc arcs_4_1[1] = { +X {13, 2}, +X}; +Xstatic arc arcs_4_2[1] = { +X {14, 3}, +X}; +Xstatic arc arcs_4_3[1] = { +X {15, 4}, +X}; +Xstatic arc arcs_4_4[1] = { +X {16, 5}, +X}; +Xstatic arc arcs_4_5[1] = { +X {0, 5}, +X}; +Xstatic state states_4[6] = { +X {1, arcs_4_0}, +X {1, arcs_4_1}, +X {1, arcs_4_2}, +X {1, arcs_4_3}, +X {1, arcs_4_4}, +X {1, arcs_4_5}, +X}; +Xstatic arc arcs_5_0[1] = { +X {17, 1}, +X}; +Xstatic arc arcs_5_1[2] = { +X {18, 2}, +X {19, 3}, +X}; +Xstatic arc arcs_5_2[1] = { +X {19, 3}, +X}; +Xstatic arc arcs_5_3[1] = { +X {0, 3}, +X}; +Xstatic state states_5[4] = { +X {1, arcs_5_0}, +X {2, arcs_5_1}, +X {1, arcs_5_2}, +X {1, arcs_5_3}, +X}; +Xstatic arc arcs_6_0[1] = { +X {20, 1}, +X}; +Xstatic arc arcs_6_1[2] = { +X {21, 0}, +X {0, 1}, +X}; +Xstatic state states_6[2] = { +X {1, arcs_6_0}, +X {2, arcs_6_1}, +X}; +Xstatic arc arcs_7_0[2] = { +X {13, 1}, +X {17, 2}, +X}; +Xstatic arc arcs_7_1[1] = { +X {0, 1}, +X}; +Xstatic arc arcs_7_2[1] = { +X {18, 3}, +X}; +Xstatic arc arcs_7_3[1] = { +X {19, 1}, +X}; +Xstatic state states_7[4] = { +X {2, arcs_7_0}, +X {1, arcs_7_1}, +X {1, arcs_7_2}, +X {1, arcs_7_3}, +X}; +Xstatic arc arcs_8_0[2] = { +X {3, 1}, +X {4, 1}, +X}; +Xstatic arc arcs_8_1[1] = { +X {0, 1}, +X}; +Xstatic state states_8[2] = { +X {2, arcs_8_0}, +X {1, arcs_8_1}, +X}; +Xstatic arc arcs_9_0[6] = { +X {22, 1}, +X {23, 1}, +X {24, 1}, +X {25, 1}, +X {26, 1}, +X {27, 1}, +X}; +Xstatic arc arcs_9_1[1] = { +X {0, 1}, +X}; +Xstatic state states_9[2] = { +X {6, arcs_9_0}, +X {1, arcs_9_1}, +X}; +Xstatic arc arcs_10_0[1] = { +X {28, 1}, +X}; +Xstatic arc arcs_10_1[2] = { +X {29, 0}, +X {2, 2}, +X}; +Xstatic arc arcs_10_2[1] = { +X {0, 2}, +X}; +Xstatic state states_10[3] = { +X {1, arcs_10_0}, +X {2, arcs_10_1}, +X {1, arcs_10_2}, +X}; +Xstatic arc arcs_11_0[1] = { +X {30, 1}, +X}; +Xstatic arc arcs_11_1[2] = { +X {31, 2}, +X {2, 3}, +X}; +Xstatic arc arcs_11_2[2] = { +X {21, 1}, +X {2, 3}, +X}; +Xstatic arc arcs_11_3[1] = { +X {0, 3}, +X}; +Xstatic state states_11[4] = { +X {1, arcs_11_0}, +X {2, arcs_11_1}, +X {2, arcs_11_2}, +X {1, arcs_11_3}, +X}; +Xstatic arc arcs_12_0[1] = { +X {32, 1}, +X}; +Xstatic arc arcs_12_1[1] = { +X {28, 2}, +X}; +Xstatic arc arcs_12_2[1] = { +X {2, 3}, +X}; +Xstatic arc arcs_12_3[1] = { +X {0, 3}, +X}; +Xstatic state states_12[4] = { +X {1, arcs_12_0}, +X {1, arcs_12_1}, +X {1, arcs_12_2}, +X {1, arcs_12_3}, +X}; +Xstatic arc arcs_13_0[1] = { +X {33, 1}, +X}; +Xstatic arc arcs_13_1[1] = { +X {2, 2}, +X}; +Xstatic arc arcs_13_2[1] = { +X {0, 2}, +X}; +Xstatic state states_13[3] = { +X {1, arcs_13_0}, +X {1, arcs_13_1}, +X {1, arcs_13_2}, +X}; +Xstatic arc arcs_14_0[3] = { +X {34, 1}, +X {35, 1}, +X {36, 1}, +X}; +Xstatic arc arcs_14_1[1] = { +X {0, 1}, +X}; +Xstatic state states_14[2] = { +X {3, arcs_14_0}, +X {1, arcs_14_1}, +X}; +Xstatic arc arcs_15_0[1] = { +X {37, 1}, +X}; +Xstatic arc arcs_15_1[1] = { +X {2, 2}, +X}; +Xstatic arc arcs_15_2[1] = { +X {0, 2}, +X}; +Xstatic state states_15[3] = { +X {1, arcs_15_0}, +X {1, arcs_15_1}, +X {1, arcs_15_2}, +X}; +Xstatic arc arcs_16_0[1] = { +X {38, 1}, +X}; +Xstatic arc arcs_16_1[2] = { +X {9, 2}, +X {2, 3}, +X}; +Xstatic arc arcs_16_2[1] = { +X {2, 3}, +X}; +Xstatic arc arcs_16_3[1] = { +X {0, 3}, +X}; +Xstatic state states_16[4] = { +X {1, arcs_16_0}, +X {2, arcs_16_1}, +X {1, arcs_16_2}, +X {1, arcs_16_3}, +X}; +Xstatic arc arcs_17_0[1] = { +X {39, 1}, +X}; +Xstatic arc arcs_17_1[1] = { +X {40, 2}, +X}; +Xstatic arc arcs_17_2[2] = { +X {21, 3}, +X {2, 4}, +X}; +Xstatic arc arcs_17_3[1] = { +X {40, 5}, +X}; +Xstatic arc arcs_17_4[1] = { +X {0, 4}, +X}; +Xstatic arc arcs_17_5[1] = { +X {2, 4}, +X}; +Xstatic state states_17[6] = { +X {1, arcs_17_0}, +X {1, arcs_17_1}, +X {2, arcs_17_2}, +X {1, arcs_17_3}, +X {1, arcs_17_4}, +X {1, arcs_17_5}, +X}; +Xstatic arc arcs_18_0[2] = { +X {41, 1}, +X {42, 2}, +X}; +Xstatic arc arcs_18_1[1] = { +X {13, 3}, +X}; +Xstatic arc arcs_18_2[1] = { +X {13, 4}, +X}; +Xstatic arc arcs_18_3[2] = { +X {21, 1}, +X {2, 5}, +X}; +Xstatic arc arcs_18_4[1] = { +X {41, 6}, +X}; +Xstatic arc arcs_18_5[1] = { +X {0, 5}, +X}; +Xstatic arc arcs_18_6[2] = { +X {43, 7}, +X {13, 8}, +X}; +Xstatic arc arcs_18_7[1] = { +X {2, 5}, +X}; +Xstatic arc arcs_18_8[2] = { +X {21, 9}, +X {2, 5}, +X}; +Xstatic arc arcs_18_9[1] = { +X {13, 8}, +X}; +Xstatic state states_18[10] = { +X {2, arcs_18_0}, +X {1, arcs_18_1}, +X {1, arcs_18_2}, +X {2, arcs_18_3}, +X {1, arcs_18_4}, +X {1, arcs_18_5}, +X {2, arcs_18_6}, +X {1, arcs_18_7}, +X {2, arcs_18_8}, +X {1, arcs_18_9}, +X}; +Xstatic arc arcs_19_0[6] = { +X {44, 1}, +X {45, 1}, +X {46, 1}, +X {47, 1}, +X {11, 1}, +X {48, 1}, +X}; +Xstatic arc arcs_19_1[1] = { +X {0, 1}, +X}; +Xstatic state states_19[2] = { +X {6, arcs_19_0}, +X {1, arcs_19_1}, +X}; +Xstatic arc arcs_20_0[1] = { +X {49, 1}, +X}; +Xstatic arc arcs_20_1[1] = { +X {31, 2}, +X}; +Xstatic arc arcs_20_2[1] = { +X {15, 3}, +X}; +Xstatic arc arcs_20_3[1] = { +X {16, 4}, +X}; +Xstatic arc arcs_20_4[3] = { +X {50, 1}, +X {51, 5}, +X {0, 4}, +X}; +Xstatic arc arcs_20_5[1] = { +X {15, 6}, +X}; +Xstatic arc arcs_20_6[1] = { +X {16, 7}, +X}; +Xstatic arc arcs_20_7[1] = { +X {0, 7}, +X}; +Xstatic state states_20[8] = { +X {1, arcs_20_0}, +X {1, arcs_20_1}, +X {1, arcs_20_2}, +X {1, arcs_20_3}, +X {3, arcs_20_4}, +X {1, arcs_20_5}, +X {1, arcs_20_6}, +X {1, arcs_20_7}, +X}; +Xstatic arc arcs_21_0[1] = { +X {52, 1}, +X}; +Xstatic arc arcs_21_1[1] = { +X {31, 2}, +X}; +Xstatic arc arcs_21_2[1] = { +X {15, 3}, +X}; +Xstatic arc arcs_21_3[1] = { +X {16, 4}, +X}; +Xstatic arc arcs_21_4[2] = { +X {51, 5}, +X {0, 4}, +X}; +Xstatic arc arcs_21_5[1] = { +X {15, 6}, +X}; +Xstatic arc arcs_21_6[1] = { +X {16, 7}, +X}; +Xstatic arc arcs_21_7[1] = { +X {0, 7}, +X}; +Xstatic state states_21[8] = { +X {1, arcs_21_0}, +X {1, arcs_21_1}, +X {1, arcs_21_2}, +X {1, arcs_21_3}, +X {2, arcs_21_4}, +X {1, arcs_21_5}, +X {1, arcs_21_6}, +X {1, arcs_21_7}, +X}; +Xstatic arc arcs_22_0[1] = { +X {53, 1}, +X}; +Xstatic arc arcs_22_1[1] = { +X {28, 2}, +X}; +Xstatic arc arcs_22_2[1] = { +X {54, 3}, +X}; +Xstatic arc arcs_22_3[1] = { +X {28, 4}, +X}; +Xstatic arc arcs_22_4[1] = { +X {15, 5}, +X}; +Xstatic arc arcs_22_5[1] = { +X {16, 6}, +X}; +Xstatic arc arcs_22_6[2] = { +X {51, 7}, +X {0, 6}, +X}; +Xstatic arc arcs_22_7[1] = { +X {15, 8}, +X}; +Xstatic arc arcs_22_8[1] = { +X {16, 9}, +X}; +Xstatic arc arcs_22_9[1] = { +X {0, 9}, +X}; +Xstatic state states_22[10] = { +X {1, arcs_22_0}, +X {1, arcs_22_1}, +X {1, arcs_22_2}, +X {1, arcs_22_3}, +X {1, arcs_22_4}, +X {1, arcs_22_5}, +X {2, arcs_22_6}, +X {1, arcs_22_7}, +X {1, arcs_22_8}, +X {1, arcs_22_9}, +X}; +Xstatic arc arcs_23_0[1] = { +X {55, 1}, +X}; +Xstatic arc arcs_23_1[1] = { +X {15, 2}, +X}; +Xstatic arc arcs_23_2[1] = { +X {16, 3}, +X}; +Xstatic arc arcs_23_3[3] = { +X {56, 1}, +X {57, 4}, +X {0, 3}, +X}; +Xstatic arc arcs_23_4[1] = { +X {15, 5}, +X}; +Xstatic arc arcs_23_5[1] = { +X {16, 6}, +X}; +Xstatic arc arcs_23_6[1] = { +X {0, 6}, +X}; +Xstatic state states_23[7] = { +X {1, arcs_23_0}, +X {1, arcs_23_1}, +X {1, arcs_23_2}, +X {3, arcs_23_3}, +X {1, arcs_23_4}, +X {1, arcs_23_5}, +X {1, arcs_23_6}, +X}; +Xstatic arc arcs_24_0[1] = { +X {58, 1}, +X}; +Xstatic arc arcs_24_1[2] = { +X {40, 2}, +X {0, 1}, +X}; +Xstatic arc arcs_24_2[2] = { +X {21, 3}, +X {0, 2}, +X}; +Xstatic arc arcs_24_3[1] = { +X {40, 4}, +X}; +Xstatic arc arcs_24_4[1] = { +X {0, 4}, +X}; +Xstatic state states_24[5] = { +X {1, arcs_24_0}, +X {2, arcs_24_1}, +X {2, arcs_24_2}, +X {1, arcs_24_3}, +X {1, arcs_24_4}, +X}; +Xstatic arc arcs_25_0[2] = { +X {3, 1}, +X {2, 2}, +X}; +Xstatic arc arcs_25_1[1] = { +X {0, 1}, +X}; +Xstatic arc arcs_25_2[1] = { +X {59, 3}, +X}; +Xstatic arc arcs_25_3[2] = { +X {2, 3}, +X {6, 4}, +X}; +Xstatic arc arcs_25_4[3] = { +X {6, 4}, +X {2, 4}, +X {60, 1}, +X}; +Xstatic state states_25[5] = { +X {2, arcs_25_0}, +X {1, arcs_25_1}, +X {1, arcs_25_2}, +X {2, arcs_25_3}, +X {3, arcs_25_4}, +X}; +Xstatic arc arcs_26_0[1] = { +X {61, 1}, +X}; +Xstatic arc arcs_26_1[2] = { +X {62, 0}, +X {0, 1}, +X}; +Xstatic state states_26[2] = { +X {1, arcs_26_0}, +X {2, arcs_26_1}, +X}; +Xstatic arc arcs_27_0[1] = { +X {63, 1}, +X}; +Xstatic arc arcs_27_1[2] = { +X {64, 0}, +X {0, 1}, +X}; +Xstatic state states_27[2] = { +X {1, arcs_27_0}, +X {2, arcs_27_1}, +X}; +Xstatic arc arcs_28_0[2] = { +X {65, 1}, +X {66, 2}, +X}; +Xstatic arc arcs_28_1[1] = { +X {63, 2}, +X}; +Xstatic arc arcs_28_2[1] = { +X {0, 2}, +X}; +Xstatic state states_28[3] = { +X {2, arcs_28_0}, +X {1, arcs_28_1}, +X {1, arcs_28_2}, +X}; +Xstatic arc arcs_29_0[1] = { +X {40, 1}, +X}; +Xstatic arc arcs_29_1[2] = { +X {67, 0}, +X {0, 1}, +X}; +Xstatic state states_29[2] = { +X {1, arcs_29_0}, +X {2, arcs_29_1}, +X}; +Xstatic arc arcs_30_0[6] = { +X {68, 1}, +X {69, 2}, +X {29, 3}, +X {54, 3}, +X {65, 4}, +X {70, 5}, +X}; +Xstatic arc arcs_30_1[3] = { +X {29, 3}, +X {69, 3}, +X {0, 1}, +X}; +Xstatic arc arcs_30_2[2] = { +X {29, 3}, +X {0, 2}, +X}; +Xstatic arc arcs_30_3[1] = { +X {0, 3}, +X}; +Xstatic arc arcs_30_4[1] = { +X {54, 3}, +X}; +Xstatic arc arcs_30_5[2] = { +X {65, 3}, +X {0, 5}, +X}; +Xstatic state states_30[6] = { +X {6, arcs_30_0}, +X {3, arcs_30_1}, +X {2, arcs_30_2}, +X {1, arcs_30_3}, +X {1, arcs_30_4}, +X {2, arcs_30_5}, +X}; +Xstatic arc arcs_31_0[1] = { +X {71, 1}, +X}; +Xstatic arc arcs_31_1[3] = { +X {72, 0}, +X {73, 0}, +X {0, 1}, +X}; +Xstatic state states_31[2] = { +X {1, arcs_31_0}, +X {3, arcs_31_1}, +X}; +Xstatic arc arcs_32_0[1] = { +X {74, 1}, +X}; +Xstatic arc arcs_32_1[4] = { +X {43, 0}, +X {75, 0}, +X {76, 0}, +X {0, 1}, +X}; +Xstatic state states_32[2] = { +X {1, arcs_32_0}, +X {4, arcs_32_1}, +X}; +Xstatic arc arcs_33_0[3] = { +X {72, 1}, +X {73, 1}, +X {77, 2}, +X}; +Xstatic arc arcs_33_1[1] = { +X {74, 3}, +X}; +Xstatic arc arcs_33_2[2] = { +X {78, 2}, +X {0, 2}, +X}; +Xstatic arc arcs_33_3[1] = { +X {0, 3}, +X}; +Xstatic state states_33[4] = { +X {3, arcs_33_0}, +X {1, arcs_33_1}, +X {2, arcs_33_2}, +X {1, arcs_33_3}, +X}; +Xstatic arc arcs_34_0[7] = { +X {17, 1}, +X {79, 2}, +X {81, 3}, +X {83, 4}, +X {13, 5}, +X {84, 5}, +X {85, 5}, +X}; +Xstatic arc arcs_34_1[2] = { +X {9, 6}, +X {19, 5}, +X}; +Xstatic arc arcs_34_2[2] = { +X {9, 7}, +X {80, 5}, +X}; +Xstatic arc arcs_34_3[1] = { +X {82, 5}, +X}; +Xstatic arc arcs_34_4[1] = { +X {9, 8}, +X}; +Xstatic arc arcs_34_5[1] = { +X {0, 5}, +X}; +Xstatic arc arcs_34_6[1] = { +X {19, 5}, +X}; +Xstatic arc arcs_34_7[1] = { +X {80, 5}, +X}; +Xstatic arc arcs_34_8[1] = { +X {83, 5}, +X}; +Xstatic state states_34[9] = { +X {7, arcs_34_0}, +X {2, arcs_34_1}, +X {2, arcs_34_2}, +X {1, arcs_34_3}, +X {1, arcs_34_4}, +X {1, arcs_34_5}, +X {1, arcs_34_6}, +X {1, arcs_34_7}, +X {1, arcs_34_8}, +X}; +Xstatic arc arcs_35_0[3] = { +X {17, 1}, +X {79, 2}, +X {87, 3}, +X}; +Xstatic arc arcs_35_1[2] = { +X {9, 4}, +X {19, 5}, +X}; +Xstatic arc arcs_35_2[1] = { +X {86, 6}, +X}; +Xstatic arc arcs_35_3[1] = { +X {13, 5}, +X}; +Xstatic arc arcs_35_4[1] = { +X {19, 5}, +X}; +Xstatic arc arcs_35_5[1] = { +X {0, 5}, +X}; +Xstatic arc arcs_35_6[1] = { +X {80, 5}, +X}; +Xstatic state states_35[7] = { +X {3, arcs_35_0}, +X {2, arcs_35_1}, +X {1, arcs_35_2}, +X {1, arcs_35_3}, +X {1, arcs_35_4}, +X {1, arcs_35_5}, +X {1, arcs_35_6}, +X}; +Xstatic arc arcs_36_0[2] = { +X {40, 1}, +X {15, 2}, +X}; +Xstatic arc arcs_36_1[2] = { +X {15, 2}, +X {0, 1}, +X}; +Xstatic arc arcs_36_2[2] = { +X {40, 3}, +X {0, 2}, +X}; +Xstatic arc arcs_36_3[1] = { +X {0, 3}, +X}; +Xstatic state states_36[4] = { +X {2, arcs_36_0}, +X {2, arcs_36_1}, +X {2, arcs_36_2}, +X {1, arcs_36_3}, +X}; +Xstatic arc arcs_37_0[1] = { +X {40, 1}, +X}; +Xstatic arc arcs_37_1[2] = { +X {21, 2}, +X {0, 1}, +X}; +Xstatic arc arcs_37_2[2] = { +X {40, 1}, +X {0, 2}, +X}; +Xstatic state states_37[3] = { +X {1, arcs_37_0}, +X {2, arcs_37_1}, +X {2, arcs_37_2}, +X}; +Xstatic arc arcs_38_0[1] = { +X {31, 1}, +X}; +Xstatic arc arcs_38_1[2] = { +X {21, 2}, +X {0, 1}, +X}; +Xstatic arc arcs_38_2[2] = { +X {31, 1}, +X {0, 2}, +X}; +Xstatic state states_38[3] = { +X {1, arcs_38_0}, +X {2, arcs_38_1}, +X {2, arcs_38_2}, +X}; +Xstatic arc arcs_39_0[1] = { +X {88, 1}, +X}; +Xstatic arc arcs_39_1[1] = { +X {13, 2}, +X}; +Xstatic arc arcs_39_2[1] = { +X {14, 3}, +X}; +Xstatic arc arcs_39_3[2] = { +X {29, 4}, +X {15, 5}, +X}; +Xstatic arc arcs_39_4[1] = { +X {89, 6}, +X}; +Xstatic arc arcs_39_5[1] = { +X {16, 7}, +X}; +Xstatic arc arcs_39_6[1] = { +X {15, 5}, +X}; +Xstatic arc arcs_39_7[1] = { +X {0, 7}, +X}; +Xstatic state states_39[8] = { +X {1, arcs_39_0}, +X {1, arcs_39_1}, +X {1, arcs_39_2}, +X {2, arcs_39_3}, +X {1, arcs_39_4}, +X {1, arcs_39_5}, +X {1, arcs_39_6}, +X {1, arcs_39_7}, +X}; +Xstatic arc arcs_40_0[1] = { +X {77, 1}, +X}; +Xstatic arc arcs_40_1[1] = { +X {90, 2}, +X}; +Xstatic arc arcs_40_2[2] = { +X {21, 0}, +X {0, 2}, +X}; +Xstatic state states_40[3] = { +X {1, arcs_40_0}, +X {1, arcs_40_1}, +X {2, arcs_40_2}, +X}; +Xstatic arc arcs_41_0[1] = { +X {17, 1}, +X}; +Xstatic arc arcs_41_1[2] = { +X {9, 2}, +X {19, 3}, +X}; +Xstatic arc arcs_41_2[1] = { +X {19, 3}, +X}; +Xstatic arc arcs_41_3[1] = { +X {0, 3}, +X}; +Xstatic state states_41[4] = { +X {1, arcs_41_0}, +X {2, arcs_41_1}, +X {1, arcs_41_2}, +X {1, arcs_41_3}, +X}; +Xstatic dfa dfas[42] = { +X {256, "single_input", 0, 3, states_0, +X "\004\060\002\100\343\006\262\000\000\203\072\001"}, +X {257, "file_input", 0, 2, states_1, +X "\204\060\002\100\343\006\262\000\000\203\072\001"}, +X {258, "expr_input", 0, 3, states_2, +X "\000\040\002\000\000\000\000\000\002\203\072\000"}, +X {259, "eval_input", 0, 3, states_3, +X "\000\040\002\000\000\000\000\000\002\203\072\000"}, +X {260, "funcdef", 0, 6, states_4, +X "\000\020\000\000\000\000\000\000\000\000\000\000"}, +X {261, "parameters", 0, 4, states_5, +X "\000\000\002\000\000\000\000\000\000\000\000\000"}, +X {262, "fplist", 0, 2, states_6, +X "\000\040\002\000\000\000\000\000\000\000\000\000"}, +X {263, "fpdef", 0, 4, states_7, +X "\000\040\002\000\000\000\000\000\000\000\000\000"}, +X {264, "stmt", 0, 2, states_8, +X "\000\060\002\100\343\006\262\000\000\203\072\001"}, +X {265, "simple_stmt", 0, 2, states_9, +X "\000\040\002\100\343\006\000\000\000\203\072\000"}, +X {266, "expr_stmt", 0, 3, states_10, +X "\000\040\002\000\000\000\000\000\000\203\072\000"}, +X {267, "print_stmt", 0, 4, states_11, +X "\000\000\000\100\000\000\000\000\000\000\000\000"}, +X {268, "del_stmt", 0, 4, states_12, +X "\000\000\000\000\001\000\000\000\000\000\000\000"}, +X {269, "pass_stmt", 0, 3, states_13, +X "\000\000\000\000\002\000\000\000\000\000\000\000"}, +X {270, "flow_stmt", 0, 2, states_14, +X "\000\000\000\000\340\000\000\000\000\000\000\000"}, +X {271, "break_stmt", 0, 3, states_15, +X "\000\000\000\000\040\000\000\000\000\000\000\000"}, +X {272, "return_stmt", 0, 4, states_16, +X "\000\000\000\000\100\000\000\000\000\000\000\000"}, +X {273, "raise_stmt", 0, 6, states_17, +X "\000\000\000\000\200\000\000\000\000\000\000\000"}, +X {274, "import_stmt", 0, 10, states_18, +X "\000\000\000\000\000\006\000\000\000\000\000\000"}, +X {275, "compound_stmt", 0, 2, states_19, +X "\000\020\000\000\000\000\262\000\000\000\000\001"}, +X {276, "if_stmt", 0, 8, states_20, +X "\000\000\000\000\000\000\002\000\000\000\000\000"}, +X {277, "while_stmt", 0, 8, states_21, +X "\000\000\000\000\000\000\020\000\000\000\000\000"}, +X {278, "for_stmt", 0, 10, states_22, +X "\000\000\000\000\000\000\040\000\000\000\000\000"}, +X {279, "try_stmt", 0, 7, states_23, +X "\000\000\000\000\000\000\200\000\000\000\000\000"}, +X {280, "except_clause", 0, 5, states_24, +X "\000\000\000\000\000\000\000\004\000\000\000\000"}, +X {281, "suite", 0, 5, states_25, +X "\004\040\002\100\343\006\000\000\000\203\072\000"}, +X {282, "test", 0, 2, states_26, +X "\000\040\002\000\000\000\000\000\002\203\072\000"}, +X {283, "and_test", 0, 2, states_27, +X "\000\040\002\000\000\000\000\000\002\203\072\000"}, +X {284, "not_test", 0, 3, states_28, +X "\000\040\002\000\000\000\000\000\002\203\072\000"}, +X {285, "comparison", 0, 2, states_29, +X "\000\040\002\000\000\000\000\000\000\203\072\000"}, +X {286, "comp_op", 0, 6, states_30, +X "\000\000\000\040\000\000\100\000\162\000\000\000"}, +X {287, "expr", 0, 2, states_31, +X "\000\040\002\000\000\000\000\000\000\203\072\000"}, +X {288, "term", 0, 2, states_32, +X "\000\040\002\000\000\000\000\000\000\203\072\000"}, +X {289, "factor", 0, 4, states_33, +X "\000\040\002\000\000\000\000\000\000\203\072\000"}, +X {290, "atom", 0, 9, states_34, +X "\000\040\002\000\000\000\000\000\000\200\072\000"}, +X {291, "trailer", 0, 7, states_35, +X "\000\000\002\000\000\000\000\000\000\200\200\000"}, +X {292, "subscript", 0, 4, states_36, +X "\000\240\002\000\000\000\000\000\000\203\072\000"}, +X {293, "exprlist", 0, 3, states_37, +X "\000\040\002\000\000\000\000\000\000\203\072\000"}, +X {294, "testlist", 0, 3, states_38, +X "\000\040\002\000\000\000\000\000\002\203\072\000"}, +X {295, "classdef", 0, 8, states_39, +X "\000\000\000\000\000\000\000\000\000\000\000\001"}, +X {296, "baselist", 0, 3, states_40, +X "\000\040\002\000\000\000\000\000\000\200\072\000"}, +X {297, "arguments", 0, 4, states_41, +X "\000\000\002\000\000\000\000\000\000\000\000\000"}, +X}; +Xstatic label labels[91] = { +X {0, "EMPTY"}, +X {256, 0}, +X {4, 0}, +X {265, 0}, +X {275, 0}, +X {257, 0}, +X {264, 0}, +X {0, 0}, +X {258, 0}, +X {294, 0}, +X {259, 0}, +X {260, 0}, +X {1, "def"}, +X {1, 0}, +X {261, 0}, +X {11, 0}, +X {281, 0}, +X {7, 0}, +X {262, 0}, +X {8, 0}, +X {263, 0}, +X {12, 0}, +X {266, 0}, +X {267, 0}, +X {269, 0}, +X {268, 0}, +X {270, 0}, +X {274, 0}, +X {293, 0}, +X {22, 0}, +X {1, "print"}, +X {282, 0}, +X {1, "del"}, +X {1, "pass"}, +X {271, 0}, +X {272, 0}, +X {273, 0}, +X {1, "break"}, +X {1, "return"}, +X {1, "raise"}, +X {287, 0}, +X {1, "import"}, +X {1, "from"}, +X {16, 0}, +X {276, 0}, +X {277, 0}, +X {278, 0}, +X {279, 0}, +X {295, 0}, +X {1, "if"}, +X {1, "elif"}, +X {1, "else"}, +X {1, "while"}, +X {1, "for"}, +X {1, "in"}, +X {1, "try"}, +X {280, 0}, +X {1, "finally"}, +X {1, "except"}, +X {5, 0}, +X {6, 0}, +X {283, 0}, +X {1, "or"}, +X {284, 0}, +X {1, "and"}, +X {1, "not"}, +X {285, 0}, +X {286, 0}, +X {20, 0}, +X {21, 0}, +X {1, "is"}, +X {288, 0}, +X {14, 0}, +X {15, 0}, +X {289, 0}, +X {17, 0}, +X {24, 0}, +X {290, 0}, +X {291, 0}, +X {9, 0}, +X {10, 0}, +X {26, 0}, +X {27, 0}, +X {25, 0}, +X {2, 0}, +X {3, 0}, +X {292, 0}, +X {23, 0}, +X {1, "class"}, +X {296, 0}, +X {297, 0}, +X}; +Xgrammar gram = { +X 42, +X dfas, +X {91, labels}, +X 256 +X}; +EOF +fi +if test -s 'src/objimpl.h' +then echo '*** I will not over-write existing file src/objimpl.h' +else +echo 'x - src/objimpl.h' +sed 's/^X//' > 'src/objimpl.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* +X123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 +X +XAdditional macros for modules that implement new object types. +XYou must first include "object.h". +X +XNEWOBJ(type, typeobj) allocates memory for a new object of the given +Xtype; here 'type' must be the C structure type used to represent the +Xobject and 'typeobj' the address of the corresponding type object. +XReference count and type pointer are filled in; the rest of the bytes of +Xthe object are *undefined*! The resulting expression type is 'type *'. +XThe size of the object is actually determined by the tp_basicsize field +Xof the type object. +X +XNEWVAROBJ(type, typeobj, n) is similar but allocates a variable-size +Xobject with n extra items. The size is computer as tp_basicsize plus +Xn * tp_itemsize. This fills in the ob_size field as well. +X*/ +X +Xextern object *newobject PROTO((typeobject *)); +Xextern varobject *newvarobject PROTO((typeobject *, unsigned int)); +X +X#define NEWOBJ(type, typeobj) ((type *) newobject(typeobj)) +X#define NEWVAROBJ(type, typeobj, n) ((type *) newvarobject(typeobj, n)) +X +Xextern int StopPrint; /* Set when printing is interrupted */ +EOF +fi +echo 'Part 03 out of 21 of pack.out complete.' +exit 0 diff --git a/shar/python-0.9.1-04-21.shar b/shar/python-0.9.1-04-21.shar new file mode 100644 index 0000000..5f1cbee --- /dev/null +++ b/shar/python-0.9.1-04-21.shar @@ -0,0 +1,2755 @@ +: This is a shell archive. +: Extract with 'sh this_file'. +: +: Extract part 01 first since it makes all directories +echo 'Start of pack.out, part 04 out of 21:' +if test -s 'demo/sgi/gl_panel/flying/freeze.s' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/flying/freeze.s' +else +echo 'x - demo/sgi/gl_panel/flying/freeze.s' +sed 's/^X//' > 'demo/sgi/gl_panel/flying/freeze.s' << 'EOF' +X;;; This file was automatically generated by the panel editor. +X;;; If you read it into gnu emacs, it will automagically format itself. +X +X(panel (prop help creator:user-panel-help) +X(prop user-panel #t) +X(label "frames per second") +X(al (pnl_toggle_button (name "freeze") +X(prop help creator:user-act-help) +X(label "freeze") +X(x 0.25) +X(y 4.3) +X(w 1.45) +X(h 0.6) +X(labeltype 16) +X(downfunc move-then-resize) +X) +X(pnl_scale_chart (name "mystrip") +X(prop help creator:user-act-help) +X(x 0.25) +X(y 0.25) +X(downfunc move-then-resize) +X) +X) +X) +X;;; Local Variables: +X;;; mode: scheme +X;;; eval: (save-excursion (goto-char (point-min)) (kill-line 3)) +X;;; eval: (save-excursion (goto-char (point-min)) (replace-regexp "[ \n]*)" ")")) +X;;; eval: (indent-region (point-min) (point-max) nil) +X;;; eval: (progn (kill-line -3) (delete-backward-char 1) (save-buffer)) +X;;; End: +EOF +fi +if test -s 'src/cstubs' +then echo '*** I will not over-write existing file src/cstubs' +else +echo 'x - src/cstubs' +sed 's/^X//' > 'src/cstubs' << 'EOF' +X/* +XInput used to generate the Python module "glmodule.c". +XThe stub generator is a Python script called "cgen". +X +XEach definition must be contained on one line: +X +X<returntype> <name> <type> <arg> <type> <arg> +X +X<returntype> can be: void, short, long (XXX maybe others?) +X +X<type> can be: char, string, short, float, long, or double +X string indicates a null terminated string; +X if <type> is char and <arg> begins with a *, the * is stripped +X and <type> is changed into string +X +X<arg> has the form <mode> or <mode>[<subscript>] +X where <mode> can be +X s: arg is sent +X r: arg is received (arg is a pointer) +X and <subscript> can be (N and I are numbers): +X N +X argI +X retval +X N*argI +X N*retval +X*/ +X +X#include <gl.h> +X#include <device.h> +X +X#include "allobjects.h" +X#include "import.h" +X#include "modsupport.h" +X#include "cgensupport.h" +X +X/* +XSome stubs are too complicated for the stub generator. +XWe can include manually written versions of them here. +XA line starting with '%' gives the name of the function so the stub +Xgenerator can include it in the table of functions. +X*/ +X +X/* +Xvarray -- an array of v.. calls. +XThe argument is an array (maybe list or tuple) of points. +XEach point must be a tuple or list of coordinates (x, y, z). +XThe points may be 2- or 3-dimensional but must all have the +Xsame dimension. Float and int values may be mixed however. +XThe points are always converted to 3D double precision points +Xby assuming z=0.0 if necessary (as indicated in the man page), +Xand for each point v3d() is called. +X*/ +X +X% varray +X +Xstatic object * +Xgl_varray(self, args) +X object *self; +X object *args; +X{ +X object *v, *w; +X int i, n, width; +X double vec[3]; +X object * (*getitem) FPROTO((object *, int)); +X +X if (!getiobjectarg(args, 1, 0, &v)) +X return NULL; +X +X if (is_listobject(v)) { +X n = getlistsize(v); +X getitem = getlistitem; +X } +X else if (is_tupleobject(v)) { +X n = gettuplesize(v); +X getitem = gettupleitem; +X } +X else { +X err_badarg(); +X return NULL; +X } +X +X if (n == 0) { +X INCREF(None); +X return None; +X } +X if (n > 0) +X w = (*getitem)(v, 0); +X +X width = 0; +X if (w == NULL) { +X } +X else if (is_listobject(w)) { +X width = getlistsize(w); +X } +X else if (is_tupleobject(w)) { +X width = gettuplesize(w); +X } +X +X switch (width) { +X case 2: +X vec[2] = 0.0; +X /* Fall through */ +X case 3: +X break; +X default: +X err_badarg(); +X return NULL; +X } +X +X for (i = 0; i < n; i++) { +X w = (*getitem)(v, i); +X if (!getidoublearray(w, 1, 0, width, vec)) +X return NULL; +X v3d(vec); +X } +X +X INCREF(None); +X return None; +X} +X +X/* +Xvnarray, nvarray -- an array of n3f and v3f calls. +XThe argument is an array (list or tuple) of pairs of points and normals. +XEach pair is a tuple (NOT a list) of a point and a normal for that point. +XEach point or normal must be a tuple (NOT a list) of coordinates (x, y, z). +XThree coordinates must be given. Float and int values may be mixed. +XFor each pair, n3f() is called for the normal, and then v3f() is called +Xfor the vector. +X +Xvnarray and nvarray differ only in the order of the vector and normal in +Xthe pair: vnarray expects (v, n) while nvarray expects (n, v). +X*/ +X +Xstatic object *gen_nvarray(); /* Forward */ +X +X% nvarray +X +Xstatic object * +Xgl_nvarray(self, args) +X object *self; +X object *args; +X{ +X return gen_nvarray(args, 0); +X} +X +X% vnarray +X +Xstatic object * +Xgl_vnarray(self, args) +X object *self; +X object *args; +X{ +X return gen_nvarray(args, 1); +X} +X +X/* Generic, internal version of {nv,nv}array: inorm indicates the +X argument order, 0: normal first, 1: vector first. */ +X +Xstatic object * +Xgen_nvarray(args, inorm) +X object *args; +X int inorm; +X{ +X object *v, *w, *wnorm, *wvec; +X int i, n; +X float norm[3], vec[3]; +X object * (*getitem) FPROTO((object *, int)); +X +X if (!getiobjectarg(args, 1, 0, &v)) +X return NULL; +X +X if (is_listobject(v)) { +X n = getlistsize(v); +X getitem = getlistitem; +X } +X else if (is_tupleobject(v)) { +X n = gettuplesize(v); +X getitem = gettupleitem; +X } +X else { +X err_badarg(); +X return NULL; +X } +X +X for (i = 0; i < n; i++) { +X w = (*getitem)(v, i); +X if (!is_tupleobject(w) || gettuplesize(w) != 2) { +X err_badarg(); +X return NULL; +X } +X wnorm = gettupleitem(w, inorm); +X wvec = gettupleitem(w, 1 - inorm); +X if (!getifloatarray(wnorm, 1, 0, 3, norm) || +X !getifloatarray(wvec, 1, 0, 3, vec)) +X return NULL; +X n3f(norm); +X v3f(vec); +X } +X +X INCREF(None); +X return None; +X} +X +X/* nurbssurface(s_knots[], t_knots[], ctl[][], s_order, t_order, type). +X The dimensions of ctl[] are computed as follows: +X [len(s_knots) - s_order], [len(t_knots) - t_order] +X*/ +X +X% nurbssurface +X +Xstatic object * +Xgl_nurbssurface(self, args) +X object *self; +X object *args; +X{ +X long arg1 ; +X double * arg2 ; +X long arg3 ; +X double * arg4 ; +X double *arg5 ; +X long arg6 ; +X long arg7 ; +X long arg8 ; +X long ncoords; +X long s_byte_stride, t_byte_stride; +X long s_nctl, t_nctl; +X long s, t; +X object *v, *w, *pt; +X double *pnext; +X if (!getilongarraysize(args, 6, 0, &arg1)) +X return NULL; +X if ((arg2 = NEW(double, arg1 )) == NULL) { +X return err_nomem(); +X } +X if (!getidoublearray(args, 6, 0, arg1 , arg2)) +X return NULL; +X if (!getilongarraysize(args, 6, 1, &arg3)) +X return NULL; +X if ((arg4 = NEW(double, arg3 )) == NULL) { +X return err_nomem(); +X } +X if (!getidoublearray(args, 6, 1, arg3 , arg4)) +X return NULL; +X if (!getilongarg(args, 6, 3, &arg6)) +X return NULL; +X if (!getilongarg(args, 6, 4, &arg7)) +X return NULL; +X if (!getilongarg(args, 6, 5, &arg8)) +X return NULL; +X if (arg8 == N_XYZ) +X ncoords = 3; +X else if (arg8 == N_XYZW) +X ncoords = 4; +X else { +X err_badarg(); +X return NULL; +X } +X s_nctl = arg1 - arg6; +X t_nctl = arg3 - arg7; +X if (!getiobjectarg(args, 6, 2, &v)) +X return NULL; +X if (!is_listobject(v) || getlistsize(v) != s_nctl) { +X err_badarg(); +X return NULL; +X } +X if ((arg5 = NEW(double, s_nctl*t_nctl*ncoords )) == NULL) { +X return err_nomem(); +X } +X pnext = arg5; +X for (s = 0; s < s_nctl; s++) { +X w = getlistitem(v, s); +X if (w == NULL || !is_listobject(w) || +X getlistsize(w) != t_nctl) { +X err_badarg(); +X return NULL; +X } +X for (t = 0; t < t_nctl; t++) { +X pt = getlistitem(w, t); +X if (!getidoublearray(pt, 1, 0, ncoords, pnext)) +X return NULL; +X pnext += ncoords; +X } +X } +X s_byte_stride = sizeof(double) * ncoords; +X t_byte_stride = s_byte_stride * s_nctl; +X nurbssurface( arg1 , arg2 , arg3 , arg4 , +X s_byte_stride , t_byte_stride , arg5 , arg6 , arg7 , arg8 ); +X DEL(arg2); +X DEL(arg4); +X DEL(arg5); +X INCREF(None); +X return None; +X} +X +X/* nurbscurve(knots, ctlpoints, order, type). +X The length of ctlpoints is len(knots)-order. */ +X +X%nurbscurve +X +Xstatic object * +Xgl_nurbscurve(self, args) +X object *self; +X object *args; +X{ +X long arg1 ; +X double * arg2 ; +X long arg3 ; +X double * arg4 ; +X long arg5 ; +X long arg6 ; +X int ncoords, npoints; +X int i; +X object *v; +X double *pnext; +X if (!getilongarraysize(args, 4, 0, &arg1)) +X return NULL; +X if ((arg2 = NEW(double, arg1 )) == NULL) { +X return err_nomem(); +X } +X if (!getidoublearray(args, 4, 0, arg1 , arg2)) +X return NULL; +X if (!getilongarg(args, 4, 2, &arg5)) +X return NULL; +X if (!getilongarg(args, 4, 3, &arg6)) +X return NULL; +X if (arg6 == N_ST) +X ncoords = 2; +X else if (arg6 == N_STW) +X ncoords = 3; +X else { +X err_badarg(); +X return NULL; +X } +X npoints = arg1 - arg5; +X if (!getiobjectarg(args, 4, 1, &v)) +X return NULL; +X if (!is_listobject(v) || getlistsize(v) != npoints) { +X err_badarg(); +X return NULL; +X } +X if ((arg4 = NEW(double, npoints*ncoords )) == NULL) { +X return err_nomem(); +X } +X pnext = arg4; +X for (i = 0; i < npoints; i++) { +X if (!getidoublearray(getlistitem(v, i), 1, 0, ncoords, pnext)) +X return NULL; +X pnext += ncoords; +X } +X arg3 = (sizeof(double)) * ncoords; +X nurbscurve( arg1 , arg2 , arg3 , arg4 , arg5 , arg6 ); +X DEL(arg2); +X DEL(arg4); +X INCREF(None); +X return None; +X} +X +X/* pwlcurve(points, type). +X Points is a list of points. Type must be N_ST. */ +X +X%pwlcurve +X +Xstatic object * +Xgl_pwlcurve(self, args) +X object *self; +X object *args; +X{ +X object *v; +X long type; +X double *data, *pnext; +X long npoints, ncoords; +X int i; +X if (!getiobjectarg(args, 2, 0, &v)) +X return NULL; +X if (!getilongarg(args, 2, 1, &type)) +X return NULL; +X if (!is_listobject(v)) { +X err_badarg(); +X return NULL; +X } +X npoints = getlistsize(v); +X if (type == N_ST) +X ncoords = 2; +X else { +X err_badarg(); +X return NULL; +X } +X if ((data = NEW(double, npoints*ncoords)) == NULL) { +X return err_nomem(); +X } +X pnext = data; +X for (i = 0; i < npoints; i++) { +X if (!getidoublearray(getlistitem(v, i), 1, 0, ncoords, pnext)) +X return NULL; +X pnext += ncoords; +X } +X pwlcurve(npoints, data, sizeof(double)*ncoords, type); +X DEL(data); +X INCREF(None); +X return None; +X} +X +X +X/* Picking and Selecting */ +X +Xstatic short *pickbuffer = NULL; +Xstatic long pickbuffersize; +X +Xstatic object * +Xpick_select(args, func) +X object *args; +X void (*func)(); +X{ +X if (!getilongarg(args, 1, 0, &pickbuffersize)) +X return NULL; +X if (pickbuffer != NULL) { +X err_setstr(RuntimeError, +X "pick/gselect: already picking/selecting"); +X return NULL; +X } +X if ((pickbuffer = NEW(short, pickbuffersize)) == NULL) { +X return err_nomem(); +X } +X (*func)(pickbuffer, pickbuffersize); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xendpick_select(args, func) +X object *args; +X long (*func)(); +X{ +X object *v, *w; +X int i, nhits, n; +X if (!getnoarg(args)) +X return NULL; +X if (pickbuffer == NULL) { +X err_setstr(RuntimeError, +X "endpick/endselect: not in pick/select mode"); +X return NULL; +X } +X nhits = (*func)(pickbuffer); +X if (nhits < 0) { +X nhits = -nhits; /* How to report buffer overflow otherwise? */ +X } +X /* Scan the buffer to see how many integers */ +X n = 0; +X for (; nhits > 0; nhits--) { +X n += 1 + pickbuffer[n]; +X } +X v = newlistobject(n); +X if (v == NULL) +X return NULL; +X /* XXX Could do it nicer and interpret the data structure here, +X returning a list of lists. But this can be done in Python... */ +X for (i = 0; i < n; i++) { +X w = newintobject((long)pickbuffer[i]); +X if (w == NULL) { +X DECREF(v); +X return NULL; +X } +X setlistitem(v, i, w); +X } +X DEL(pickbuffer); +X pickbuffer = NULL; +X return v; +X} +X +Xextern void pick(), gselect(); +Xextern long endpick(), endselect(); +X +X%pick +Xstatic object *gl_pick(self, args) object *self, *args; { +X return pick_select(args, pick); +X} +X +X%endpick +Xstatic object *gl_endpick(self, args) object *self, *args; { +X return endpick_select(args, endpick); +X} +X +X%gselect +Xstatic object *gl_gselect(self, args) object *self, *args; { +X return pick_select(args, gselect); +X} +X +X%endselect +Xstatic object *gl_endselect(self, args) object *self, *args; { +X return endpick_select(args, endselect); +X} +X +X +X/* XXX The generator botches this one. Here's a quick hack to fix it. */ +X +X% getmatrix float r[16] +X +Xstatic object * +Xgl_getmatrix(self, args) +X object *self; +X object *args; +X{ +X float arg1 [ 16 ] ; +X object *v, *w; +X int i; +X getmatrix( arg1 ); +X v = newlistobject(16); +X if (v == NULL) { +X return err_nomem(); +X } +X for (i = 0; i < 16; i++) { +X w = mknewfloatobject(arg1[i]); +X if (w == NULL) { +X DECREF(v); +X return NULL; +X } +X setlistitem(v, i, w); +X } +X return v; +X} +X +X/* End of manually written stubs */ +X +X%% +X +Xlong getshade +Xvoid devport short s long s +Xvoid rdr2i long s long s +Xvoid rectfs short s short s short s short s +Xvoid rects short s short s short s short s +Xvoid rmv2i long s long s +Xvoid noport +Xvoid popviewport +Xvoid clear +Xvoid clearhitcode +Xvoid closeobj +Xvoid cursoff +Xvoid curson +Xvoid doublebuffer +Xvoid finish +Xvoid gconfig +Xvoid ginit +Xvoid greset +Xvoid multimap +Xvoid onemap +Xvoid popattributes +Xvoid popmatrix +Xvoid pushattributes +Xvoid pushmatrix +Xvoid pushviewport +Xvoid qreset +Xvoid RGBmode +Xvoid singlebuffer +Xvoid swapbuffers +Xvoid gsync +Xvoid tpon +Xvoid tpoff +Xvoid clkon +Xvoid clkoff +Xvoid ringbell +X#void callfunc +Xvoid gbegin +Xvoid textinit +Xvoid initnames +Xvoid pclos +Xvoid popname +Xvoid spclos +Xvoid zclear +Xvoid screenspace +Xvoid reshapeviewport +Xvoid winpush +Xvoid winpop +Xvoid foreground +Xvoid endfullscrn +Xvoid endpupmode +Xvoid fullscrn +Xvoid pupmode +Xvoid winconstraints +Xvoid pagecolor short s +Xvoid textcolor short s +Xvoid color short s +Xvoid curveit short s +Xvoid font short s +Xvoid linewidth short s +Xvoid setlinestyle short s +Xvoid setmap short s +Xvoid swapinterval short s +Xvoid writemask short s +Xvoid textwritemask short s +Xvoid qdevice short s +Xvoid unqdevice short s +Xvoid curvebasis short s +Xvoid curveprecision short s +Xvoid loadname short s +Xvoid passthrough short s +Xvoid pushname short s +Xvoid setmonitor short s +Xvoid setshade short s +Xvoid setpattern short s +Xvoid pagewritemask short s +X# +Xvoid callobj long s +Xvoid delobj long s +Xvoid editobj long s +Xvoid makeobj long s +Xvoid maketag long s +Xvoid chunksize long s +Xvoid compactify long s +Xvoid deltag long s +Xvoid lsrepeat long s +Xvoid objinsert long s +Xvoid objreplace long s +Xvoid winclose long s +Xvoid blanktime long s +Xvoid freepup long s +X# This is not in the library!? +X###void pupcolor long s +X# +Xvoid backbuffer long s +Xvoid frontbuffer long s +Xvoid lsbackup long s +Xvoid resetls long s +Xvoid lampon long s +Xvoid lampoff long s +Xvoid setbell long s +Xvoid blankscreen long s +Xvoid depthcue long s +Xvoid zbuffer long s +Xvoid backface long s +X# +Xvoid cmov2i long s long s +Xvoid draw2i long s long s +Xvoid move2i long s long s +Xvoid pnt2i long s long s +Xvoid patchbasis long s long s +Xvoid patchprecision long s long s +Xvoid pdr2i long s long s +Xvoid pmv2i long s long s +Xvoid rpdr2i long s long s +Xvoid rpmv2i long s long s +Xvoid xfpt2i long s long s +Xvoid objdelete long s long s +Xvoid patchcurves long s long s +Xvoid minsize long s long s +Xvoid maxsize long s long s +Xvoid keepaspect long s long s +Xvoid prefsize long s long s +Xvoid stepunit long s long s +Xvoid fudge long s long s +Xvoid winmove long s long s +X# +Xvoid attachcursor short s short s +Xvoid deflinestyle short s short s +Xvoid noise short s short s +Xvoid picksize short s short s +Xvoid qenter short s short s +Xvoid setdepth short s short s +Xvoid cmov2s short s short s +Xvoid draw2s short s short s +Xvoid move2s short s short s +Xvoid pdr2s short s short s +Xvoid pmv2s short s short s +Xvoid pnt2s short s short s +Xvoid rdr2s short s short s +Xvoid rmv2s short s short s +Xvoid rpdr2s short s short s +Xvoid rpmv2s short s short s +Xvoid xfpt2s short s short s +X# +Xvoid cmov2 float s float s +Xvoid draw2 float s float s +Xvoid move2 float s float s +Xvoid pnt2 float s float s +Xvoid pdr2 float s float s +Xvoid pmv2 float s float s +Xvoid rdr2 float s float s +Xvoid rmv2 float s float s +Xvoid rpdr2 float s float s +Xvoid rpmv2 float s float s +Xvoid xfpt2 float s float s +X# +Xvoid loadmatrix float s[16] +Xvoid multmatrix float s[16] +Xvoid crv float s[16] +Xvoid rcrv float s[16] +X# +X# Methods that have strings. +X# +Xvoid addtopup long s char *s long s +Xvoid charstr char *s +Xvoid getport char *s +Xlong strwidth char *s +Xlong winopen char *s +Xvoid wintitle char *s +X# +X# Methods that have 1 long (# of elements) and an array +X# +Xvoid polf long s float s[3*arg1] +Xvoid polf2 long s float s[2*arg1] +Xvoid poly long s float s[3*arg1] +Xvoid poly2 long s float s[2*arg1] +Xvoid crvn long s float s[3*arg1] +Xvoid rcrvn long s float s[4*arg1] +X# +Xvoid polf2i long s long s[2*arg1] +Xvoid polfi long s long s[3*arg1] +Xvoid poly2i long s long s[2*arg1] +Xvoid polyi long s long s[3*arg1] +X# +Xvoid polf2s long s short s[2*arg1] +Xvoid polfs long s short s[3*arg1] +Xvoid polys long s short s[3*arg1] +Xvoid poly2s long s short s[2*arg1] +X# +Xvoid defcursor short s short s[16] +Xvoid writepixels short s short s[arg1] +Xvoid defbasis long s float s[16] +Xvoid gewrite short s short s[arg1] +X# +Xvoid rotate short s char s +X# This is not in the library!? +X###void setbutton short s char s +Xvoid rot float s char s +X# +Xvoid circfi long s long s long s +Xvoid circi long s long s long s +Xvoid cmovi long s long s long s +Xvoid drawi long s long s long s +Xvoid movei long s long s long s +Xvoid pnti long s long s long s +Xvoid newtag long s long s long s +Xvoid pdri long s long s long s +Xvoid pmvi long s long s long s +Xvoid rdri long s long s long s +Xvoid rmvi long s long s long s +Xvoid rpdri long s long s long s +Xvoid rpmvi long s long s long s +Xvoid xfpti long s long s long s +X# +Xvoid circ float s float s float s +Xvoid circf float s float s float s +Xvoid cmov float s float s float s +Xvoid draw float s float s float s +Xvoid move float s float s float s +Xvoid pnt float s float s float s +Xvoid scale float s float s float s +Xvoid translate float s float s float s +Xvoid pdr float s float s float s +Xvoid pmv float s float s float s +Xvoid rdr float s float s float s +Xvoid rmv float s float s float s +Xvoid rpdr float s float s float s +Xvoid rpmv float s float s float s +Xvoid xfpt float s float s float s +X# +Xvoid RGBcolor short s short s short s +Xvoid RGBwritemask short s short s short s +Xvoid setcursor short s short s short s +Xvoid tie short s short s short s +Xvoid circfs short s short s short s +Xvoid circs short s short s short s +Xvoid cmovs short s short s short s +Xvoid draws short s short s short s +Xvoid moves short s short s short s +Xvoid pdrs short s short s short s +Xvoid pmvs short s short s short s +Xvoid pnts short s short s short s +Xvoid rdrs short s short s short s +Xvoid rmvs short s short s short s +Xvoid rpdrs short s short s short s +Xvoid rpmvs short s short s short s +Xvoid xfpts short s short s short s +Xvoid curorigin short s short s short s +Xvoid cyclemap short s short s short s +X# +Xvoid patch float s[16] float s[16] float s[16] +Xvoid splf long s float s[3*arg1] short s[arg1] +Xvoid splf2 long s float s[2*arg1] short s[arg1] +Xvoid splfi long s long s[3*arg1] short s[arg1] +Xvoid splf2i long s long s[2*arg1] short s[arg1] +Xvoid splfs long s short s[3*arg1] short s[arg1] +Xvoid splf2s long s short s[2*arg1] short s[arg1] +Xvoid defpattern short s short s short s[arg2*arg2/16] +X# +Xvoid rpatch float s[16] float s[16] float s[16] float s[16] +X# +X# routines that send 4 floats +X# +Xvoid ortho2 float s float s float s float s +Xvoid rect float s float s float s float s +Xvoid rectf float s float s float s float s +Xvoid xfpt4 float s float s float s float s +X# +Xvoid textport short s short s short s short s +Xvoid mapcolor short s short s short s short s +Xvoid scrmask short s short s short s short s +Xvoid setvaluator short s short s short s short s +Xvoid viewport short s short s short s short s +Xvoid shaderange short s short s short s short s +Xvoid xfpt4s short s short s short s short s +Xvoid rectfi long s long s long s long s +Xvoid recti long s long s long s long s +Xvoid xfpt4i long s long s long s long s +Xvoid prefposition long s long s long s long s +X# +Xvoid arc float s float s float s short s short s +Xvoid arcf float s float s float s short s short s +Xvoid arcfi long s long s long s short s short s +Xvoid arci long s long s long s short s short s +X# +Xvoid bbox2 short s short s float s float s float s float s +Xvoid bbox2i short s short s long s long s long s long s +Xvoid bbox2s short s short s short s short s short s short s +Xvoid blink short s short s short s short s short s +Xvoid ortho float s float s float s float s float s float s +Xvoid window float s float s float s float s float s float s +Xvoid lookat float s float s float s float s float s float s short s +X# +Xvoid perspective short s float s float s float s +Xvoid polarview float s short s short s short s +X# XXX getichararray not supported +X#void writeRGB short s char s[arg1] char s[arg1] char s[arg1] +X# +Xvoid arcfs short s short s short s short s short s +Xvoid arcs short s short s short s short s short s +Xvoid rectcopy short s short s short s short s short s short s +Xvoid RGBcursor short s short s short s short s short s short s short s +X# +Xlong getbutton short s +Xlong getcmmode +Xlong getlsbackup +Xlong getresetls +Xlong getdcm +Xlong getzbuffer +Xlong ismex +Xlong isobj long s +Xlong isqueued short s +Xlong istag long s +X# +Xlong genobj +Xlong gentag +Xlong getbuffer +Xlong getcolor +Xlong getdisplaymode +Xlong getfont +Xlong getheight +Xlong gethitcode +Xlong getlstyle +Xlong getlwidth +Xlong getmap +Xlong getplanes +Xlong getwritemask +Xlong qtest +Xlong getlsrepeat +Xlong getmonitor +Xlong getopenobj +Xlong getpattern +Xlong winget +Xlong winattach +Xlong getothermonitor +Xlong newpup +X# +Xlong getvaluator short s +Xvoid winset long s +Xlong dopup long s +Xvoid getdepth short r short r +Xvoid getcpos short r short r +Xvoid getsize long r long r +Xvoid getorigin long r long r +Xvoid getviewport short r short r short r short r +Xvoid gettp short r short r short r short r +Xvoid getgpos float r float r float r float r +Xvoid winposition long s long s long s long s +Xvoid gRGBcolor short r short r short r +Xvoid gRGBmask short r short r short r +Xvoid getscrmask short r short r short r short r +Xvoid gRGBcursor short r short r short r short r short r short r short r short r long * +Xvoid getmcolor short s short r short r short r +Xvoid mapw long s short s short s float r float r float r float r float r float r +Xvoid mapw2 long s short s short s float r float r +Xvoid defrasterfont short s short s short s Fontchar s[arg3] short s short s[4*arg5] +Xlong qread short r +Xvoid getcursor short r short r short r long r +X# +X# For these we receive arrays of stuff +X# +Xvoid getdev long s short s[arg1] short r[arg1] +X#XXX not generated correctly yet +X#void getmatrix float r[16] +Xlong readpixels short s short r[retval] +Xlong readRGB short s char r[retval] char r[retval] char r[retval] +Xlong blkqread short s short r[arg1] +X# +X# New 4D routines +X# +Xvoid cmode +Xvoid concave long s +Xvoid curstype long s +Xvoid drawmode long s +Xvoid gammaramp short s[256] short s[256] short s[256] +Xlong getbackface +Xlong getdescender +Xlong getdrawmode +Xlong getmmode +Xlong getsm +Xlong getvideo long s +Xvoid imakebackground +Xvoid lmbind short s short s +Xvoid lmdef long s long s long s float s[arg3] +Xvoid mmode long s +Xvoid normal float s[3] +Xvoid overlay long s +Xvoid RGBrange short s short s short s short s short s short s short s short s +Xvoid setvideo long s long s +Xvoid shademodel long s +Xvoid underlay long s +X# +X# New Personal Iris/GT Routines +X# +Xvoid bgnclosedline +Xvoid bgnline +Xvoid bgnpoint +Xvoid bgnpolygon +Xvoid bgnsurface +Xvoid bgntmesh +Xvoid bgntrim +Xvoid endclosedline +Xvoid endline +Xvoid endpoint +Xvoid endpolygon +Xvoid endsurface +Xvoid endtmesh +Xvoid endtrim +Xvoid blendfunction long s long s +Xvoid c3f float s[3] +Xvoid c3i long s[3] +Xvoid c3s short s[3] +Xvoid c4f float s[4] +Xvoid c4i long s[4] +Xvoid c4s short s[4] +Xvoid colorf float s +Xvoid cpack long s +Xvoid czclear long s long s +Xvoid dglclose long s +Xlong dglopen char *s long s +Xlong getgdesc long s +Xvoid getnurbsproperty long s float r +Xvoid glcompat long s long s +Xvoid iconsize long s long s +Xvoid icontitle char *s +Xvoid lRGBrange short s short s short s short s short s short s long s long s +Xvoid linesmooth long s +Xvoid lmcolor long s +Xvoid logicop long s +Xlong lrectread short s short s short s short s long r[retval] +Xvoid lrectwrite short s short s short s short s long s[(arg2-arg1+1)*(arg4-arg3+1)] +Xlong rectread short s short s short s short s short r[retval] +Xvoid rectwrite short s short s short s short s short s[(arg2-arg1+1)*(arg4-arg3+1)] +Xvoid lsetdepth long s long s +Xvoid lshaderange short s short s long s long s +Xvoid n3f float s[3] +Xvoid noborder +Xvoid pntsmooth long s +Xvoid readsource long s +Xvoid rectzoom float s float s +Xvoid sbox float s float s float s float s +Xvoid sboxi long s long s long s long s +Xvoid sboxs short s short s short s short s +Xvoid sboxf float s float s float s float s +Xvoid sboxfi long s long s long s long s +Xvoid sboxfs short s short s short s short s +Xvoid setnurbsproperty long s float s +Xvoid setpup long s long s long s +Xvoid smoothline long s +Xvoid subpixel long s +Xvoid swaptmesh +Xlong swinopen long s +Xvoid v2f float s[2] +Xvoid v2i long s[2] +Xvoid v2s short s[2] +Xvoid v3f float s[3] +Xvoid v3i long s[3] +Xvoid v3s short s[3] +Xvoid v4f float s[4] +Xvoid v4i long s[4] +Xvoid v4s short s[4] +Xvoid videocmd long s +Xlong windepth long s +Xvoid wmpack long s +Xvoid zdraw long s +Xvoid zfunction long s +Xvoid zsource long s +Xvoid zwritemask long s +X# +X# uses doubles +X# +Xvoid v2d double s[2] +Xvoid v3d double s[3] +Xvoid v4d double s[4] +EOF +fi +if test -s 'src/stdwinmodule.c' +then echo '*** I will not over-write existing file src/stdwinmodule.c' +else +echo 'x - src/stdwinmodule.c' +sed 's/^X//' > 'src/stdwinmodule.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Stdwin module */ +X +X/* Stdwin itself is a module, not a separate object type. +X Object types defined here: +X wp: a window +X dp: a drawing structure (only one can exist at a time) +X mp: a menu +X tp: a textedit block +X*/ +X +X/* Rules for translating C stdwin function calls into Python stwin: +X - All names drop their initial letter 'w' +X - Functions with a window as first parameter are methods of window objects +X - There is no equivalent for wclose(); just delete the window object +X (all references to it!) (XXX maybe this is a bad idea) +X - w.begindrawing() returns a drawing object +X - There is no equivalent for wenddrawing(win); just delete the drawing +X object (all references to it!) (XXX maybe this is a bad idea) +X - Functions that may only be used inside wbegindrawing / wendddrawing +X are methods of the drawing object; this includes the text measurement +X functions (which however have doubles as module functions). +X - Methods of the drawing object drop an initial 'draw' from their name +X if they have it, e.g., wdrawline() --> d.line() +X - The obvious type conversions: int --> intobject; string --> stringobject +X - A text parameter followed by a length parameter is only a text (string) +X parameter in Python +X - A point or other pair of horizontal and vertical coordinates is always +X a pair of integers in Python +X - Two points forming a rectangle or endpoints of a line segment are a +X pair of points in Python +X - The arguments to d.elarc() are three points. +X - The functions wgetclip() and wsetclip() are translated into +X stdwin.getcutbuffer() and stdwin.setcutbuffer(); 'clip' is really +X a bad word for what these functions do (clipping has a different +X meaning in the drawing world), while cutbuffer is standard X jargon. +X XXX This must change again in the light of changes to stdwin! +X - For textedit, similar rules hold, but they are less strict. +X XXX more? +X*/ +X +X#include "allobjects.h" +X +X#include "modsupport.h" +X +X#include "stdwin.h" +X +X/* Window and menu object types declared here because of forward references */ +X +Xtypedef struct { +X OB_HEAD +X object *w_title; +X WINDOW *w_win; +X object *w_attr; /* Attributes dictionary */ +X} windowobject; +X +Xextern typeobject Windowtype; /* Really static, forward */ +X +X#define is_windowobject(wp) ((wp)->ob_type == &Windowtype) +X +Xtypedef struct { +X OB_HEAD +X MENU *m_menu; +X int m_id; +X object *m_attr; /* Attributes dictionary */ +X} menuobject; +X +Xextern typeobject Menutype; /* Really static, forward */ +X +X#define is_menuobject(mp) ((mp)->ob_type == &Menutype) +X +X +X/* Strongly stdwin-specific argument handlers */ +X +Xstatic int +Xgetmousedetail(v, ep) +X object *v; +X EVENT *ep; +X{ +X if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 4) +X return err_badarg(); +X return getintintarg(gettupleitem(v, 0), +X &ep->u.where.h, &ep->u.where.v) && +X getintarg(gettupleitem(v, 1), &ep->u.where.clicks) && +X getintarg(gettupleitem(v, 2), &ep->u.where.button) && +X getintarg(gettupleitem(v, 3), &ep->u.where.mask); +X} +X +Xstatic int +Xgetmenudetail(v, ep) +X object *v; +X EVENT *ep; +X{ +X object *mp; +X if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) +X return err_badarg(); +X mp = gettupleitem(v, 0); +X if (mp == NULL || !is_menuobject(mp)) +X return err_badarg(); +X ep->u.m.id = ((menuobject *)mp) -> m_id; +X return getintarg(gettupleitem(v, 1), &ep->u.m.item); +X} +X +Xstatic int +Xgeteventarg(v, ep) +X object *v; +X EVENT *ep; +X{ +X object *wp, *detail; +X int a[4]; +X if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 3) +X return err_badarg(); +X if (!getintarg(gettupleitem(v, 0), &ep->type)) +X return 0; +X wp = gettupleitem(v, 1); +X if (wp == None) +X ep->window = NULL; +X else if (wp == NULL || !is_windowobject(wp)) +X return err_badarg(); +X else +X ep->window = ((windowobject *)wp) -> w_win; +X detail = gettupleitem(v, 2); +X switch (ep->type) { +X case WE_CHAR: +X if (!is_stringobject(detail) || getstringsize(detail) != 1) +X return err_badarg(); +X ep->u.character = getstringvalue(detail)[0]; +X return 1; +X case WE_COMMAND: +X return getintarg(detail, &ep->u.command); +X case WE_DRAW: +X if (!getrectarg(detail, a)) +X return 0; +X ep->u.area.left = a[0]; +X ep->u.area.top = a[1]; +X ep->u.area.right = a[2]; +X ep->u.area.bottom = a[3]; +X return 1; +X case WE_MOUSE_DOWN: +X case WE_MOUSE_UP: +X case WE_MOUSE_MOVE: +X return getmousedetail(detail, ep); +X case WE_MENU: +X return getmenudetail(detail, ep); +X default: +X return 1; +X } +X} +X +X +X/* Return construction tools */ +X +Xstatic object * +Xmakepoint(a, b) +X int a, b; +X{ +X object *v; +X object *w; +X if ((v = newtupleobject(2)) == NULL) +X return NULL; +X if ((w = newintobject((long)a)) == NULL || +X settupleitem(v, 0, w) != 0 || +X (w = newintobject((long)b)) == NULL || +X settupleitem(v, 1, w) != 0) { +X DECREF(v); +X return NULL; +X } +X return v; +X} +X +Xstatic object * +Xmakerect(a, b, c, d) +X int a, b, c, d; +X{ +X object *v; +X object *w; +X if ((v = newtupleobject(2)) == NULL) +X return NULL; +X if ((w = makepoint(a, b)) == NULL || +X settupleitem(v, 0, w) != 0 || +X (w = makepoint(c, d)) == NULL || +X settupleitem(v, 1, w) != 0) { +X DECREF(v); +X return NULL; +X } +X return v; +X} +X +Xstatic object * +Xmakemouse(hor, ver, clicks, button, mask) +X int hor, ver, clicks, button, mask; +X{ +X object *v; +X object *w; +X if ((v = newtupleobject(4)) == NULL) +X return NULL; +X if ((w = makepoint(hor, ver)) == NULL || +X settupleitem(v, 0, w) != 0 || +X (w = newintobject((long)clicks)) == NULL || +X settupleitem(v, 1, w) != 0 || +X (w = newintobject((long)button)) == NULL || +X settupleitem(v, 2, w) != 0 || +X (w = newintobject((long)mask)) == NULL || +X settupleitem(v, 3, w) != 0) { +X DECREF(v); +X return NULL; +X } +X return v; +X} +X +Xstatic object * +Xmakemenu(mp, item) +X object *mp; +X int item; +X{ +X object *v; +X object *w; +X if ((v = newtupleobject(2)) == NULL) +X return NULL; +X INCREF(mp); +X if (settupleitem(v, 0, mp) != 0 || +X (w = newintobject((long)item)) == NULL || +X settupleitem(v, 1, w) != 0) { +X DECREF(v); +X return NULL; +X } +X return v; +X} +X +X +X/* Drawing objects */ +X +Xtypedef struct { +X OB_HEAD +X windowobject *d_ref; +X} drawingobject; +X +Xstatic drawingobject *Drawing; /* Set to current drawing object, or NULL */ +X +X/* Drawing methods */ +X +Xstatic void +Xdrawing_dealloc(dp) +X drawingobject *dp; +X{ +X wenddrawing(dp->d_ref->w_win); +X Drawing = NULL; +X DECREF(dp->d_ref); +X free((char *)dp); +X} +X +Xstatic object * +Xdrawing_generic(dp, args, func) +X drawingobject *dp; +X object *args; +X void (*func) FPROTO((int, int, int, int)); +X{ +X int a[4]; +X if (!getrectarg(args, a)) +X return NULL; +X (*func)(a[0], a[1], a[2], a[3]); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xdrawing_line(dp, args) +X drawingobject *dp; +X object *args; +X{ +X drawing_generic(dp, args, wdrawline); +X} +X +Xstatic object * +Xdrawing_xorline(dp, args) +X drawingobject *dp; +X object *args; +X{ +X drawing_generic(dp, args, wxorline); +X} +X +Xstatic object * +Xdrawing_circle(dp, args) +X drawingobject *dp; +X object *args; +X{ +X int a[3]; +X if (!getpointintarg(args, a)) +X return NULL; +X wdrawcircle(a[0], a[1], a[2]); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xdrawing_elarc(dp, args) +X drawingobject *dp; +X object *args; +X{ +X int a[6]; +X if (!get3pointarg(args, a)) +X return NULL; +X wdrawelarc(a[0], a[1], a[2], a[3], a[4], a[5]); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xdrawing_box(dp, args) +X drawingobject *dp; +X object *args; +X{ +X drawing_generic(dp, args, wdrawbox); +X} +X +Xstatic object * +Xdrawing_erase(dp, args) +X drawingobject *dp; +X object *args; +X{ +X drawing_generic(dp, args, werase); +X} +X +Xstatic object * +Xdrawing_paint(dp, args) +X drawingobject *dp; +X object *args; +X{ +X drawing_generic(dp, args, wpaint); +X} +X +Xstatic object * +Xdrawing_invert(dp, args) +X drawingobject *dp; +X object *args; +X{ +X drawing_generic(dp, args, winvert); +X} +X +Xstatic object * +Xdrawing_cliprect(dp, args) +X drawingobject *dp; +X object *args; +X{ +X drawing_generic(dp, args, wcliprect); +X} +X +Xstatic object * +Xdrawing_noclip(dp, args) +X drawingobject *dp; +X object *args; +X{ +X if (!getnoarg(args)) +X return NULL; +X wnoclip(); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xdrawing_shade(dp, args) +X drawingobject *dp; +X object *args; +X{ +X int a[5]; +X if (!getrectintarg(args, a)) +X return NULL; +X wshade(a[0], a[1], a[2], a[3], a[4]); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xdrawing_text(dp, args) +X drawingobject *dp; +X object *args; +X{ +X int a[2]; +X object *s; +X if (!getpointstrarg(args, a, &s)) +X return NULL; +X wdrawtext(a[0], a[1], getstringvalue(s), (int)getstringsize(s)); +X INCREF(None); +X return None; +X} +X +X/* The following four are also used as stdwin functions */ +X +Xstatic object * +Xdrawing_lineheight(dp, args) +X drawingobject *dp; +X object *args; +X{ +X if (!getnoarg(args)) +X return NULL; +X return newintobject((long)wlineheight()); +X} +X +Xstatic object * +Xdrawing_baseline(dp, args) +X drawingobject *dp; +X object *args; +X{ +X if (!getnoarg(args)) +X return NULL; +X return newintobject((long)wbaseline()); +X} +X +Xstatic object * +Xdrawing_textwidth(dp, args) +X drawingobject *dp; +X object *args; +X{ +X object *s; +X if (!getstrarg(args, &s)) +X return NULL; +X return newintobject( +X (long)wtextwidth(getstringvalue(s), (int)getstringsize(s))); +X} +X +Xstatic object * +Xdrawing_textbreak(dp, args) +X drawingobject *dp; +X object *args; +X{ +X object *s; +X int a; +X if (!getstrintarg(args, &s, &a)) +X return NULL; +X return newintobject( +X (long)wtextbreak(getstringvalue(s), (int)getstringsize(s), a)); +X} +X +Xstatic struct methodlist drawing_methods[] = { +X {"box", drawing_box}, +X {"circle", drawing_circle}, +X {"cliprect", drawing_cliprect}, +X {"elarc", drawing_elarc}, +X {"erase", drawing_erase}, +X {"invert", drawing_invert}, +X {"line", drawing_line}, +X {"noclip", drawing_noclip}, +X {"paint", drawing_paint}, +X {"shade", drawing_shade}, +X {"text", drawing_text}, +X {"xorline", drawing_xorline}, +X +X /* Text measuring methods: */ +X {"baseline", drawing_baseline}, +X {"lineheight", drawing_lineheight}, +X {"textbreak", drawing_textbreak}, +X {"textwidth", drawing_textwidth}, +X {NULL, NULL} /* sentinel */ +X}; +X +Xstatic object * +Xdrawing_getattr(wp, name) +X drawingobject *wp; +X char *name; +X{ +X return findmethod(drawing_methods, (object *)wp, name); +X} +X +Xstatic typeobject Drawingtype = { +X OB_HEAD_INIT(&Typetype) +X 0, /*ob_size*/ +X "drawing", /*tp_name*/ +X sizeof(drawingobject), /*tp_size*/ +X 0, /*tp_itemsize*/ +X /* methods */ +X drawing_dealloc, /*tp_dealloc*/ +X 0, /*tp_print*/ +X drawing_getattr, /*tp_getattr*/ +X 0, /*tp_setattr*/ +X 0, /*tp_compare*/ +X 0, /*tp_repr*/ +X}; +X +X +X/* Text(edit) objects */ +X +Xtypedef struct { +X OB_HEAD +X TEXTEDIT *t_text; +X windowobject *t_ref; +X object *t_attr; /* Attributes dictionary */ +X} textobject; +X +Xextern typeobject Texttype; /* Really static, forward */ +X +Xstatic textobject * +Xnewtextobject(wp, left, top, right, bottom) +X windowobject *wp; +X int left, top, right, bottom; +X{ +X textobject *tp; +X tp = NEWOBJ(textobject, &Texttype); +X if (tp == NULL) +X return NULL; +X tp->t_attr = NULL; +X INCREF(wp); +X tp->t_ref = wp; +X tp->t_text = tecreate(wp->w_win, left, top, right, bottom); +X if (tp->t_text == NULL) { +X DECREF(tp); +X return (textobject *) err_nomem(); +X } +X return tp; +X} +X +X/* Text(edit) methods */ +X +Xstatic void +Xtext_dealloc(tp) +X textobject *tp; +X{ +X if (tp->t_text != NULL) +X tefree(tp->t_text); +X if (tp->t_attr != NULL) +X DECREF(tp->t_attr); +X DECREF(tp->t_ref); +X DEL(tp); +X} +X +Xstatic object * +Xtext_arrow(self, args) +X textobject *self; +X object *args; +X{ +X int code; +X if (!getintarg(args, &code)) +X return NULL; +X tearrow(self->t_text, code); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xtext_draw(self, args) +X textobject *self; +X object *args; +X{ +X register TEXTEDIT *tp = self->t_text; +X int a[4]; +X int left, top, right, bottom; +X if (!getrectarg(args, a)) +X return NULL; +X if (Drawing != NULL) { +X err_setstr(RuntimeError, "not drawing"); +X return NULL; +X } +X /* Clip to text area and ignore if area is empty */ +X left = tegetleft(tp); +X top = tegettop(tp); +X right = tegetright(tp); +X bottom = tegetbottom(tp); +X if (a[0] < left) a[0] = left; +X if (a[1] < top) a[1] = top; +X if (a[2] > right) a[2] = right; +X if (a[3] > bottom) a[3] = bottom; +X if (a[0] < a[2] && a[1] < a[3]) { +X /* Hide/show focus around draw call; these are undocumented, +X but required here to get the highlighting correct. +X The call to werase is also required for this reason. +X Finally, this forces us to require (above) that we are NOT +X already drawing. */ +X tehidefocus(tp); +X wbegindrawing(self->t_ref->w_win); +X werase(a[0], a[1], a[2], a[3]); +X tedrawnew(tp, a[0], a[1], a[2], a[3]); +X wenddrawing(self->t_ref->w_win); +X teshowfocus(tp); +X } +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xtext_event(self, args) +X textobject *self; +X object *args; +X{ +X register TEXTEDIT *tp = self->t_text; +X EVENT e; +X if (!geteventarg(args, &e)) +X return NULL; +X if (e.type == WE_MOUSE_DOWN) { +X /* Cheat at the margins */ +X int width, height; +X wgetdocsize(e.window, &width, &height); +X if (e.u.where.h < 0 && tegetleft(tp) == 0) +X e.u.where.h = 0; +X else if (e.u.where.h > width && tegetright(tp) == width) +X e.u.where.h = width; +X if (e.u.where.v < 0 && tegettop(tp) == 0) +X e.u.where.v = 0; +X else if (e.u.where.v > height && tegetright(tp) == height) +X e.u.where.v = height; +X } +X return newintobject((long) teevent(tp, &e)); +X} +X +Xstatic object * +Xtext_getfocus(self, args) +X textobject *self; +X object *args; +X{ +X if (!getnoarg(args)) +X return NULL; +X return makepoint(tegetfoc1(self->t_text), tegetfoc2(self->t_text)); +X} +X +Xstatic object * +Xtext_getfocustext(self, args) +X textobject *self; +X object *args; +X{ +X int f1, f2; +X char *text; +X if (!getnoarg(args)) +X return NULL; +X f1 = tegetfoc1(self->t_text); +X f2 = tegetfoc2(self->t_text); +X text = tegettext(self->t_text); +X return newsizedstringobject(text + f1, f2-f1); +X} +X +Xstatic object * +Xtext_getrect(self, args) +X textobject *self; +X object *args; +X{ +X if (!getnoarg(args)) +X return NULL; +X return makerect(tegetleft(self->t_text), +X tegettop(self->t_text), +X tegetright(self->t_text), +X tegetbottom(self->t_text)); +X} +X +Xstatic object * +Xtext_gettext(self, args) +X textobject *self; +X object *args; +X{ +X if (!getnoarg(args)) +X return NULL; +X return newsizedstringobject(tegettext(self->t_text), +X tegetlen(self->t_text)); +X} +X +Xstatic object * +Xtext_move(self, args) +X textobject *self; +X object *args; +X{ +X int a[4]; +X if (!getrectarg(args, a)) +X return NULL; +X temovenew(self->t_text, a[0], a[1], a[2], a[3]); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xtext_setfocus(self, args) +X textobject *self; +X object *args; +X{ +X int a[2]; +X if (!getpointarg(args, a)) +X return NULL; +X tesetfocus(self->t_text, a[0], a[1]); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xtext_replace(self, args) +X textobject *self; +X object *args; +X{ +X object *text; +X if (!getstrarg(args, &text)) +X return NULL; +X tereplace(self->t_text, getstringvalue(text)); +X INCREF(None); +X return None; +X} +X +Xstatic struct methodlist text_methods[] = { +X "arrow", text_arrow, +X "draw", text_draw, +X "event", text_event, +X "getfocus", text_getfocus, +X "getfocustext", text_getfocustext, +X "getrect", text_getrect, +X "gettext", text_gettext, +X "move", text_move, +X "replace", text_replace, +X "setfocus", text_setfocus, +X {NULL, NULL} /* sentinel */ +X}; +X +Xstatic object * +Xtext_getattr(tp, name) +X textobject *tp; +X char *name; +X{ +X if (tp->t_attr != NULL) { +X object *v = dictlookup(tp->t_attr, name); +X if (v != NULL) { +X INCREF(v); +X return v; +X } +X } +X return findmethod(text_methods, (object *)tp, name); +X} +X +Xstatic int +Xtext_setattr(tp, name, v) +X textobject *tp; +X char *name; +X object *v; +X{ +X if (tp->t_attr == NULL) { +X tp->t_attr = newdictobject(); +X if (tp->t_attr == NULL) +X return -1; +X } +X if (v == NULL) +X return dictremove(tp->t_attr, name); +X else +X return dictinsert(tp->t_attr, name, v); +X} +X +Xstatic typeobject Texttype = { +X OB_HEAD_INIT(&Typetype) +X 0, /*ob_size*/ +X "textedit", /*tp_name*/ +X sizeof(textobject), /*tp_size*/ +X 0, /*tp_itemsize*/ +X /* methods */ +X text_dealloc, /*tp_dealloc*/ +X 0, /*tp_print*/ +X text_getattr, /*tp_getattr*/ +X text_setattr, /*tp_setattr*/ +X 0, /*tp_compare*/ +X 0, /*tp_repr*/ +X}; +X +X +X/* Menu objects */ +X +X#define IDOFFSET 10 /* Menu IDs we use start here */ +X#define MAXNMENU 20 /* Max #menus we allow */ +Xstatic menuobject *menulist[MAXNMENU]; +X +Xstatic menuobject * +Xnewmenuobject(title) +X object *title; +X{ +X int id; +X MENU *menu; +X menuobject *mp; +X for (id = 0; id < MAXNMENU; id++) { +X if (menulist[id] == NULL) +X break; +X } +X if (id >= MAXNMENU) +X return (menuobject *) err_nomem(); +X menu = wmenucreate(id + IDOFFSET, getstringvalue(title)); +X if (menu == NULL) +X return (menuobject *) err_nomem(); +X mp = NEWOBJ(menuobject, &Menutype); +X if (mp != NULL) { +X mp->m_menu = menu; +X mp->m_id = id + IDOFFSET; +X mp->m_attr = NULL; +X menulist[id] = mp; +X } +X else +X wmenudelete(menu); +X return mp; +X} +X +X/* Menu methods */ +X +Xstatic void +Xmenu_dealloc(mp) +X menuobject *mp; +X{ +X +X int id = mp->m_id - IDOFFSET; +X if (id >= 0 && id < MAXNMENU && menulist[id] == mp) { +X menulist[id] = NULL; +X } +X wmenudelete(mp->m_menu); +X if (mp->m_attr != NULL) +X DECREF(mp->m_attr); +X DEL(mp); +X} +X +Xstatic object * +Xmenu_additem(self, args) +X menuobject *self; +X object *args; +X{ +X object *text; +X int shortcut; +X if (is_tupleobject(args)) { +X object *v; +X if (!getstrstrarg(args, &text, &v)) +X return NULL; +X if (getstringsize(v) != 1) { +X err_badarg(); +X return NULL; +X } +X shortcut = *getstringvalue(v) & 0xff; +X } +X else { +X if (!getstrarg(args, &text)) +X return NULL; +X shortcut = -1; +X } +X wmenuadditem(self->m_menu, getstringvalue(text), shortcut); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xmenu_setitem(self, args) +X menuobject *self; +X object *args; +X{ +X int index; +X object *text; +X if (!getintstrarg(args, &index, &text)) +X return NULL; +X wmenusetitem(self->m_menu, index, getstringvalue(text)); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xmenu_enable(self, args) +X menuobject *self; +X object *args; +X{ +X int index; +X int flag; +X if (!getintintarg(args, &index, &flag)) +X return NULL; +X wmenuenable(self->m_menu, index, flag); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xmenu_check(self, args) +X menuobject *self; +X object *args; +X{ +X int index; +X int flag; +X if (!getintintarg(args, &index, &flag)) +X return NULL; +X wmenucheck(self->m_menu, index, flag); +X INCREF(None); +X return None; +X} +X +Xstatic struct methodlist menu_methods[] = { +X "additem", menu_additem, +X "setitem", menu_setitem, +X "enable", menu_enable, +X "check", menu_check, +X {NULL, NULL} /* sentinel */ +X}; +X +Xstatic object * +Xmenu_getattr(mp, name) +X menuobject *mp; +X char *name; +X{ +X if (mp->m_attr != NULL) { +X object *v = dictlookup(mp->m_attr, name); +X if (v != NULL) { +X INCREF(v); +X return v; +X } +X } +X return findmethod(menu_methods, (object *)mp, name); +X} +X +Xstatic int +Xmenu_setattr(mp, name, v) +X menuobject *mp; +X char *name; +X object *v; +X{ +X if (mp->m_attr == NULL) { +X mp->m_attr = newdictobject(); +X if (mp->m_attr == NULL) +X return -1; +X } +X if (v == NULL) +X return dictremove(mp->m_attr, name); +X else +X return dictinsert(mp->m_attr, name, v); +X} +X +Xstatic typeobject Menutype = { +X OB_HEAD_INIT(&Typetype) +X 0, /*ob_size*/ +X "menu", /*tp_name*/ +X sizeof(menuobject), /*tp_size*/ +X 0, /*tp_itemsize*/ +X /* methods */ +X menu_dealloc, /*tp_dealloc*/ +X 0, /*tp_print*/ +X menu_getattr, /*tp_getattr*/ +X menu_setattr, /*tp_setattr*/ +X 0, /*tp_compare*/ +X 0, /*tp_repr*/ +X}; +X +X +X/* Windows */ +X +X#define MAXNWIN 50 +Xstatic windowobject *windowlist[MAXNWIN]; +X +X/* Window methods */ +X +Xstatic void +Xwindow_dealloc(wp) +X windowobject *wp; +X{ +X if (wp->w_win != NULL) { +X int tag = wgettag(wp->w_win); +X if (tag >= 0 && tag < MAXNWIN) +X windowlist[tag] = NULL; +X else +X fprintf(stderr, "XXX help! tag %d in window_dealloc\n", +X tag); +X wclose(wp->w_win); +X } +X DECREF(wp->w_title); +X if (wp->w_attr != NULL) +X DECREF(wp->w_attr); +X free((char *)wp); +X} +X +Xstatic void +Xwindow_print(wp, fp, flags) +X windowobject *wp; +X FILE *fp; +X int flags; +X{ +X fprintf(fp, "<window titled '%s'>", getstringvalue(wp->w_title)); +X} +X +Xstatic object * +Xwindow_begindrawing(wp, args) +X windowobject *wp; +X object *args; +X{ +X drawingobject *dp; +X if (!getnoarg(args)) +X return NULL; +X if (Drawing != NULL) { +X err_setstr(RuntimeError, "already drawing"); +X return NULL; +X } +X dp = NEWOBJ(drawingobject, &Drawingtype); +X if (dp == NULL) +X return NULL; +X Drawing = dp; +X INCREF(wp); +X dp->d_ref = wp; +X wbegindrawing(wp->w_win); +X return (object *)dp; +X} +X +Xstatic object * +Xwindow_change(wp, args) +X windowobject *wp; +X object *args; +X{ +X int a[4]; +X if (!getrectarg(args, a)) +X return NULL; +X wchange(wp->w_win, a[0], a[1], a[2], a[3]); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xwindow_gettitle(wp, args) +X windowobject *wp; +X object *args; +X{ +X if (!getnoarg(args)) +X return NULL; +X INCREF(wp->w_title); +X return wp->w_title; +X} +X +Xstatic object * +Xwindow_getwinsize(wp, args) +X windowobject *wp; +X object *args; +X{ +X int width, height; +X if (!getnoarg(args)) +X return NULL; +X wgetwinsize(wp->w_win, &width, &height); +X return makepoint(width, height); +X} +X +Xstatic object * +Xwindow_getdocsize(wp, args) +X windowobject *wp; +X object *args; +X{ +X int width, height; +X if (!getnoarg(args)) +X return NULL; +X wgetdocsize(wp->w_win, &width, &height); +X return makepoint(width, height); +X} +X +Xstatic object * +Xwindow_getorigin(wp, args) +X windowobject *wp; +X object *args; +X{ +X int width, height; +X if (!getnoarg(args)) +X return NULL; +X wgetorigin(wp->w_win, &width, &height); +X return makepoint(width, height); +X} +X +Xstatic object * +Xwindow_scroll(wp, args) +X windowobject *wp; +X object *args; +X{ +X int a[6]; +X if (!getrectpointarg(args, a)) +X return NULL; +X wscroll(wp->w_win, a[0], a[1], a[2], a[3], a[4], a[5]); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xwindow_setdocsize(wp, args) +X windowobject *wp; +X object *args; +X{ +X int a[2]; +X if (!getpointarg(args, a)) +X return NULL; +X wsetdocsize(wp->w_win, a[0], a[1]); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xwindow_setorigin(wp, args) +X windowobject *wp; +X object *args; +X{ +X int a[2]; +X if (!getpointarg(args, a)) +X return NULL; +X wsetorigin(wp->w_win, a[0], a[1]); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xwindow_settitle(wp, args) +X windowobject *wp; +X object *args; +X{ +X object *title; +X if (!getstrarg(args, &title)) +X return NULL; +X DECREF(wp->w_title); +X INCREF(title); +X wp->w_title = title; +X wsettitle(wp->w_win, getstringvalue(title)); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xwindow_show(wp, args) +X windowobject *wp; +X object *args; +X{ +X int a[4]; +X if (!getrectarg(args, a)) +X return NULL; +X wshow(wp->w_win, a[0], a[1], a[2], a[3]); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xwindow_settimer(wp, args) +X windowobject *wp; +X object *args; +X{ +X int a; +X if (!getintarg(args, &a)) +X return NULL; +X wsettimer(wp->w_win, a); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xwindow_menucreate(self, args) +X windowobject *self; +X object *args; +X{ +X menuobject *mp; +X object *title; +X if (!getstrarg(args, &title)) +X return NULL; +X wmenusetdeflocal(1); +X mp = newmenuobject(title); +X if (mp == NULL) +X return NULL; +X wmenuattach(self->w_win, mp->m_menu); +X return (object *)mp; +X} +X +Xstatic object * +Xwindow_textcreate(self, args) +X windowobject *self; +X object *args; +X{ +X textobject *tp; +X int a[4]; +X if (!getrectarg(args, a)) +X return NULL; +X return (object *) +X newtextobject(self, a[0], a[1], a[2], a[3]); +X} +X +Xstatic object * +Xwindow_setselection(self, args) +X windowobject *self; +X object *args; +X{ +X int sel; +X object *str; +X int ok; +X if (!getintstrarg(args, &sel, &str)) +X return NULL; +X ok = wsetselection(self->w_win, sel, +X getstringvalue(str), (int)getstringsize(str)); +X return newintobject(ok); +X} +X +Xstatic object * +Xwindow_setwincursor(self, args) +X windowobject *self; +X object *args; +X{ +X object *str; +X CURSOR *c; +X if (!getstrarg(args, &str)) +X return NULL; +X c = wfetchcursor(getstringvalue(str)); +X if (c == NULL) { +X err_setstr(RuntimeError, "no such cursor"); +X return NULL; +X } +X wsetwincursor(self->w_win, c); +X INCREF(None); +X return None; +X} +X +Xstatic struct methodlist window_methods[] = { +X {"begindrawing",window_begindrawing}, +X {"change", window_change}, +X {"getdocsize", window_getdocsize}, +X {"getorigin", window_getorigin}, +X {"gettitle", window_gettitle}, +X {"getwinsize", window_getwinsize}, +X {"menucreate", window_menucreate}, +X {"scroll", window_scroll}, +X {"setwincursor",window_setwincursor}, +X {"setdocsize", window_setdocsize}, +X {"setorigin", window_setorigin}, +X {"setselection",window_setselection}, +X {"settimer", window_settimer}, +X {"settitle", window_settitle}, +X {"show", window_show}, +X {"textcreate", window_textcreate}, +X {NULL, NULL} /* sentinel */ +X}; +X +Xstatic object * +Xwindow_getattr(wp, name) +X windowobject *wp; +X char *name; +X{ +X if (wp->w_attr != NULL) { +X object *v = dictlookup(wp->w_attr, name); +X if (v != NULL) { +X INCREF(v); +X return v; +X } +X } +X return findmethod(window_methods, (object *)wp, name); +X} +X +Xstatic int +Xwindow_setattr(wp, name, v) +X windowobject *wp; +X char *name; +X object *v; +X{ +X if (wp->w_attr == NULL) { +X wp->w_attr = newdictobject(); +X if (wp->w_attr == NULL) +X return -1; +X } +X if (v == NULL) +X return dictremove(wp->w_attr, name); +X else +X return dictinsert(wp->w_attr, name, v); +X} +X +Xstatic typeobject Windowtype = { +X OB_HEAD_INIT(&Typetype) +X 0, /*ob_size*/ +X "window", /*tp_name*/ +X sizeof(windowobject), /*tp_size*/ +X 0, /*tp_itemsize*/ +X /* methods */ +X window_dealloc, /*tp_dealloc*/ +X window_print, /*tp_print*/ +X window_getattr, /*tp_getattr*/ +X window_setattr, /*tp_setattr*/ +X 0, /*tp_compare*/ +X 0, /*tp_repr*/ +X}; +X +X/* Stdwin methods */ +X +Xstatic object * +Xstdwin_open(sw, args) +X object *sw; +X object *args; +X{ +X int tag; +X object *title; +X windowobject *wp; +X if (!getstrarg(args, &title)) +X return NULL; +X for (tag = 0; tag < MAXNWIN; tag++) { +X if (windowlist[tag] == NULL) +X break; +X } +X if (tag >= MAXNWIN) +X return err_nomem(); +X wp = NEWOBJ(windowobject, &Windowtype); +X if (wp == NULL) +X return NULL; +X INCREF(title); +X wp->w_title = title; +X wp->w_win = wopen(getstringvalue(title), (void (*)()) NULL); +X wp->w_attr = NULL; +X if (wp->w_win == NULL) { +X DECREF(wp); +X return NULL; +X } +X windowlist[tag] = wp; +X wsettag(wp->w_win, tag); +X return (object *)wp; +X} +X +Xstatic object * +Xstdwin_get_poll_event(poll, args) +X int poll; +X object *args; +X{ +X EVENT e; +X object *v, *w; +X if (!getnoarg(args)) +X return NULL; +X if (Drawing != NULL) { +X err_setstr(RuntimeError, "cannot getevent() while drawing"); +X return NULL; +X } +X/* again: */ +X if (poll) { +X if (!wpollevent(&e)) { +X INCREF(None); +X return None; +X } +X } +X else +X wgetevent(&e); +X if (e.type == WE_COMMAND && e.u.command == WC_CANCEL) { +X /* Turn keyboard interrupts into exceptions */ +X err_set(KeyboardInterrupt); +X return NULL; +X } +X/* +X if (e.window == NULL && (e.type == WE_COMMAND || e.type == WE_CHAR)) +X goto again; +X*/ +X if (e.type == WE_COMMAND && e.u.command == WC_CLOSE) { +X /* Turn WC_CLOSE commands into WE_CLOSE events */ +X e.type = WE_CLOSE; +X } +X v = newtupleobject(3); +X if (v == NULL) +X return NULL; +X if ((w = newintobject((long)e.type)) == NULL) { +X DECREF(v); +X return NULL; +X } +X settupleitem(v, 0, w); +X if (e.window == NULL) +X w = None; +X else { +X int tag = wgettag(e.window); +X if (tag < 0 || tag >= MAXNWIN || windowlist[tag] == NULL) +X w = None; +X else +X w = (object *)windowlist[tag]; +X#ifdef sgi +X /* XXX Trap for unexplained weird bug */ +X if ((long)w == (long)0x80000001) { +X err_setstr(SystemError, +X "bad pointer in stdwin.getevent()"); +X return NULL; +X } +X#endif +X } +X INCREF(w); +X settupleitem(v, 1, w); +X switch (e.type) { +X case WE_CHAR: +X { +X char c[1]; +X c[0] = e.u.character; +X w = newsizedstringobject(c, 1); +X } +X break; +X case WE_COMMAND: +X w = newintobject((long)e.u.command); +X break; +X case WE_DRAW: +X w = makerect(e.u.area.left, e.u.area.top, +X e.u.area.right, e.u.area.bottom); +X break; +X case WE_MOUSE_DOWN: +X case WE_MOUSE_MOVE: +X case WE_MOUSE_UP: +X w = makemouse(e.u.where.h, e.u.where.v, +X e.u.where.clicks, +X e.u.where.button, +X e.u.where.mask); +X break; +X case WE_MENU: +X if (e.u.m.id >= IDOFFSET && e.u.m.id < IDOFFSET+MAXNMENU && +X menulist[e.u.m.id - IDOFFSET] != NULL) +X w = (object *)menulist[e.u.m.id - IDOFFSET]; +X else +X w = None; +X w = makemenu(w, e.u.m.item); +X break; +X case WE_LOST_SEL: +X w = newintobject((long)e.u.sel); +X break; +X default: +X w = None; +X INCREF(w); +X break; +X } +X if (w == NULL) { +X DECREF(v); +X return NULL; +X } +X settupleitem(v, 2, w); +X return v; +X} +X +Xstatic object * +Xstdwin_getevent(sw, args) +X object *sw; +X object *args; +X{ +X return stdwin_get_poll_event(0, args); +X} +X +Xstatic object * +Xstdwin_pollevent(sw, args) +X object *sw; +X object *args; +X{ +X return stdwin_get_poll_event(1, args); +X} +X +Xstatic object * +Xstdwin_setdefwinpos(sw, args) +X object *sw; +X object *args; +X{ +X int a[2]; +X if (!getpointarg(args, a)) +X return NULL; +X wsetdefwinpos(a[0], a[1]); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xstdwin_setdefwinsize(sw, args) +X object *sw; +X object *args; +X{ +X int a[2]; +X if (!getpointarg(args, a)) +X return NULL; +X wsetdefwinsize(a[0], a[1]); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xstdwin_getdefwinpos(wp, args) +X windowobject *wp; +X object *args; +X{ +X int h, v; +X if (!getnoarg(args)) +X return NULL; +X wgetdefwinpos(&h, &v); +X return makepoint(h, v); +X} +X +Xstatic object * +Xstdwin_getdefwinsize(wp, args) +X windowobject *wp; +X object *args; +X{ +X int width, height; +X if (!getnoarg(args)) +X return NULL; +X wgetdefwinsize(&width, &height); +X return makepoint(width, height); +X} +X +Xstatic object * +Xstdwin_menucreate(self, args) +X object *self; +X object *args; +X{ +X object *title; +X if (!getstrarg(args, &title)) +X return NULL; +X wmenusetdeflocal(0); +X return (object *)newmenuobject(title); +X} +X +Xstatic object * +Xstdwin_askfile(self, args) +X object *self; +X object *args; +X{ +X object *prompt, *dflt; +X int new, ret; +X char buf[256]; +X if (!getstrstrintarg(args, &prompt, &dflt, &new)) +X return NULL; +X strncpy(buf, getstringvalue(dflt), sizeof buf); +X buf[sizeof buf - 1] = '\0'; +X ret = waskfile(getstringvalue(prompt), buf, sizeof buf, new); +X if (!ret) { +X err_set(KeyboardInterrupt); +X return NULL; +X } +X return newstringobject(buf); +X} +X +Xstatic object * +Xstdwin_askync(self, args) +X object *self; +X object *args; +X{ +X object *prompt; +X int new, ret; +X if (!getstrintarg(args, &prompt, &new)) +X return NULL; +X ret = waskync(getstringvalue(prompt), new); +X if (ret < 0) { +X err_set(KeyboardInterrupt); +X return NULL; +X } +X return newintobject((long)ret); +X} +X +Xstatic object * +Xstdwin_askstr(self, args) +X object *self; +X object *args; +X{ +X object *prompt, *dflt; +X int ret; +X char buf[256]; +X if (!getstrstrarg(args, &prompt, &dflt)) +X return NULL; +X strncpy(buf, getstringvalue(dflt), sizeof buf); +X buf[sizeof buf - 1] = '\0'; +X ret = waskstr(getstringvalue(prompt), buf, sizeof buf); +X if (!ret) { +X err_set(KeyboardInterrupt); +X return NULL; +X } +X return newstringobject(buf); +X} +X +Xstatic object * +Xstdwin_message(self, args) +X object *self; +X object *args; +X{ +X object *msg; +X if (!getstrarg(args, &msg)) +X return NULL; +X wmessage(getstringvalue(msg)); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xstdwin_fleep(self, args) +X object *self; +X object *args; +X{ +X if (!getnoarg(args)) +X return NULL; +X wfleep(); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xstdwin_setcutbuffer(self, args) +X object *self; +X object *args; +X{ +X int i; +X object *str; +X if (!getintstrarg(args, &i, &str)) +X return NULL; +X wsetcutbuffer(i, getstringvalue(str), getstringsize(str)); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xstdwin_getcutbuffer(self, args) +X object *self; +X object *args; +X{ +X int i; +X char *str; +X int len; +X if (!getintarg(args, &i)) +X return NULL; +X str = wgetcutbuffer(i, &len); +X if (str == NULL) { +X str = ""; +X len = 0; +X } +X return newsizedstringobject(str, len); +X} +X +Xstatic object * +Xstdwin_rotatecutbuffers(self, args) +X object *self; +X object *args; +X{ +X int i; +X if (!getintarg(args, &i)) +X return NULL; +X wrotatecutbuffers(i); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xstdwin_getselection(self, args) +X object *self; +X object *args; +X{ +X int sel; +X char *data; +X int len; +X if (!getintarg(args, &sel)) +X return NULL; +X data = wgetselection(sel, &len); +X if (data == NULL) { +X data = ""; +X len = 0; +X } +X return newsizedstringobject(data, len); +X} +X +Xstatic object * +Xstdwin_resetselection(self, args) +X object *self; +X object *args; +X{ +X int sel; +X if (!getintarg(args, &sel)) +X return NULL; +X wresetselection(sel); +X INCREF(None); +X return None; +X} +X +Xstatic struct methodlist stdwin_methods[] = { +X {"askfile", stdwin_askfile}, +X {"askstr", stdwin_askstr}, +X {"askync", stdwin_askync}, +X {"fleep", stdwin_fleep}, +X {"getselection", stdwin_getselection}, +X {"getcutbuffer", stdwin_getcutbuffer}, +X {"getdefwinpos", stdwin_getdefwinpos}, +X {"getdefwinsize", stdwin_getdefwinsize}, +X {"getevent", stdwin_getevent}, +X {"menucreate", stdwin_menucreate}, +X {"message", stdwin_message}, +X {"open", stdwin_open}, +X {"pollevent", stdwin_pollevent}, +X {"resetselection", stdwin_resetselection}, +X {"rotatecutbuffers", stdwin_rotatecutbuffers}, +X {"setcutbuffer", stdwin_setcutbuffer}, +X {"setdefwinpos", stdwin_setdefwinpos}, +X {"setdefwinsize", stdwin_setdefwinsize}, +X +X /* Text measuring methods borrow code from drawing objects: */ +X {"baseline", drawing_baseline}, +X {"lineheight", drawing_lineheight}, +X {"textbreak", drawing_textbreak}, +X {"textwidth", drawing_textwidth}, +X {NULL, NULL} /* sentinel */ +X}; +X +Xvoid +Xinitstdwin() +X{ +X static int inited; +X if (!inited) { +X winit(); +X inited = 1; +X } +X initmodule("stdwin", stdwin_methods); +X} +EOF +fi +echo 'Part 04 out of 21 of pack.out complete.' +exit 0 diff --git a/shar/python-0.9.1-05-21.shar b/shar/python-0.9.1-05-21.shar new file mode 100644 index 0000000..2d7f035 --- /dev/null +++ b/shar/python-0.9.1-05-21.shar @@ -0,0 +1,2528 @@ +: This is a shell archive. +: Extract with 'sh this_file'. +: +: Extract part 01 first since it makes all directories +echo 'Start of pack.out, part 05 out of 21:' +if test -s 'demo/sgi/audio_stdwin/README' +then echo '*** I will not over-write existing file demo/sgi/audio_stdwin/README' +else +echo 'x - demo/sgi/audio_stdwin/README' +sed 's/^X//' > 'demo/sgi/audio_stdwin/README' << 'EOF' +XThree programs that provide a user interface based upon STDWIN to the +Xaudio device of the SGI 4D/25. These scripts also demonstrate the power +Xof a set of window interface classes implemented in Python that simplify +Xthe construction of all sorts of buttons, etc. +X +Xjukebox Browses a directory full of sound samples and lets you +X play selected ones. (Probably not fully functional, it +X requires a conversion program.) +X +Xrec A tape recorder that lets you record a sound sample, +X play it back, and save it to a file. Various options to +X set sampling rate, volume etc. When idle it doubles +X as a VU meter. +X +Xvumeter A VU meter that displays a history of the volume of +X sound recently sampled from the microphone. +EOF +fi +if test -s 'src/panelmodule.c' +then echo '*** I will not over-write existing file src/panelmodule.c' +else +echo 'x - src/panelmodule.c' +sed 's/^X//' > 'src/panelmodule.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Panel module. +X Interface to the NASA Ames "panel library" for the SGI Graphics Library +X by David Tristram. +X +X NOTE: the panel library dumps core if you don't create a window before +X calling pnl.mkpanel(). A call to gl.winopen() suffices. +X If you don't want a window to be created, call gl.noport() before +X gl.winopen(). +X*/ +X +X#include <gl.h> +X#include <device.h> +X#include <panel.h> +X +X#include "allobjects.h" +X#include "import.h" +X#include "modsupport.h" +X#include "cgensupport.h" +X +X +X/* The offsetof() macro calculates the offset of a structure member +X in its structure. Unfortunately this cannot be written down portably, +X hence it is standardized by ANSI C. For pre-ANSI C compilers, +X we give a version here that works usually (but watch out!): */ +X +X#ifndef offsetof +X#define offsetof(type, member) ( (int) & ((type*)0) -> member ) +X#endif +X +X +X/* Panel objects */ +X +Xtypedef struct { +X OB_HEAD +X Panel *ob_panel; +X object *ob_paneldict; +X} panelobject; +X +Xextern typeobject Paneltype; /* Really static, forward */ +X +X#define is_panelobject(v) ((v)->ob_type == &Paneltype) +X +X +X/* Actuator objects */ +X +Xtypedef struct { +X OB_HEAD +X Actuator *ob_actuator; +X} actuatorobject; +X +Xextern typeobject Actuatortype; /* Really static, forward */ +X +X#define is_actuatorobject(v) ((v)->ob_type == &Actuatortype) +X +Xstatic object *newactuatorobject(); /* Forward */ +X +X +X/* Since we allow different types of members than the functions from +X structmember.c, the memberlist stuff is replicated here. +X (Historically, it originated in this file and later became a generic +X feature.) */ +X +X/* An array of memberlist structures defines the name, type and offset +X of selected members of a C structure. These can be read by +X panel_getmember() and set by panel_setmember() (except if their +X READONLY flag is set). The array must be terminated with an entry +X whose name pointer is NULL. */ +X +Xstruct memberlist { +X char *name; +X int type; +X int offset; +X int readonly; +X}; +X +X/* Types */ +X#define T_SHORT 0 +X#define T_DEVICE T_SHORT +X#define T_LONG 1 +X#define T_INT T_LONG +X#define T_BOOL T_LONG +X#define T_FLOAT 2 +X#define T_COORD T_FLOAT +X#define T_STRING 3 +X#define T_FUNC 4 +X#define T_ACTUATOR 5 +X +X/* Readonly flag */ +X#define READONLY 1 +X#define RO READONLY /* Shorthand */ +X +Xstatic object * +Xpanel_getmember(addr, mlist, name) +X char *addr; +X struct memberlist *mlist; +X char *name; +X{ +X object *v; +X register struct memberlist *l; +X +X for (l = mlist; l->name != NULL; l++) { +X if (strcmp(l->name, name) == 0) { +X addr += l->offset; +X switch (l->type) { +X case T_SHORT: +X v = newintobject((long) *(short*)addr); +X break; +X case T_LONG: +X v = newintobject(*(long*)addr); +X break; +X case T_FLOAT: +X v = newfloatobject(*(float*)addr); +X break; +X case T_STRING: +X if (*(char**)addr == NULL) { +X INCREF(None); +X v = None; +X } +X else +X v = newstringobject(*(char**)addr); +X break; +X case T_ACTUATOR: +X v = newactuatorobject(*(Actuator**)addr); +X break; +X default: +X err_badarg(); +X v = NULL; +X } +X return v; +X } +X } +X err_setstr(NameError, name); +X return NULL; +X} +X +X/* Attempt to set a member. Return: 0 if OK; 1 if not found; -1 if error */ +X +Xstatic int +Xpanel_setmember(addr, mlist, name, v) +X char *addr; +X struct memberlist *mlist; +X char *name; +X object *v; +X{ +X register struct memberlist *l; +X +X for (l = mlist; l->name != NULL; l++) { +X if (strcmp(l->name, name) == 0) { +X if (l->readonly) { +X err_setstr(TypeError, "read-only member"); +X return -1; +X } +X addr += l->offset; +X switch (l->type) { +X case T_SHORT: +X if (!is_intobject(v)) { +X err_setstr(TypeError, "int expected"); +X return -1; +X } +X *(short*)addr = getintvalue(v); +X break; +X case T_LONG: +X if (!is_intobject(v)) { +X err_setstr(TypeError, "int expected"); +X return -1; +X } +X *(long*)addr = getintvalue(v); +X break; +X case T_FLOAT: +X if (is_intobject(v)) +X *(float*)addr = getintvalue(v); +X else if (is_floatobject(v)) +X *(float*)addr = getfloatvalue(v); +X else { +X err_setstr(TypeError,"float expected"); +X return -1; +X } +X break; +X case T_STRING: +X /* XXX Should free(*(char**)addr) here +X but it's dangerous since we don't know +X if we set the label ourselves */ +X if (v == None) +X *(char**)addr = NULL; +X else if (!is_stringobject(v)) { +X err_setstr(TypeError, +X "string expected"); +X return -1; +X } +X else +X *(char**)addr = +X strdup(getstringvalue(v)); +X break; +X case T_ACTUATOR: +X if (v == None) +X *(Actuator**)addr = NULL; +X else if (!is_actuatorobject(v)) { +X err_setstr(TypeError, +X "actuator expected"); +X return -1; +X } +X else +X *(Actuator**)addr = +X ((actuatorobject *)v)->ob_actuator; +X break; +X default: +X err_setstr(SystemError, "unknown member type"); +X return -1; +X } +X return 0; /* Found it */ +X } +X } +X +X return 1; /* Not found */ +X} +X +X +X/* Panel object methods */ +X +Xstatic object * +Xpanel_addpanel(self, args) +X panelobject *self; +X object *args; +X{ +X if (!getnoarg(args)) +X return NULL; +X pnl_addpanel(self->ob_panel); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xpanel_endgroup(self, args) +X panelobject *self; +X object *args; +X{ +X if (!getnoarg(args)) +X return NULL; +X pnl_endgroup(self->ob_panel); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xpanel_fixpanel(self, args) +X panelobject *self; +X object *args; +X{ +X if (!getnoarg(args)) +X return NULL; +X pnl_fixpanel(self->ob_panel); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xpanel_strwidth(self, args) +X panelobject *self; +X object *args; +X{ +X object *v; +X double width; +X if (!getstrarg(args, &v)) +X return NULL; +X width = pnl_strwidth(self->ob_panel, getstringvalue(v)); +X return newfloatobject(width); +X} +X +Xstatic struct methodlist panel_methods[] = { +X {"addpanel", panel_addpanel}, +X {"endgroup", panel_endgroup}, +X {"fixpanel", panel_fixpanel}, +X {"strwidth", panel_strwidth}, +X {NULL, NULL} /* sentinel */ +X}; +X +Xstatic object * +Xnewpanelobject() +X{ +X panelobject *p; +X p = NEWOBJ(panelobject, &Paneltype); +X if (p == NULL) +X return NULL; +X p->ob_panel = pnl_mkpanel(); +X if ((p->ob_paneldict = newdictobject()) == NULL) { +X DECREF(p); +X return NULL; +X } +X return (object *)p; +X} +X +Xstatic void +Xpanel_dealloc(p) +X panelobject *p; +X{ +X pnl_delpanel(p->ob_panel); +X if (p->ob_paneldict != NULL) +X DECREF(p->ob_paneldict); +X DEL(p); +X} +X +X +X/* Table of panel members */ +X +X#define PANOFF(member) offsetof(Panel, member) +X +Xstatic struct memberlist panel_memberlist[] = { +X {"id", T_SHORT, PANOFF(id), READONLY}, +X {"a", T_ACTUATOR, PANOFF(a), READONLY}, +X {"al", T_ACTUATOR, PANOFF(al), READONLY}, +X {"lastgroup", T_ACTUATOR, PANOFF(lastgroup), READONLY}, +X +X {"active", T_BOOL, PANOFF(active)}, +X {"selectable", T_BOOL, PANOFF(selectable)}, +X +X {"x", T_LONG, PANOFF(x)}, +X {"y", T_LONG, PANOFF(y)}, +X {"w", T_LONG, PANOFF(w)}, +X {"h", T_LONG, PANOFF(h)}, +X +X {"minx", T_COORD, PANOFF(minx)}, +X {"maxx", T_COORD, PANOFF(maxx)}, +X {"miny", T_COORD, PANOFF(miny)}, +X {"maxy", T_COORD, PANOFF(maxy)}, +X +X {"cw", T_COORD, PANOFF(cw)}, +X {"ch", T_COORD, PANOFF(ch)}, +X +X {"gid", T_LONG, PANOFF(gid), READONLY}, +X {"usergid", T_LONG, PANOFF(usergid), READONLY}, +X +X {"vobj", T_LONG, PANOFF(vobj), READONLY}, +X {"ppu", T_FLOAT, PANOFF(ppu)}, +X +X {"label", T_STRING, PANOFF(label)}, +X +X /* Panel callbacks are not supported */ +X +X {"visible", T_BOOL, PANOFF(visible)}, +X {"somedirty", T_INT, PANOFF(somedirty)}, +X {"dirtycnt", T_INT, PANOFF(dirtycnt)}, +X +X /* T_PANEL is not supported */ +X /* +X {"next", T_PANEL, PANOFF(next), READONLY}, +X */ +X +X {NULL, 0, 0} /* Sentinel */ +X}; +X +Xstatic object * +Xpanel_getattr(p, name) +X panelobject *p; +X char *name; +X{ +X object *v; +X +X v = dictlookup(p->ob_paneldict, name); +X if (v != NULL) { +X INCREF(v); +X return v; +X } +X +X v = findmethod(panel_methods, (object *)p, name); +X if (v != NULL) +X return v; +X err_clear(); +X return panel_getmember((char *)p->ob_panel, panel_memberlist, name); +X} +X +Xstatic int +Xpanel_setattr(p, name, v) +X panelobject *p; +X char *name; +X object *v; +X{ +X int err; +X +X /* We don't allow deletion of attributes */ +X if (v == NULL) { +X err_setstr(TypeError, "read-only panel attribute"); +X return -1; +X } +X err = panel_setmember((char *)p->ob_panel, panel_memberlist, name, v); +X if (err != 1) +X return err; +X return dictinsert(p->ob_paneldict, name, v); +X} +X +Xstatic typeobject Paneltype = { +X OB_HEAD_INIT(&Typetype) +X 0, /*ob_size*/ +X "panel", /*tp_name*/ +X sizeof(panelobject), /*tp_size*/ +X 0, /*tp_itemsize*/ +X /* methods */ +X panel_dealloc, /*tp_dealloc*/ +X 0, /*tp_print*/ +X panel_getattr, /*tp_getattr*/ +X panel_setattr, /*tp_setattr*/ +X 0, /*tp_compare*/ +X 0, /*tp_repr*/ +X}; +X +X +X/* Descriptions of actuator-specific data members */ +X +Xstruct memberlist slider_spec[] = { +X {"mode", T_INT, offsetof(Slider, mode)}, +X {"finefactor", T_FLOAT, offsetof(Slider, finefactor)}, +X {"differentialfactor", +X T_FLOAT, offsetof(Slider, differentialfactor)}, +X {"valsave", T_FLOAT, offsetof(Slider, valsave), RO}, +X {"wsave", T_COORD, offsetof(Slider, wsave)}, +X {"bh", T_COORD, offsetof(Slider, bh)}, +X {NULL} +X}; +X +X#define palette_spec slider_spec +X +Xstruct memberlist puck_spec[] = { +X /* Actuators already have members x and y, so the Puck's x and y +X have different names */ +X {"puck_x", T_FLOAT, offsetof(Puck, x)}, +X {"puck_y", T_FLOAT, offsetof(Puck, y)}, +X {NULL} +X}; +X +Xstruct memberlist dial_spec[] = { +X {"mode", T_INT, offsetof(Dial, mode)}, +X {"finefactor", T_FLOAT, offsetof(Dial, finefactor)}, +X {"valsave", T_FLOAT, offsetof(Dial, valsave), RO}, +X {"wsave", T_COORD, offsetof(Dial, wsave)}, +X {"winds", T_FLOAT, offsetof(Dial, winds)}, +X {NULL} +X}; +X +Xstruct memberlist slideroid_spec[] = { +X {"mode", T_INT, offsetof(Slideroid, mode)}, +X {"finemode", T_BOOL, offsetof(Slideroid, finemode)}, +X {"resetmode", T_BOOL, offsetof(Slideroid, resetmode)}, +X /* XXX Can't do resettarget (pointer to float) */ +X /* XXX This makes resetval pretty useless... */ +X /* +X {"resetval", T_FLOAT, offsetof(Slideroid, resetval)}, +X */ +X {"valsave", T_FLOAT, offsetof(Slideroid, valsave), RO}, +X {"wsave", T_COORD, offsetof(Slideroid, wsave)}, +X {NULL} +X}; +X +Xstruct memberlist stripchart_spec[] = { +X {"firstpt", T_INT, offsetof(Stripchart, firstpt), RO}, +X {"lastpt", T_INT, offsetof(Stripchart, lastpt), RO}, +X {"Bind_Low", T_BOOL, offsetof(Stripchart, Bind_Low)}, +X {"Bind_High", T_BOOL, offsetof(Stripchart, Bind_High)}, +X /* XXX Can't do y (array of floats) */ +X {"lowlabel", T_ACTUATOR, offsetof(Stripchart, lowlabel), RO}, +X {"highlabel", T_ACTUATOR, offsetof(Stripchart, highlabel), RO}, +X {NULL} +X}; +X +Xstruct memberlist typein_spec[] = { +X /* Note: these should be readonly after the actuator is added +X to a panel */ +X {"str", T_STRING, offsetof(Typein, str)}, +X {"len", T_INT, offsetof(Typein, len)}, +X {NULL} +X}; +X +Xstruct memberlist typeout_spec[] = { +X {"mode", T_INT, offsetof(Typeout, mode)}, +X /* XXX The buffer is managed by the actuator; but how do we +X add text? */ +X {"buf", T_STRING, offsetof(Typeout, buf), READONLY}, +X {"delimstr", T_STRING, offsetof(Typeout, delimstr)}, +X {"start", T_INT, offsetof(Typeout, start)}, +X {"dot", T_INT, offsetof(Typeout, dot)}, +X {"mark", T_INT, offsetof(Typeout, mark)}, +X {"col", T_INT, offsetof(Typeout, col)}, +X {"lin", T_INT, offsetof(Typeout, lin)}, +X {"len", T_INT, offsetof(Typeout, len)}, +X {"size", T_INT, offsetof(Typeout, size)}, +X {NULL} +X}; +X +Xstruct memberlist mouse_spec[] = { +X /* Actuators already have members x and y, so the Mouse's x and y +X have different names */ +X {"mouse_x", T_FLOAT, offsetof(Mouse, x)}, +X {"mouse_y", T_FLOAT, offsetof(Mouse, y)}, +X {NULL} +X}; +X +X#define MULOFF(member) offsetof(Multislider, member) +X +Xstruct memberlist multislider_spec[] = { +X {"mode", T_INT, MULOFF(mode)}, +X {"n", T_INT, MULOFF(n)}, +X {"finefactor", T_FLOAT, MULOFF(finefactor)}, +X {"wsave", T_COORD, MULOFF(wsave)}, +X {"sa", T_ACTUATOR, MULOFF(sa)}, +X {"bh", T_COORD, MULOFF(bh)}, +X {"clrx", T_COORD, MULOFF(clrx)}, +X {"clry", T_COORD, MULOFF(clry)}, +X {"clrw", T_COORD, MULOFF(clrw)}, +X {"clrh", T_COORD, MULOFF(clrh)}, +X /* XXX acttype? */ +X {NULL} +X}; +X +X/* XXX Still to do: +X Frame +X Icon +X Cycle +X Scroll +X Menu +X*/ +X +X/* List of known actuator initializer functions */ +X +Xstruct { +X char *name; +X void (*func)(); +X struct memberlist *spec; +X} initializerlist[] = { +X {"analog_bar", pnl_analog_bar}, +X {"analog_meter", pnl_analog_meter}, +X {"button", pnl_button}, +X {"cycle", pnl_cycle}, +X /* Doesn't exist: */ +X/* {"dhslider", pnl_dhslider, slider_spec}, */ +X {"dial", pnl_dial, dial_spec}, +X {"down_arrow_button", pnl_down_arrow_button}, +X {"down_double_arrow_button", pnl_down_double_arrow_button}, +X {"dvslider", pnl_dvslider, slider_spec}, +X {"filled_hslider", pnl_filled_hslider, slider_spec}, +X {"filled_slider", pnl_filled_slider, slider_spec}, +X {"filled_vslider", pnl_filled_vslider, slider_spec}, +X {"floating_puck", pnl_floating_puck, puck_spec}, +X {"frame", pnl_frame}, +X {"graphframe", pnl_graphframe}, +X {"hmultislider", pnl_hmultislider, multislider_spec}, +X {"hmultislider_bar", pnl_hmultislider_bar}, +X {"hmultislider_open_bar", pnl_hmultislider_open_bar}, +X {"hpalette", pnl_hpalette, palette_spec}, +X {"hslider", pnl_hslider, slider_spec}, +X {"icon", pnl_icon}, +X {"icon_menu", pnl_icon_menu}, +X {"label", pnl_label}, +X {"left_arrow_button", pnl_left_arrow_button}, +X {"left_double_arrow_button", pnl_left_double_arrow_button}, +X {"menu", pnl_menu}, +X {"menu_item", pnl_menu_item}, +X {"meter", pnl_meter}, +X {"mouse", pnl_mouse, mouse_spec}, +X {"multislider", pnl_multislider, multislider_spec}, +X {"multislider_bar", pnl_multislider_bar}, +X {"multislider_open_bar", pnl_multislider_open_bar}, +X {"palette", pnl_palette, palette_spec}, +X {"puck", pnl_puck, puck_spec}, +X {"radio_button", pnl_radio_button}, +X {"radio_check_button", pnl_radio_check_button}, +X {"right_arrow_button", pnl_right_arrow_button}, +X {"right_double_arrow_button", pnl_right_double_arrow_button}, +X {"rubber_puck", pnl_rubber_puck, puck_spec}, +X {"scale_chart", pnl_scale_chart, stripchart_spec}, +X {"scroll", pnl_scroll}, +X {"signal", pnl_signal}, +X {"slider", pnl_slider, slider_spec}, +X {"slideroid", pnl_slideroid, slideroid_spec}, +X {"strip_chart", pnl_strip_chart, stripchart_spec}, +X {"sub_menu", pnl_sub_menu}, +X {"toggle_button", pnl_toggle_button}, +X {"typein", pnl_typein, typein_spec}, +X {"typeout", pnl_typeout, typeout_spec}, +X {"up_arrow_button", pnl_up_arrow_button}, +X {"up_double_arrow_button", pnl_up_double_arrow_button}, +X {"viewframe", pnl_viewframe}, +X {"vmultislider", pnl_vmultislider, multislider_spec}, +X {"vmultislider_bar", pnl_vmultislider_bar}, +X {"vmultislider_open_bar", pnl_vmultislider_open_bar}, +X {"vpalette", pnl_vpalette, palette_spec}, +X {"vslider", pnl_vslider, slider_spec}, +X {"wide_button", pnl_wide_button}, +X {NULL, NULL} /* Sentinel */ +X}; +X +X +X/* Pseudo downfunc etc. */ +X +Xstatic Actuator *down_pend, *active_pend, *up_pend; +X +Xstatic void +Xdownfunc(a) +X Actuator *a; +X{ +X if (down_pend == NULL) +X down_pend = a; +X} +X +Xstatic void +Xactivefunc(a) +X Actuator *a; +X{ +X if (active_pend == NULL) +X active_pend = a; +X} +X +Xstatic void +Xupfunc(a) +X Actuator *a; +X{ +X if (up_pend == NULL) +X up_pend = a; +X} +X +X +X/* Lay-out for the user data */ +X +Xstruct userdata { +X object *dict; /* Dictionary object for additional attributes */ +X struct memberlist *spec; /* Actuator-specific members */ +X}; +X +X +X/* Create a new actuator; the actuator type is given as a string */ +X +Xstatic Actuator * +Xmakeactuator(name) +X char *name; +X{ +X Actuator *act; +X void (*initializer)() = NULL; +X int i; +X struct userdata *u; +X for (i = 0; initializerlist[i].name != NULL; i++) { +X if (strcmp(initializerlist[i].name, name) == 0) { +X initializer = initializerlist[i].func; +X break; +X } +X } +X if (initializerlist[i].name == NULL) { +X err_badarg(); +X return NULL; +X } +X u = NEW(struct userdata, 1); +X if (u == NULL) { +X err_nomem(); +X return NULL; +X } +X u->dict = NULL; +X u->spec = initializerlist[i].spec; +X act = pnl_mkact(initializer); +X act->u = (char *)u; +X act->downfunc = downfunc; +X act->activefunc = activefunc; +X act->upfunc = upfunc; +X return act; +X} +X +X +X/* Actuator objects methods */ +X +Xstatic object * +Xactuator_addact(self, args) +X actuatorobject *self; +X object *args; +X{ +X Panel *p; +X if (!is_panelobject(args)) { +X err_badarg(); +X return NULL; +X } +X p = ((panelobject *)args) -> ob_panel; +X pnl_addact(self->ob_actuator, p); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xactuator_addsubact(self, args) +X actuatorobject *self; +X object *args; +X{ +X Actuator *a; +X if (!is_actuatorobject(args)) { +X err_badarg(); +X return NULL; +X } +X a = ((actuatorobject *)args) -> ob_actuator; +X pnl_addsubact(self->ob_actuator, a); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xactuator_delact(self, args) +X actuatorobject *self; +X object *args; +X{ +X Panel *p; +X if (!getnoarg(args)) +X return NULL; +X pnl_delact(self->ob_actuator); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xactuator_fixact(self, args) +X actuatorobject *self; +X object *args; +X{ +X Panel *p; +X if (!getnoarg(args)) +X return NULL; +X pnl_fixact(self->ob_actuator); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xactuator_tprint(self, args) +X actuatorobject *self; +X object *args; +X{ +X object *str; +X if (self->ob_actuator->type != PNL_TYPEOUT) { +X err_setstr(TypeError, "tprint for non-typeout panel"); +X return NULL; +X } +X if (!getstrarg(args, &str)) +X return NULL; +X tprint(self->ob_actuator, getstringvalue(str)); +X /* XXX Can't turn tprint's errors into exceptions, sorry */ +X INCREF(None); +X return None; +X} +X +Xstatic struct methodlist actuator_methods[] = { +X {"addact", actuator_addact}, +X {"addsubact", actuator_addsubact}, +X {"delact", actuator_delact}, +X {"fixact", actuator_fixact}, +X {"tprint", actuator_tprint}, +X {NULL, NULL} /* sentinel */ +X}; +X +Xstatic object * +Xnewactuatorobject(act) +X Actuator *act; +X{ +X actuatorobject *a; +X if (act == NULL) { +X INCREF(None); +X return None; +X } +X a = NEWOBJ(actuatorobject, &Actuatortype); +X if (a == NULL) +X return NULL; +X a->ob_actuator = act; +X return (object *)a; +X} +X +Xstatic void +Xactuator_dealloc(a) +X actuatorobject *a; +X{ +X /* Do NOT delete the actuator; most actuator objects are created +X to hold a temporary reference to an actuator, like one gotten +X from pnl_dopanel(). */ +X +X DEL(a); +X} +X +X +X/* Table of actuator members */ +X +X#define ACTOFF(member) offsetof(Actuator, member) +X +Xstruct memberlist act_memberlist[] = { +X {"id", T_SHORT, ACTOFF(id), READONLY}, +X +X /* T_PANEL is not defined */ +X /* +X {"p", T_PANEL, ACTOFF(p), READONLY}, +X */ +X +X {"pa", T_ACTUATOR, ACTOFF(pa), READONLY}, +X {"ca", T_ACTUATOR, ACTOFF(ca), READONLY}, +X {"al", T_ACTUATOR, ACTOFF(al), READONLY}, +X {"na", T_INT, ACTOFF(na), READONLY}, +X {"type", T_INT, ACTOFF(type), READONLY}, +X {"active", T_BOOL, ACTOFF(active)}, +X +X {"x", T_COORD, ACTOFF(x)}, +X {"y", T_COORD, ACTOFF(y)}, +X {"w", T_COORD, ACTOFF(w)}, +X {"h", T_COORD, ACTOFF(h)}, +X +X {"lx", T_COORD, ACTOFF(lx)}, +X {"ly", T_COORD, ACTOFF(ly)}, +X {"lw", T_COORD, ACTOFF(lw)}, +X {"lh", T_COORD, ACTOFF(lh)}, +X {"ld", T_COORD, ACTOFF(ld)}, +X +X {"val", T_FLOAT, ACTOFF(val)}, +X {"extval", T_FLOAT, ACTOFF(extval)}, +X {"initval", T_FLOAT, ACTOFF(initval)}, +X {"maxval", T_FLOAT, ACTOFF(maxval)}, +X {"minval", T_FLOAT, ACTOFF(minval)}, +X {"scalefactor", T_FLOAT, ACTOFF(scalefactor)}, +X +X {"label", T_STRING, ACTOFF(label)}, +X {"key", T_DEVICE, ACTOFF(key)}, +X {"labeltype", T_INT, ACTOFF(labeltype)}, +X +X /* Internal callbacks are not supported; +X user callbacks are treated special! */ +X +X {"dirtycnt", T_INT, ACTOFF(dirtycnt)}, +X +X /* members u and data are accessed differently */ +X +X {"automatic", T_BOOL, ACTOFF(automatic)}, +X {"selectable", T_BOOL, ACTOFF(selectable)}, +X {"visible", T_BOOL, ACTOFF(visible)}, +X {"beveled", T_BOOL, ACTOFF(beveled)}, +X +X {"group", T_ACTUATOR, ACTOFF(group), READONLY}, +X {"next", T_ACTUATOR, ACTOFF(next), READONLY}, +X +X {NULL, 0, 0} /* Sentinel */ +X}; +X +X +X/* Potential name conflicts between attributes are solved as follows. +X - Actuator-specific attributes always override generic attributes. +X - When reading, the dictionary has overrides everything else; +X when writing, everything else overrides the dictionary. +X - When reading, methods are tried last. +X*/ +X +Xstatic object * +Xactuator_getattr(a, name) +X actuatorobject *a; +X char *name; +X{ +X Actuator *act = a->ob_actuator; +X struct userdata *u = (struct userdata *) act->u; +X object *v; +X +X if (u != NULL) { +X /* 1. Try the dictionary */ +X if (u->dict != NULL) { +X v = dictlookup(u->dict, name); +X if (v != NULL) { +X INCREF(v); +X return v; +X } +X } +X +X /* 2. Try actuator-specific attributes */ +X if (u->spec != NULL) { +X v = panel_getmember(act->data, u->spec, name); +X if (v != NULL) +X return v; +X err_clear(); +X } +X } +X +X /* 3. Try generic actuator attributes */ +X v = panel_getmember((char *)act, act_memberlist, name); +X if (v != NULL) +X return v; +X +X /* 4. Try methods */ +X err_clear(); +X return findmethod(actuator_methods, (object *)a, name); +X} +X +Xstatic int +Xactuator_setattr(a, name, v) +X actuatorobject *a; +X char *name; +X object *v; +X{ +X Actuator *act = a->ob_actuator; +X struct userdata *u = (struct userdata *) act->u; +X int err; +X +X /* 0. We don't allow deletion of attributes */ +X if (v == NULL) { +X err_setstr(TypeError, "read-only actuator attribute"); +X return -1; +X } +X +X /* 1. Try actuator-specific attributes */ +X if (u != NULL && u->spec != NULL) { +X err = panel_setmember(act->data, u->spec, name, v); +X if (err != 1) +X return err; +X } +X +X /* 2. Try generic actuator attributes */ +X err = panel_setmember((char *)act, act_memberlist, name, v); +X if (err != 1) +X return err; +X +X /* 3. Try the dictionary */ +X if (u != NULL) { +X if (u->dict == NULL && (u->dict = newdictobject()) == NULL) +X return NULL; +X return dictinsert(u->dict, name, v); +X } +X +X err_setstr(NameError, name); +X return -1; +X} +X +Xstatic int +Xactuator_compare(v, w) +X actuatorobject *v, *w; +X{ +X long i = (long)v->ob_actuator; +X long j = (long)w->ob_actuator; +X return (i < j) ? -1 : (i > j) ? 1 : 0; +X} +X +Xstatic typeobject Actuatortype = { +X OB_HEAD_INIT(&Typetype) +X 0, /*ob_size*/ +X "actuator", /*tp_name*/ +X sizeof(actuatorobject), /*tp_size*/ +X 0, /*tp_itemsize*/ +X /* methods */ +X actuator_dealloc, /*tp_dealloc*/ +X 0, /*tp_print*/ +X actuator_getattr, /*tp_getattr*/ +X actuator_setattr, /*tp_setattr*/ +X actuator_compare, /*tp_compare*/ +X 0, /*tp_repr*/ +X}; +X +X +X/* The panel module itself */ +X +Xstatic object * +Xmodule_mkpanel(self, args) +X object *self; +X object *args; +X{ +X if (!getnoarg(args)) +X return NULL; +X return newpanelobject(); +X} +X +Xstatic object * +Xmodule_mkact(self, args) +X object *self; +X object *args; +X{ +X object *v; +X Actuator *a; +X if (!getstrarg(args, &v)) +X return NULL; +X a = makeactuator(getstringvalue(v)); +X if (a == NULL) +X return NULL; +X return newactuatorobject(a); +X} +X +Xstatic object * +Xmodule_dopanel(self, args) +X object *self; +X object *args; +X{ +X Actuator *a; +X object *v, *w; +X if (!getnoarg(args)) +X return NULL; +X a = pnl_dopanel(); +X v = newtupleobject(4); +X if (v == NULL) +X return NULL; +X settupleitem(v, 0, newactuatorobject(a)); +X settupleitem(v, 1, newactuatorobject(down_pend)); +X settupleitem(v, 2, newactuatorobject(active_pend)); +X settupleitem(v, 3, newactuatorobject(up_pend)); +X down_pend = active_pend = up_pend = NULL; +X return v; +X} +X +Xstatic object * +Xmodule_drawpanel(self, args) +X object *self; +X object *args; +X{ +X if (!getnoarg(args)) +X return NULL; +X pnl_drawpanel(); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xmodule_needredraw(self, args) +X object *self; +X object *args; +X{ +X if (!getnoarg(args)) +X return NULL; +X pnl_needredraw(); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xmodule_userredraw(self, args) +X object *self; +X object *args; +X{ +X short wid; +X if (!getnoarg(args)) +X return NULL; +X wid = pnl_userredraw(); +X return newintobject((long)wid); +X} +X +Xstatic object * +Xmodule_block(self, args) +X object *self; +X object *args; +X{ +X int flag; +X if (!getintarg(args, &flag)) +X return NULL; +X pnl_block = flag; +X INCREF(None); +X return None; +X} +X +Xstatic struct methodlist module_methods[] = { +X {"block", module_block}, +X {"dopanel", module_dopanel}, +X {"drawpanel", module_drawpanel}, +X {"mkpanel", module_mkpanel}, +X {"mkact", module_mkact}, +X {"needredraw", module_needredraw}, +X {"userredraw", module_userredraw}, +X {NULL, NULL} /* sentinel */ +X}; +X +Xvoid +Xinitpanel() +X{ +X /* Setting pnl_block to 1 would greatly reduce the CPU usage +X of an idle application. Unfortunately it also breaks our +X little hacks to get callback functions in Python called. +X So we clear pnl_block here. You can set/clear pnl_block +X from Python using pnl.block(flag). It works if you have +X no upfuncs. */ +X pnl_block = 0; +X initmodule("pnl", module_methods); +X} +EOF +fi +if test -s 'src/regexp.c' +then echo '*** I will not over-write existing file src/regexp.c' +else +echo 'x - src/regexp.c' +sed 's/^X//' > 'src/regexp.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* +X * regcomp and regexec -- regsub and regerror are elsewhere +X * +X * Copyright (c) 1986 by University of Toronto. +X * Written by Henry Spencer. Not derived from licensed software. +X#ifdef MULTILINE +X * Changed by Guido van Rossum, CWI, Amsterdam +X * for multi-line support. +X#endif +X * +X * Permission is granted to anyone to use this software for any +X * purpose on any computer system, and to redistribute it freely, +X * subject to the following restrictions: +X * +X * 1. The author is not responsible for the consequences of use of +X * this software, no matter how awful, even if they arise +X * from defects in it. +X * +X * 2. The origin of this software must not be misrepresented, either +X * by explicit claim or by omission. +X * +X * 3. Altered versions must be plainly marked as such, and must not +X * be misrepresented as being the original software. +X * +X * Beware that some of this code is subtly aware of the way operator +X * precedence is structured in regular expressions. Serious changes in +X * regular-expression syntax might require a total rethink. +X */ +X#include <stdio.h> +X#include "PROTO.h" +X#include "malloc.h" +X#undef ANY /* Conflicting identifier defined in malloc.h */ +X#include <string.h> /* XXX Remove if not found */ +X#include "regexp.h" +X#include "regmagic.h" +X +X#ifdef MULTILINE +X/* +X * Defining MULTILINE turns on the following changes in the semantics: +X * 1. The '.' operator matches all characters except a newline. +X * 2. The '^' operator matches at the beginning of the string or after +X * a newline. (Anchored matches are retried after each newline.) +X * 3. The '$' operator matches at the end of the string or before +X * a newline. +X * 4. A '\' followed by an 'n' matches a newline. (This is an +X * unfortunate exception to the rule that '\' followed by a +X * character matches that character...) +X * +X * Also, there is a new function reglexec(prog, string, offset) +X * which searches for a match starting at 'string+offset'; +X * it differs from regexec(prog, string+offset) in assuming +X * that the line begins at 'string'. +X */ +X#endif +X +X/* +X * The "internal use only" fields in regexp.h are present to pass info from +X * compile to execute that permits the execute phase to run lots faster on +X * simple cases. They are: +X * +X * regstart char that must begin a match; '\0' if none obvious +X * reganch is the match anchored (at beginning-of-line only)? +X * regmust string (pointer into program) that match must include, or NULL +X * regmlen length of regmust string +X * +X * Regstart and reganch permit very fast decisions on suitable starting points +X * for a match, cutting down the work a lot. Regmust permits fast rejection +X * of lines that cannot possibly match. The regmust tests are costly enough +X * that regcomp() supplies a regmust only if the r.e. contains something +X * potentially expensive (at present, the only such thing detected is * or + +X * at the start of the r.e., which can involve a lot of backup). Regmlen is +X * supplied because the test in regexec() needs it and regcomp() is computing +X * it anyway. +X */ +X +X/* +X * Structure for regexp "program". This is essentially a linear encoding +X * of a nondeterministic finite-state machine (aka syntax charts or +X * "railroad normal form" in parsing technology). Each node is an opcode +X * plus a "next" pointer, possibly plus an operand. "Next" pointers of +X * all nodes except BRANCH implement concatenation; a "next" pointer with +X * a BRANCH on both ends of it is connecting two alternatives. (Here we +X * have one of the subtle syntax dependencies: an individual BRANCH (as +X * opposed to a collection of them) is never concatenated with anything +X * because of operator precedence.) The operand of some types of node is +X * a literal string; for others, it is a node leading into a sub-FSM. In +X * particular, the operand of a BRANCH node is the first node of the branch. +X * (NB this is *not* a tree structure: the tail of the branch connects +X * to the thing following the set of BRANCHes.) The opcodes are: +X */ +X +X/* definition number opnd? meaning */ +X#define END 0 /* no End of program. */ +X#define BOL 1 /* no Match "" at beginning of line. */ +X#define EOL 2 /* no Match "" at end of line. */ +X#define ANY 3 /* no Match any one character. */ +X#define ANYOF 4 /* str Match any character in this string. */ +X#define ANYBUT 5 /* str Match any character not in this string. */ +X#define BRANCH 6 /* node Match this alternative, or the next... */ +X#define BACK 7 /* no Match "", "next" ptr points backward. */ +X#define EXACTLY 8 /* str Match this string. */ +X#define NOTHING 9 /* no Match empty string. */ +X#define STAR 10 /* node Match this (simple) thing 0 or more times. */ +X#define PLUS 11 /* node Match this (simple) thing 1 or more times. */ +X#define OPEN 20 /* no Mark this point in input as start of #n. */ +X /* OPEN+1 is number 1, etc. */ +X#define CLOSE 30 /* no Analogous to OPEN. */ +X +X/* +X * Opcode notes: +X * +X * BRANCH The set of branches constituting a single choice are hooked +X * together with their "next" pointers, since precedence prevents +X * anything being concatenated to any individual branch. The +X * "next" pointer of the last BRANCH in a choice points to the +X * thing following the whole choice. This is also where the +X * final "next" pointer of each individual branch points; each +X * branch starts with the operand node of a BRANCH node. +X * +X * BACK Normal "next" pointers all implicitly point forward; BACK +X * exists to make loop structures possible. +X * +X * STAR,PLUS '?', and complex '*' and '+', are implemented as circular +X * BRANCH structures using BACK. Simple cases (one character +X * per match) are implemented with STAR and PLUS for speed +X * and to minimize recursive plunges. +X * +X * OPEN,CLOSE ...are numbered at compile time. +X */ +X +X/* +X * A node is one char of opcode followed by two chars of "next" pointer. +X * "Next" pointers are stored as two 8-bit pieces, high order first. The +X * value is a positive offset from the opcode of the node containing it. +X * An operand, if any, simply follows the node. (Note that much of the +X * code generation knows about this implicit relationship.) +X * +X * Using two bytes for the "next" pointer is vast overkill for most things, +X * but allows patterns to get big without disasters. +X */ +X#define OP(p) (*(p)) +X#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377)) +X#define OPERAND(p) ((p) + 3) +X +X/* +X * See regmagic.h for one further detail of program structure. +X */ +X +X +X/* +X * Utility definitions. +X */ +X#ifndef CHARBITS +X#define UCHARAT(p) ((int)*(unsigned char *)(p)) +X#else +X#define UCHARAT(p) ((int)*(p)&CHARBITS) +X#endif +X +X#define FAIL(m) { regerror(m); return(NULL); } +X#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?') +X#define META "^$.[()|?+*\\" +X +X/* +X * Flags to be passed up and down. +X */ +X#define HASWIDTH 01 /* Known never to match null string. */ +X#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */ +X#define SPSTART 04 /* Starts with * or +. */ +X#define WORST 0 /* Worst case. */ +X +X/* +X * Global work variables for regcomp(). +X */ +Xstatic char *regparse; /* Input-scan pointer. */ +Xstatic int regnpar; /* () count. */ +Xstatic char regdummy; +Xstatic char *regcode; /* Code-emit pointer; ®dummy = don't. */ +Xstatic long regsize; /* Code size. */ +X#ifdef MULTILINE +Xstatic int regnl; /* '\n' detected. */ +X#endif +X +X/* +X * Forward declarations for regcomp()'s friends. +X */ +X#ifndef STATIC +X#define STATIC static +X#endif +XSTATIC char *reg(); +XSTATIC char *regbranch(); +XSTATIC char *regpiece(); +XSTATIC char *regatom(); +XSTATIC char *regnode(); +XSTATIC char *regnext(); +XSTATIC void regc(); +XSTATIC void reginsert(); +XSTATIC void regtail(); +XSTATIC void regoptail(); +X#ifdef STRCSPN +XSTATIC int strcspn(); +X#endif +X +X/* +X - regcomp - compile a regular expression into internal code +X * +X * We can't allocate space until we know how big the compiled form will be, +X * but we can't compile it (and thus know how big it is) until we've got a +X * place to put the code. So we cheat: we compile it twice, once with code +X * generation turned off and size counting turned on, and once "for real". +X * This also means that we don't allocate space until we are sure that the +X * thing really will compile successfully, and we never have to move the +X * code and thus invalidate pointers into it. (Note that it has to be in +X * one piece because free() must be able to free it all.) +X * +X * Beware that the optimization-preparation code in here knows about some +X * of the structure of the compiled regexp. +X */ +Xregexp * +Xregcomp(exp) +Xchar *exp; +X{ +X register regexp *r; +X register char *scan; +X register char *longest; +X register int len; +X int flags; +X +X if (exp == NULL) +X FAIL("NULL argument"); +X +X /* First pass: determine size, legality. */ +X regparse = exp; +X regnpar = 1; +X regsize = 0L; +X regcode = ®dummy; +X#ifdef MULTILINE +X regnl = 0; +X#endif +X regc(MAGIC); +X if (reg(0, &flags) == NULL) +X return(NULL); +X +X /* Small enough for pointer-storage convention? */ +X if (regsize >= 32767L) /* Probably could be 65535L. */ +X FAIL("regexp too big"); +X +X /* Allocate space. */ +X r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize); +X if (r == NULL) +X FAIL("out of space"); +X +X /* Second pass: emit code. */ +X regparse = exp; +X regnpar = 1; +X regcode = r->program; +X regc(MAGIC); +X if (reg(0, &flags) == NULL) +X return(NULL); +X +X /* Dig out information for optimizations. */ +X r->regstart = '\0'; /* Worst-case defaults. */ +X r->reganch = 0; +X r->regmust = NULL; +X r->regmlen = 0; +X scan = r->program+1; /* First BRANCH. */ +X if (OP(regnext(scan)) == END) { /* Only one top-level choice. */ +X scan = OPERAND(scan); +X +X /* Starting-point info. */ +X if (OP(scan) == EXACTLY) +X r->regstart = *OPERAND(scan); +X else if (OP(scan) == BOL) +X r->reganch++; +X +X /* +X * If there's something expensive in the r.e., find the +X * longest literal string that must appear and make it the +X * regmust. Resolve ties in favor of later strings, since +X * the regstart check works with the beginning of the r.e. +X * and avoiding duplication strengthens checking. Not a +X * strong reason, but sufficient in the absence of others. +X */ +X#ifdef MULTILINE +X if ((flags&SPSTART) && !regnl) { +X#else +X if (flags&SPSTART) { +X#endif +X longest = NULL; +X len = 0; +X for (; scan != NULL; scan = regnext(scan)) +X if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) { +X longest = OPERAND(scan); +X len = strlen(OPERAND(scan)); +X } +X r->regmust = longest; +X r->regmlen = len; +X } +X } +X +X return(r); +X} +X +X/* +X - reg - regular expression, i.e. main body or parenthesized thing +X * +X * Caller must absorb opening parenthesis. +X * +X * Combining parenthesis handling with the base level of regular expression +X * is a trifle forced, but the need to tie the tails of the branches to what +X * follows makes it hard to avoid. +X */ +Xstatic char * +Xreg(paren, flagp) +Xint paren; /* Parenthesized? */ +Xint *flagp; +X{ +X register char *ret; +X register char *br; +X register char *ender; +X register int parno; +X int flags; +X +X *flagp = HASWIDTH; /* Tentatively. */ +X +X /* Make an OPEN node, if parenthesized. */ +X if (paren) { +X if (regnpar >= NSUBEXP) +X FAIL("too many ()"); +X parno = regnpar; +X regnpar++; +X ret = regnode(OPEN+parno); +X } else +X ret = NULL; +X +X /* Pick up the branches, linking them together. */ +X br = regbranch(&flags); +X if (br == NULL) +X return(NULL); +X if (ret != NULL) +X regtail(ret, br); /* OPEN -> first. */ +X else +X ret = br; +X if (!(flags&HASWIDTH)) +X *flagp &= ~HASWIDTH; +X *flagp |= flags&SPSTART; +X while (*regparse == '|') { +X regparse++; +X br = regbranch(&flags); +X if (br == NULL) +X return(NULL); +X regtail(ret, br); /* BRANCH -> BRANCH. */ +X if (!(flags&HASWIDTH)) +X *flagp &= ~HASWIDTH; +X *flagp |= flags&SPSTART; +X } +X +X /* Make a closing node, and hook it on the end. */ +X ender = regnode((paren) ? CLOSE+parno : END); +X regtail(ret, ender); +X +X /* Hook the tails of the branches to the closing node. */ +X for (br = ret; br != NULL; br = regnext(br)) +X regoptail(br, ender); +X +X /* Check for proper termination. */ +X if (paren && *regparse++ != ')') { +X FAIL("unmatched ()"); +X } else if (!paren && *regparse != '\0') { +X if (*regparse == ')') { +X FAIL("unmatched ()"); +X } else +X FAIL("junk on end"); /* "Can't happen". */ +X /* NOTREACHED */ +X } +X +X return(ret); +X} +X +X/* +X - regbranch - one alternative of an | operator +X * +X * Implements the concatenation operator. +X */ +Xstatic char * +Xregbranch(flagp) +Xint *flagp; +X{ +X register char *ret; +X register char *chain; +X register char *latest; +X int flags; +X +X *flagp = WORST; /* Tentatively. */ +X +X ret = regnode(BRANCH); +X chain = NULL; +X while (*regparse != '\0' && *regparse != '|' && *regparse != ')') { +X latest = regpiece(&flags); +X if (latest == NULL) +X return(NULL); +X *flagp |= flags&HASWIDTH; +X if (chain == NULL) /* First piece. */ +X *flagp |= flags&SPSTART; +X else +X regtail(chain, latest); +X chain = latest; +X } +X if (chain == NULL) /* Loop ran zero times. */ +X (void) regnode(NOTHING); +X +X return(ret); +X} +X +X/* +X - regpiece - something followed by possible [*+?] +X * +X * Note that the branching code sequences used for ? and the general cases +X * of * and + are somewhat optimized: they use the same NOTHING node as +X * both the endmarker for their branch list and the body of the last branch. +X * It might seem that this node could be dispensed with entirely, but the +X * endmarker role is not redundant. +X */ +Xstatic char * +Xregpiece(flagp) +Xint *flagp; +X{ +X register char *ret; +X register char op; +X register char *next; +X int flags; +X +X ret = regatom(&flags); +X if (ret == NULL) +X return(NULL); +X +X op = *regparse; +X if (!ISMULT(op)) { +X *flagp = flags; +X return(ret); +X } +X +X if (!(flags&HASWIDTH) && op != '?') +X FAIL("*+ operand could be empty"); +X *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH); +X +X if (op == '*' && (flags&SIMPLE)) +X reginsert(STAR, ret); +X else if (op == '*') { +X /* Emit x* as (x&|), where & means "self". */ +X reginsert(BRANCH, ret); /* Either x */ +X regoptail(ret, regnode(BACK)); /* and loop */ +X regoptail(ret, ret); /* back */ +X regtail(ret, regnode(BRANCH)); /* or */ +X regtail(ret, regnode(NOTHING)); /* null. */ +X } else if (op == '+' && (flags&SIMPLE)) +X reginsert(PLUS, ret); +X else if (op == '+') { +X /* Emit x+ as x(&|), where & means "self". */ +X next = regnode(BRANCH); /* Either */ +X regtail(ret, next); +X regtail(regnode(BACK), ret); /* loop back */ +X regtail(next, regnode(BRANCH)); /* or */ +X regtail(ret, regnode(NOTHING)); /* null. */ +X } else if (op == '?') { +X /* Emit x? as (x|) */ +X reginsert(BRANCH, ret); /* Either x */ +X regtail(ret, regnode(BRANCH)); /* or */ +X next = regnode(NOTHING); /* null. */ +X regtail(ret, next); +X regoptail(ret, next); +X } +X regparse++; +X if (ISMULT(*regparse)) +X FAIL("nested *?+"); +X +X return(ret); +X} +X +X/* +X - regatom - the lowest level +X * +X * Optimization: gobbles an entire sequence of ordinary characters so that +X * it can turn them into a single node, which is smaller to store and +X * faster to run. Backslashed characters are exceptions, each becoming a +X * separate node; the code is simpler that way and it's not worth fixing. +X */ +Xstatic char * +Xregatom(flagp) +Xint *flagp; +X{ +X register char *ret; +X int flags; +X +X *flagp = WORST; /* Tentatively. */ +X +X switch (*regparse++) { +X case '^': +X ret = regnode(BOL); +X break; +X case '$': +X ret = regnode(EOL); +X break; +X case '.': +X ret = regnode(ANY); +X *flagp |= HASWIDTH|SIMPLE; +X break; +X case '[': { +X register int class; +X register int classend; +X +X if (*regparse == '^') { /* Complement of range. */ +X ret = regnode(ANYBUT); +X regparse++; +X } else +X ret = regnode(ANYOF); +X if (*regparse == ']' || *regparse == '-') +X regc(*regparse++); +X while (*regparse != '\0' && *regparse != ']') { +X if (*regparse == '-') { +X regparse++; +X if (*regparse == ']' || *regparse == '\0') +X regc('-'); +X else { +X class = UCHARAT(regparse-2)+1; +X classend = UCHARAT(regparse); +X if (class > classend+1) +X FAIL("invalid [] range"); +X for (; class <= classend; class++) +X regc(class); +X regparse++; +X } +X } else +X regc(*regparse++); +X } +X regc('\0'); +X if (*regparse != ']') +X FAIL("unmatched []"); +X regparse++; +X *flagp |= HASWIDTH|SIMPLE; +X } +X break; +X case '(': +X ret = reg(1, &flags); +X if (ret == NULL) +X return(NULL); +X *flagp |= flags&(HASWIDTH|SPSTART); +X break; +X case '\0': +X case '|': +X case ')': +X FAIL("internal urp"); /* Supposed to be caught earlier. */ +X break; +X case '?': +X case '+': +X case '*': +X FAIL("?+* follows nothing"); +X break; +X case '\\': +X if (*regparse == '\0') +X FAIL("trailing \\"); +X ret = regnode(EXACTLY); +X#ifdef MULTILINE +X if (*regparse == 'n') { +X regc('\n'); +X regparse++; +X regnl++; +X } +X else +X#endif +X regc(*regparse++); +X regc('\0'); +X *flagp |= HASWIDTH|SIMPLE; +X break; +X default: { +X register int len; +X register char ender; +X +X regparse--; +X len = strcspn(regparse, META); +X if (len <= 0) +X FAIL("internal disaster"); +X ender = *(regparse+len); +X if (len > 1 && ISMULT(ender)) +X len--; /* Back off clear of ?+* operand. */ +X *flagp |= HASWIDTH; +X if (len == 1) +X *flagp |= SIMPLE; +X ret = regnode(EXACTLY); +X while (len > 0) { +X#ifdef MULTILINE +X if (*regparse == '\n') +X regnl++; +X#endif +X regc(*regparse++); +X len--; +X } +X regc('\0'); +X } +X break; +X } +X +X return(ret); +X} +X +X/* +X - regnode - emit a node +X */ +Xstatic char * /* Location. */ +Xregnode(op) +Xchar op; +X{ +X register char *ret; +X register char *ptr; +X +X ret = regcode; +X if (ret == ®dummy) { +X regsize += 3; +X return(ret); +X } +X +X ptr = ret; +X *ptr++ = op; +X *ptr++ = '\0'; /* Null "next" pointer. */ +X *ptr++ = '\0'; +X regcode = ptr; +X +X return(ret); +X} +X +X/* +X - regc - emit (if appropriate) a byte of code +X */ +Xstatic void +Xregc(b) +Xchar b; +X{ +X if (regcode != ®dummy) +X *regcode++ = b; +X else +X regsize++; +X} +X +X/* +X - reginsert - insert an operator in front of already-emitted operand +X * +X * Means relocating the operand. +X */ +Xstatic void +Xreginsert(op, opnd) +Xchar op; +Xchar *opnd; +X{ +X register char *src; +X register char *dst; +X register char *place; +X +X if (regcode == ®dummy) { +X regsize += 3; +X return; +X } +X +X src = regcode; +X regcode += 3; +X dst = regcode; +X while (src > opnd) +X *--dst = *--src; +X +X place = opnd; /* Op node, where operand used to be. */ +X *place++ = op; +X *place++ = '\0'; +X *place++ = '\0'; +X} +X +X/* +X - regtail - set the next-pointer at the end of a node chain +X */ +Xstatic void +Xregtail(p, val) +Xchar *p; +Xchar *val; +X{ +X register char *scan; +X register char *temp; +X register int offset; +X +X if (p == ®dummy) +X return; +X +X /* Find last node. */ +X scan = p; +X for (;;) { +X temp = regnext(scan); +X if (temp == NULL) +X break; +X scan = temp; +X } +X +X if (OP(scan) == BACK) +X offset = scan - val; +X else +X offset = val - scan; +X *(scan+1) = (offset>>8)&0377; +X *(scan+2) = offset&0377; +X} +X +X/* +X - regoptail - regtail on operand of first argument; nop if operandless +X */ +Xstatic void +Xregoptail(p, val) +Xchar *p; +Xchar *val; +X{ +X /* "Operandless" and "op != BRANCH" are synonymous in practice. */ +X if (p == NULL || p == ®dummy || OP(p) != BRANCH) +X return; +X regtail(OPERAND(p), val); +X} +X +X/* +X * regexec and friends +X */ +X +X/* +X * Global work variables for regexec(). +X */ +Xstatic char *reginput; /* String-input pointer. */ +Xstatic char *regbol; /* Beginning of input, for ^ check. */ +Xstatic char **regstartp; /* Pointer to startp array. */ +Xstatic char **regendp; /* Ditto for endp. */ +X +X/* +X * Forwards. +X */ +XSTATIC int regtry(); +XSTATIC int regmatch(); +XSTATIC int regrepeat(); +X +X#ifdef DEBUG +Xint regnarrate = 0; +Xvoid regdump(); +XSTATIC char *regprop(); +X#endif +X +X/* +X - regexec - match a regexp against a string +X */ +Xint +Xregexec(prog, string) +Xregister regexp *prog; +Xregister char *string; +X{ +X register char *s; +X extern char *strchr(); +X +X /* Be paranoid... */ +X if (prog == NULL || string == NULL) { +X regerror("NULL parameter"); +X return(0); +X } +X +X#ifdef MULTILINE +X /* Check for \n in string, and if so, call the more general routine. */ +X if (strchr(string, '\n') != NULL) +X return reglexec(prog, string, 0); +X#endif +X +X /* Check validity of program. */ +X if (UCHARAT(prog->program) != MAGIC) { +X regerror("corrupted program"); +X return(0); +X } +X +X /* If there is a "must appear" string, look for it. */ +X if (prog->regmust != NULL) { +X s = string; +X while ((s = strchr(s, prog->regmust[0])) != NULL) { +X if (strncmp(s, prog->regmust, prog->regmlen) == 0) +X break; /* Found it. */ +X s++; +X } +X if (s == NULL) /* Not present. */ +X return(0); +X } +X +X /* Mark beginning of line for ^ . */ +X regbol = string; +X +X /* Simplest case: anchored match need be tried only once. */ +X if (prog->reganch) +X return(regtry(prog, string)); +X +X /* Messy cases: unanchored match. */ +X s = string; +X if (prog->regstart != '\0') +X /* We know what char it must start with. */ +X while ((s = strchr(s, prog->regstart)) != NULL) { +X if (regtry(prog, s)) +X return(1); +X s++; +X } +X else +X /* We don't -- general case. */ +X do { +X if (regtry(prog, s)) +X return(1); +X } while (*s++ != '\0'); +X +X /* Failure. */ +X return(0); +X} +X +X#ifdef MULTILINE +X/* +X - reglexec - match a regexp against a long string buffer, starting at offset +X */ +Xint +Xreglexec(prog, string, offset) +Xregister regexp *prog; +Xregister char *string; +X{ +X register char *s; +X extern char *strchr(); +X +X /* Be paranoid... */ +X if (prog == NULL || string == NULL) { +X regerror("NULL parameter"); +X return(0); +X } +X +X /* Check validity of program. */ +X if (UCHARAT(prog->program) != MAGIC) { +X regerror("corrupted program"); +X return(0); +X } +X +X /* (Don't look for "must appear" string -- string can be long.) */ +X +X /* Mark beginning of line for ^ . */ +X regbol = string; +X +X /* Apply offset. +X Assume 0 <= offset <= strlen(string), but don't check, +X as string can be long. */ +X s= string + offset; +X +X /* Anchored match need be tried only at line starts. */ +X if (prog->reganch) { +X while (!regtry(prog, s)) { +X s = strchr(s, '\n'); +X if (s == NULL) +X return(0); +X s++; +X } +X return(1); +X } +X +X /* Messy cases: unanchored match. */ +X if (prog->regstart != '\0') +X /* We know what char it must start with. */ +X while ((s = strchr(s, prog->regstart)) != NULL) { +X if (regtry(prog, s)) +X return(1); +X s++; +X } +X else +X /* We don't -- general case. */ +X do { +X if (regtry(prog, s)) +X return(1); +X } while (*s++ != '\0'); +X +X /* Failure. */ +X return(0); +X} +X#endif +X +X/* +X - regtry - try match at specific point +X */ +Xstatic int /* 0 failure, 1 success */ +Xregtry(prog, string) +Xregexp *prog; +Xchar *string; +X{ +X register int i; +X register char **sp; +X register char **ep; +X +X reginput = string; +X regstartp = prog->startp; +X regendp = prog->endp; +X +X sp = prog->startp; +X ep = prog->endp; +X for (i = NSUBEXP; i > 0; i--) { +X *sp++ = NULL; +X *ep++ = NULL; +X } +X if (regmatch(prog->program + 1)) { +X prog->startp[0] = string; +X prog->endp[0] = reginput; +X return(1); +X } else +X return(0); +X} +X +X/* +X - regmatch - main matching routine +X * +X * Conceptually the strategy is simple: check to see whether the current +X * node matches, call self recursively to see whether the rest matches, +X * and then act accordingly. In practice we make some effort to avoid +X * recursion, in particular by going through "ordinary" nodes (that don't +X * need to know whether the rest of the match failed) by a loop instead of +X * by recursion. +X */ +Xstatic int /* 0 failure, 1 success */ +Xregmatch(prog) +Xchar *prog; +X{ +X register char *scan; /* Current node. */ +X char *next; /* Next node. */ +X extern char *strchr(); +X +X scan = prog; +X#ifdef DEBUG +X if (scan != NULL && regnarrate) +X fprintf(stderr, "%s(\n", regprop(scan)); +X#endif +X while (scan != NULL) { +X#ifdef DEBUG +X if (regnarrate) +X fprintf(stderr, "%s...\n", regprop(scan)); +X#endif +X next = regnext(scan); +X +X switch (OP(scan)) { +X case BOL: +X#ifdef MULTILINE +X if (!(reginput == regbol || +X reginput > regbol && *(reginput-1) == '\n')) +X#else +X if (reginput != regbol) +X#endif +X return(0); +X break; +X case EOL: +X#ifdef MULTILINE +X if (*reginput != '\0' && *reginput != '\n') +X#else +X if (*reginput != '\0') +X#endif +X return(0); +X break; +X case ANY: +X#ifdef MULTILINE +X if (*reginput == '\0' || *reginput == '\n') +X#else +X if (*reginput == '\0') +X#endif +X return(0); +X reginput++; +X break; +X case EXACTLY: { +X register int len; +X register char *opnd; +X +X opnd = OPERAND(scan); +X /* Inline the first character, for speed. */ +X if (*opnd != *reginput) +X return(0); +X len = strlen(opnd); +X if (len > 1 && strncmp(opnd, reginput, len) != 0) +X return(0); +X reginput += len; +X } +X break; +X case ANYOF: +X if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL) +X return(0); +X reginput++; +X break; +X case ANYBUT: +X#ifdef MULTILINE +X if (*reginput == '\0' || *reginput == '\n' || +X strchr(OPERAND(scan), *reginput) != NULL) +X#else +X if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL) +X#endif +X return(0); +X reginput++; +X break; +X case NOTHING: +X break; +X case BACK: +X break; +X case OPEN+1: +X case OPEN+2: +X case OPEN+3: +X case OPEN+4: +X case OPEN+5: +X case OPEN+6: +X case OPEN+7: +X case OPEN+8: +X case OPEN+9: { +X register int no; +X register char *save; +X +X no = OP(scan) - OPEN; +X save = reginput; +X +X if (regmatch(next)) { +X /* +X * Don't set startp if some later +X * invocation of the same parentheses +X * already has. +X */ +X if (regstartp[no] == NULL) +X regstartp[no] = save; +X return(1); +X } else +X return(0); +X } +X break; +X case CLOSE+1: +X case CLOSE+2: +X case CLOSE+3: +X case CLOSE+4: +X case CLOSE+5: +X case CLOSE+6: +X case CLOSE+7: +X case CLOSE+8: +X case CLOSE+9: { +X register int no; +X register char *save; +X +X no = OP(scan) - CLOSE; +X save = reginput; +X +X if (regmatch(next)) { +X /* +X * Don't set endp if some later +X * invocation of the same parentheses +X * already has. +X */ +X if (regendp[no] == NULL) +X regendp[no] = save; +X return(1); +X } else +X return(0); +X } +X break; +X case BRANCH: { +X register char *save; +X +X if (OP(next) != BRANCH) /* No choice. */ +X next = OPERAND(scan); /* Avoid recursion. */ +X else { +X do { +X save = reginput; +X if (regmatch(OPERAND(scan))) +X return(1); +X reginput = save; +X scan = regnext(scan); +X } while (scan != NULL && OP(scan) == BRANCH); +X return(0); +X /* NOTREACHED */ +X } +X } +X break; +X case STAR: +X case PLUS: { +X register char nextch; +X register int no; +X register char *save; +X register int min; +X +X /* +X * Lookahead to avoid useless match attempts +X * when we know what character comes next. +X */ +X nextch = '\0'; +X if (OP(next) == EXACTLY) +X nextch = *OPERAND(next); +X min = (OP(scan) == STAR) ? 0 : 1; +X save = reginput; +X no = regrepeat(OPERAND(scan)); +X while (no >= min) { +X /* If it could work, try it. */ +X if (nextch == '\0' || *reginput == nextch) +X if (regmatch(next)) +X return(1); +X /* Couldn't or didn't -- back up. */ +X no--; +X reginput = save + no; +X } +X return(0); +X } +X break; +X case END: +X return(1); /* Success! */ +X break; +X default: +X regerror("memory corruption"); +X return(0); +X break; +X } +X +X scan = next; +X } +X +X /* +X * We get here only if there's trouble -- normally "case END" is +X * the terminating point. +X */ +X regerror("corrupted pointers"); +X return(0); +X} +X +X/* +X - regrepeat - repeatedly match something simple, report how many +X */ +Xstatic int +Xregrepeat(p) +Xchar *p; +X{ +X register int count = 0; +X register char *scan; +X register char *opnd; +X#ifdef MULTILINE +X register char *eol; +X#endif +X +X scan = reginput; +X opnd = OPERAND(p); +X switch (OP(p)) { +X case ANY: +X#ifdef MULTILINE +X if ((eol = strchr(scan, '\n')) != NULL) { +X count += eol - scan; +X scan = eol; +X break; +X } +X#endif +X count = strlen(scan); +X scan += count; +X break; +X case EXACTLY: +X while (*opnd == *scan) { +X count++; +X scan++; +X } +X break; +X case ANYOF: +X while (*scan != '\0' && strchr(opnd, *scan) != NULL) { +X count++; +X scan++; +X } +X break; +X case ANYBUT: +X#ifdef MULTILINE +X while (*scan != '\0' && *scan != '\n' && +X strchr(opnd, *scan) == NULL) { +X#else +X while (*scan != '\0' && strchr(opnd, *scan) == NULL) { +X#endif +X count++; +X scan++; +X } +X break; +X default: /* Oh dear. Called inappropriately. */ +X regerror("internal foulup"); +X count = 0; /* Best compromise. */ +X break; +X } +X reginput = scan; +X +X return(count); +X} +X +X/* +X - regnext - dig the "next" pointer out of a node +X */ +Xstatic char * +Xregnext(p) +Xregister char *p; +X{ +X register int offset; +X +X if (p == ®dummy) +X return(NULL); +X +X offset = NEXT(p); +X if (offset == 0) +X return(NULL); +X +X if (OP(p) == BACK) +X return(p-offset); +X else +X return(p+offset); +X} +X +X#ifdef DEBUG +X +XSTATIC char *regprop(); +X +X/* +X - regdump - dump a regexp onto stdout in vaguely comprehensible form +X */ +Xvoid +Xregdump(r) +Xregexp *r; +X{ +X register char *s; +X register char op = EXACTLY; /* Arbitrary non-END op. */ +X register char *next; +X extern char *strchr(); +X +X +X s = r->program + 1; +X while (op != END) { /* While that wasn't END last time... */ +X op = OP(s); +X printf("%2d%s", (int)(s-r->program), regprop(s)); /* Where, what. */ +X next = regnext(s); +X if (next == NULL) /* Next ptr. */ +X printf("(0)"); +X else +X printf("(%d)", (int)((s-r->program)+(next-s))); +X s += 3; +X if (op == ANYOF || op == ANYBUT || op == EXACTLY) { +X /* Literal string, where present. */ +X while (*s != '\0') { +X#ifdef MULTILINE +X if (*s == '\n') +X printf("\\n"); +X else +X#endif +X putchar(*s); +X s++; +X } +X s++; +X } +X putchar('\n'); +X } +X +X /* Header fields of interest. */ +X if (r->regstart != '\0') +X printf("start `%c' ", r->regstart); +X if (r->reganch) +X printf("anchored "); +X if (r->regmust != NULL) +X printf("must have \"%s\"", r->regmust); +X printf("\n"); +X} +X +X/* +X - regprop - printable representation of opcode +X */ +Xstatic char * +Xregprop(op) +Xchar *op; +X{ +X register char *p; +X static char buf[50]; +X +X (void) strcpy(buf, ":"); +X +X switch (OP(op)) { +X case BOL: +X p = "BOL"; +X break; +X case EOL: +X p = "EOL"; +X break; +X case ANY: +X p = "ANY"; +X break; +X case ANYOF: +X p = "ANYOF"; +X break; +X case ANYBUT: +X p = "ANYBUT"; +X break; +X case BRANCH: +X p = "BRANCH"; +X break; +X case EXACTLY: +X p = "EXACTLY"; +X break; +X case NOTHING: +X p = "NOTHING"; +X break; +X case BACK: +X p = "BACK"; +X break; +X case END: +X p = "END"; +X break; +X case OPEN+1: +X case OPEN+2: +X case OPEN+3: +X case OPEN+4: +X case OPEN+5: +X case OPEN+6: +X case OPEN+7: +X case OPEN+8: +X case OPEN+9: +X sprintf(buf+strlen(buf), "OPEN%d", (int)(OP(op)-OPEN)); +X p = NULL; +X break; +X case CLOSE+1: +X case CLOSE+2: +X case CLOSE+3: +X case CLOSE+4: +X case CLOSE+5: +X case CLOSE+6: +X case CLOSE+7: +X case CLOSE+8: +X case CLOSE+9: +X sprintf(buf+strlen(buf), "CLOSE%d", (int)(OP(op)-CLOSE)); +X p = NULL; +X break; +X case STAR: +X p = "STAR"; +X break; +X case PLUS: +X p = "PLUS"; +X break; +X default: +X regerror("corrupted opcode"); +X break; +X } +X if (p != NULL) +X (void) strcat(buf, p); +X return(buf); +X} +X#endif +X +X/* +X * The following is provided for those people who do not have strcspn() in +X * their C libraries. They should get off their butts and do something +X * about it; at least one public-domain implementation of those (highly +X * useful) string routines has been published on Usenet. +X */ +X#ifdef STRCSPN +X/* +X * strcspn - find length of initial segment of s1 consisting entirely +X * of characters not from s2 +X */ +X +Xstatic int +Xstrcspn(s1, s2) +Xchar *s1; +Xchar *s2; +X{ +X register char *scan1; +X register char *scan2; +X register int count; +X +X count = 0; +X for (scan1 = s1; *scan1 != '\0'; scan1++) { +X for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */ +X if (*scan1 == *scan2++) +X return(count); +X count++; +X } +X return(count); +X} +X#endif +EOF +fi +echo 'Part 05 out of 21 of pack.out complete.' +exit 0 diff --git a/shar/python-0.9.1-06-21.shar b/shar/python-0.9.1-06-21.shar new file mode 100644 index 0000000..2d2194b --- /dev/null +++ b/shar/python-0.9.1-06-21.shar @@ -0,0 +1,2510 @@ +: This is a shell archive. +: Extract with 'sh this_file'. +: +: Extract part 01 first since it makes all directories +echo 'Start of pack.out, part 06 out of 21:' +if test -s 'doc/Makefile' +then echo '*** I will not over-write existing file doc/Makefile' +else +echo 'x - doc/Makefile' +sed 's/^X//' > 'doc/Makefile' << 'EOF' +X# Makefile for Python documentation. +X +XLATEX= latex +XDVIPS= dvips +XTEXPREVIEW= xdvi +X +XPRINT= lpr +X +Xtut: tut.dvi +X $(TEXPREVIEW) tut +X +Xtut.dvi tut.ps: tut.toc tut.tex myformat.sty +X +Xmod: mod.dvi +X $(TEXPREVIEW) mod +X +Xmod.dvi mod.ps: mod.toc mod.tex mod1.tex mod2.tex mod3.tex myformat.sty +X +XALL= tut.ps mod.ps +X +Xall: $(ALL) +X +Xprint: $(ALL) +X $(PRINT) $(ALL) +X +Xclean: +X rm -f *.dvi *.aux *.toc *.log *.ps core [#@,]* *~ +X +X.SUFFIXES: # Remove default suffixes +X +X.SUFFIXES: .tex .aux .toc .dvi .ps +X +X.tex.aux: +X $(LATEX) $* +X +X.tex.toc: +X $(LATEX) $* +X +X.tex.dvi: +X $(LATEX) $* +X +X.dvi.ps: +X $(DVIPS) $* >$*.ps +X +X.tex.ps: +X $(LATEX) $* +X $(DVIPS) $* >$*.ps +EOF +fi +if test -s 'doc/mod2.tex' +then echo '*** I will not over-write existing file doc/mod2.tex' +else +echo 'x - doc/mod2.tex' +sed 's/^X//' > 'doc/mod2.tex' << 'EOF' +X\section{Built-in Modules} +X +XThe modules described in this section are built into the interpreter. +XThey must be imported using +X{\tt import}. +XSome modules are not always available; it is a configuration option to +Xprovide them. +XDetails are listed with the descriptions, but the best way to see if +Xa module exists in a particular implementation is to attempt to import +Xit. +X +X\subsection{Built-in Module {\tt sys}} +X +XThis module provides access to some variables used or maintained by the +Xinterpreter and to functions that interact strongly with the interpreter. +XIt is always available. +X\begin{description} +X\funcitem{argv} +XThe list of command line arguments passed to a {\Python} script. +X{\tt sys.argv[0]} +Xis the script name. +XIf no script name was passed to the {\Python} interpreter, +X{\tt sys.argv} +Xis empty. +X\funcitem{exit}{n} +XExits from {\Python} with numeric exit status +X{\tt n}. +XThis closes all open files and performs other cleanup-actions required by +Xthe interpreter (but +X{\em finally clauses} +Xof +X{\tt try} +Xstatements are not executed!). +X\funcitem{modules} +XGives the list of modules that have already been loaded. +XThis can be manipulated to force reloading of modules and other tricks. +X\funcitem{path} +XA list of strings that specifies the search path for modules. +XInitialized from the environment variable {\tt PYTHONPATH}, or an +Xinstallation-dependent default. +X\funcitem{ps1,~ps2} +XStrings specifying the primary and secondary prompt of the interpreter. +XThese are only defined if the interpreter is in interactive mode. +XTheir initial values in this case are +X{\tt '>>> '} +Xand +X{\tt '... '}. +X\funcitem{stdin, stdout, stderr} +X%.br +XFile objects corresponding to the interpreter's standard input, output +Xand error streams. +X{\tt sys.stdin} +Xis used for all interpreter input except for scripts but including calls +Xto +X{\tt input()} +Xand +X{\tt raw\_input()}. +X{\tt sys.stdout} +Xis used for the output of +X{\tt print} and expression statements +Xand for the prompts of +X{\tt input()} +Xand +X{\tt raw\_input()}. +XThe interpreter's own prompts and its error messages are written to +Xstderr. +XAssigning to +X{\tt sys.stderr} +Xhas no effect on the interpreter; it can be used to write error messages +Xto stderr using +X{\tt print}. +X\end{description} +X +X\subsection{Built-in Module {\tt math}} +X +XThis module is always available. +XIt provides access to the mathematical functions defined by the C +Xstandard. +XThey are: +X{\tt acos(x)}, +X{\tt asin(x)}, +X{\tt atan(x)}, +X{\tt atan2(x,y)}, +X{\tt ceil(x)}, +X{\tt cos(x)}, +X{\tt cosh(x)}, +X{\tt exp(x)}, +X{\tt fabs(x)}, +X{\tt floor(x)}, +X%{\tt fmod(...)} XXX not yet +X%{\tt frexp(...)} XXX not yet +X%{\tt ldexp(...)} XXX not yet +X{\tt log(x)}, +X{\tt log10(x)}, +X%{\tt modf(...)} XXX not yet +X{\tt pow(x,y)}, +X{\tt sin(x)}, +X{\tt sinh(x)}, +X{\tt sqrt(x)}, +X{\tt tan(x)}, +X{\tt tanh(x)}. +X +XIt also defines two mathematical constants: +X{\tt pi} +Xand +X{\tt e}. +X +X\subsection{Built-in Module {\tt time}} +X +XThis module provides various time-related functions. +XIt is always available. +XFunctions are: +X\begin{description} +X\funcitem{sleep}{secs} +XSuspends execution for the given number of seconds. +X\funcitem{time}{} +XReturns the time in seconds since the Epoch (Thursday January 1, +X00:00:00, 1970 UCT on \UNIX\ machines). +X\end{description} +X +X\noindent +XIn some versions (Amoeba, Mac) the following functions also exist: +X\begin{description} +X\funcitem{millisleep}{msecs} +XSuspends execution for the given number of milliseconds. +X\funcitem{millitimer}{} +XReturns the number of milliseconds of real time elapsed since some point +Xin the past that is fixed per execution of the python interpreter (but +Xmay change in each following run). +X\end{description} +X +X\noindent +XThe granularity of the milliseconds functions may be more than a +Xmillisecond (100 msecs on Amoeba, 1/60 sec on the Mac). +X +X\subsection{Built-in Module {\tt regexp}} +X +XThis module provides a regular expression matching operation. +XIt is always available. +X +XThe module defines a function and an exception: +X +X\begin{description} +X +X\funcitem{compile}{pattern} +X +XCompile a regular expression given as a string into a regular +Xexpression object. +XThe string must be an egrep-style regular expression; +Xthis means that the characters +X{\tt '(' ')' '*' '+' '?'\ '|' }\verb='^' '$'= +Xare special. +X(It is implemented using Henry Spencer's regular expression matching +Xfunctions.) +X +Xexcitem{error}{regexp.error} +X +XException raised when a string passed to {\tt compile()} is not a +Xvalid regular expression (e.g., unmatched parentheses) or when some other +Xerror occurs during compilation or matching +X(``no match found'' is not an error). +X +X\end{description} +X +XCompiled regular expression objects support a single method: +X +X\begin{description} +X +X\funcitem{exec}{str} +X +XFind the first occurrence of the compiled regular expression in the +Xstring {\tt str}. +XThe return value is a tuple of pairs specifying where a match was +Xfound and where matches were found for subpatterns specified with +X{\tt '('} and {\tt ')'} in the pattern. +XIf no match is found, an empty tuple is returned; otherwise the first +Xitem of the tuple is a pair of slice indices into the search string +Xgiving the match found. +XIf there were any subpatterns in the pattern, the returned tuple has an +Xadditional item for each subpattern, giving the slice indices into the +Xsearch string where that subpattern was found. +X +X\end{description} +X +XFor example: +X\bcode\begin{verbatim} +X>>> import regexp +X>>> r = regexp.compile('--(.*)--') +X>>> s = 'a--b--c' +X>>> r.exec(s) +X((1, 6), (3, 4)) +X>>> s[1:6] # The entire match +X'--b--' +X>>> s[3:4] # The subpattern +X'b' +X>>> +X\end{verbatim}\ecode +X +X\subsection{Built-in Module {\tt posix}} +X +XThis module provides access to operating system functionality that is +Xstandardized by the C Standard and the POSIX standard (a thinly diguised +X{\UNIX} interface). +XIt is available in all {\Python} versions except on the Macintosh. +XErrors are reported exceptions. +XIt defines the following items: +X\begin{description} +X\funcitem{chdir}{path} +XChanges the current directory to +X{\tt path}. +X\funcitem{chmod}{path, mode} +XChange the mode of +X{\tt path} +Xto the numeric +X{\tt mode}. +X\funcitem{environ} +XA dictionary representing the string environment at the time +Xthe interpreter was started. +X(Modifying this dictionary does not affect the string environment of the +Xinterpreter.) +XFor example, +X{\tt posix.environ['HOME']} +Xis the pathname of your home directory, equivalent to +X{\tt getenv("HOME")} +Xin C. +X\excitem{error}{posix.error} +X%.br +XThe exception raised when an POSIX function returns an error. +XThe value accompanying this exception is a pair containing the numeric +Xerror code from +X{\tt errno} +Xand the corresponding string, as would be printed by the C function +X{\tt perror()}. +X\funcitem{getcwd}{} +XReturns a string representing the current working directory. +X\funcitem{link}{src, dst} +XCreates a hard link pointing to +X{\tt src} +Xnamed +X{\tt dst}. +X\funcitem{listdir}{path} +XReturns a list containing the names of the entries in the +Xdirectory. +XThe list is in arbitrary order. +XIt includes the special entries +X{\tt '.'} +Xand +X{\tt '..'} +Xif they are present in the directory. +X\funcitem{mkdir}{path, mode} +XCreates a directory named +X{\tt path} +Xwith numeric mode +X{\tt mode}. +X\funcitem{rename}{src, dst} +XRenames the file or directory +X{\tt src} +Xto +X{\tt dst}. +X\funcitem{rmdir}{path} +XRemoves the directory +X{\tt path}. +X\funcitem{stat}{path} +XPerforms a +X{\em stat} +Xsystem call on the given path. +XThe return value is a tuple of at least 10 integers giving the most +Ximportant (and portable) members of the +X{\em stat} +Xstructure, in the order +X{\tt st\_mode}, +X{\tt st\_ino}, +X{\tt st\_dev}, +X{\tt st\_nlink}, +X{\tt st\_uid}, +X{\tt st\_gid}, +X{\tt st\_size}, +X{\tt st\_atime}, +X{\tt st\_mtime}, +X{\tt st\_ctime}. +XMore items may be added at the end by some implementations. +X\funcitem{system}{command} +XExecutes the command (a string) in a subshell. +XThis is implemented by calling the Standard C function +X{\tt system()}, +Xand has the same limitations. +XChanges to +X{\tt posix.environ}, +X{\tt sys.stdin} +Xetc. are not reflected in the environment of the executed command. +XThe return value is the exit status of the process as returned by +XStandard C +X{\tt system()}. +X\funcitem{umask}{mask} +XSets the current numeric umask and returns the previous umask. +X\funcitem{unlink}{path} +XUnlinks the file +X{\tt path}. +X\funcitem{utimes(path, }{atime, mtime)} +X%.br +XSets the access and modified time of the file to the given values. +X(The second argument is a tuple of two items.) +X\end{description} +X +XThe following functions are only available on systems that support +Xsymbolic links: +X\begin{description} +X\funcitem{lstat}{path} +XLike +X{\tt stat()}, +Xbut does not follow symbolic links. +X\funcitem{readlink}{path} +XReturns a string representing the path to which the symbolic link +Xpoints. +X\funcitem{symlink}{src, dst} +XCreates a symbolic link pointing to +X{\tt src} +Xnamed +X{\tt dst}. +X\end{description} +X +X\subsection{Built-in Module {\tt stdwin}} +X +XThis module defines several new object types and functions that +Xprovide access to the functionality of the Standard Window System +XInterface, STDWIN [CWI report CR-R8817]. +XIt is available on systems to which STDWIN has been ported (which is +Xmost systems). +XIt is only available if the {\tt DISPLAY} environment variable is set +Xor an explicit `{\tt -display \it displayname}' argument is passed to +Xthe interpreter. +X +XFunctions have names that usually resemble their C STDWIN counterparts +Xwith the initial `w' dropped. +XPoints are represented by pairs of integers; rectangles +Xby pairs of points. +XFor a complete description of STDWIN please refer to the documentation +Xof STDWIN for C programmers (aforementioned CWI report). +X\subsubsection{Functions Defined in Module {\tt stdwin}} +X +XThe following functions are defined in the {\tt stdwin} module: +X\begin{description} +X\funcitem{open}{title} +X%.br +XOpens a new window whose initial title is given by the string argument. +XReturns a window object; window object methods are described below.% +X\footnote{ +XThe {\Python} version of STDWIN does not support draw procedures; all +Xdrawing requests are reported as draw events. +X} +X\funcitem{getevent}{} +X%.br +XWaits for and returns the next event. +XAn event is returned as a triple: the first element is the event +Xtype, a small integer; the second element is the window object to which +Xthe event applies, or +X{\tt None} +Xif it applies to no window in particular; +Xthe third element is type-dependent. +XNames for event types and command codes are defined in the standard +Xmodule +X{\tt stdwinevent}. +X\funcitem{setdefwinpos}{h, v} +X%.br +XSets the default window position. +X\funcitem{setdefwinsize}{width, height} +X%.br +XSets the default window size. +X\funcitem{menucreate}{title} +X%.br +XCreates a menu object referring to a global menu (a menu that appears in +Xall windows). +XMethods of menu objects are described below. +X\funcitem{fleep}{} +X%.br +XCauses a beep or bell (or perhaps a `visual bell' or flash, hence the +Xname). +X\funcitem{message}{string} +X%.br +XDisplays a dialog box containing the string. +XThe user must click OK before the function returns. +X\funcitem{askync}{prompt, default} +X%.br +XDisplays a dialog that prompts the user to answer a question with yes or +Xno. +XThe function returns 0 for no, 1 for yes. +XIf the user hits the Return key, the default (which must be 0 or 1) is +Xreturned. +XIf the user cancels the dialog, the +X{\tt KeyboardInterrupt} +Xexception is raised. +X\funcitem{askstr}{prompt, default} +X%.br +XDisplays a dialog that prompts the user for a string. +XIf the user hits the Return key, the default string is returned. +XIf the user cancels the dialog, the +X{\tt KeyboardInterrupt} +Xexception is raised. +X\funcitem{askfile}{prompt, default, new} +X%.br +XAsks the user to specify a filename. +XIf +X{\tt new} +Xis zero it must be an existing file; otherwise, it must be a new file. +XIf the user cancels the dialog, the +X{\tt KeyboardInterrupt} +Xexception is raised. +X\funcitem{setcutbuffer}{i, string} +X%.br +XStores the string in the system's cut buffer number +X{\tt i}, +Xwhere it can be found (for pasting) by other applications. +XOn X11, there are 8 cut buffers (numbered 0..7). +XCut buffer number 0 is the `clipboard' on the Macintosh. +X\funcitem{getcutbuffer}{i} +X%.br +XReturns the contents of the system's cut buffer number +X{\tt i}. +X\funcitem{rotatebutbuffers}{n} +X%.br +XOn X11, this rotates the 8 cut buffers by +X{\tt n}. +XIgnored on the Macintosh. +X\funcitem{getselection}{i} +X%.br +XReturns X11 selection number +X{\tt i.} +XSelections are not cut buffers. +XSelection numbers are defined in module +X{\tt stdwinevents}. +XSelection {\tt WS\_PRIMARY} is the +X{\em primary} +Xselection (used by +Xxterm, +Xfor instance); +Xselection {\tt WS\_SECONDARY} is the +X{\em secondary} +Xselection; selection {\tt WS\_CLIPBOARD} is the +X{\em clipboard} +Xselection (used by +Xxclipboard). +XOn the Macintosh, this always returns an empty string. +X\funcitem{resetselection}{i} +X%.br +XResets selection number +X{\tt i}, +Xif this process owns it. +X(See window method +X{\tt setselection()}). +X\funcitem{baseline}{} +X%.br +XReturn the baseline of the current font (defined by STDWIN as the +Xvertical distance between the baseline and the top of the +Xcharacters).% +X\footnote{ +XThere is no way yet to set the current font. +XThis will change in a future version. +X} +X\funcitem{lineheight}{} +X%.br +XReturn the total line height of the current font. +X\funcitem{textbreak}{str, width} +X%.br +XReturn the number of characters of the string that fit into a space of +X{\tt width} +Xbits wide when drawn in the curent font. +X\funcitem{textwidth}{str} +X%.br +XReturn the width in bits of the string when drawn in the current font. +X\end{description} +X +X\subsubsection{Window Object Methods} +X +XWindow objects are created by +X{\tt stdwin.open()}. +XThere is no explicit function to close a window; windows are closed when +Xthey are garbage-collected. +XWindow objects have the following methods: +X\begin{description} +X\funcitem{begindrawing}{} +XReturns a drawing object, whose methods (described below) allow drawing +Xin the window. +X\funcitem{change}{rect} +XInvalidates the given rectangle; this may cause a draw event. +X\funcitem{gettitle}{} +XReturns the window's title string. +X\funcitem{getdocsize}{} +X\begin{sloppypar} +XReturns a pair of integers giving the size of the document as set by +X{\tt setdocsize()}. +X\end{sloppypar} +X\funcitem{getorigin}{} +XReturns a pair of integers giving the origin of the window with respect +Xto the document. +X\funcitem{getwinsize}{} +XReturns a pair of integers giving the size of the window. +X\funcitem{menucreate}{title} +XCreates a menu object referring to a local menu (a menu that appears +Xonly in this window). +XMethods menu objects are described below. +X\funcitem{scroll}{rect,~point} +XScrolls the given rectangle by the vector given by the point. +X\funcitem{setwincursor}{name} +X\begin{sloppypar} +XSets the window cursor to a cursor of the given name. +XIt raises the +X{\tt Runtime\-Error} +Xexception if no cursor of the given name exists. +XSuitable names are +X{\tt 'ibeam'}, +X{\tt 'arrow'}, +X{\tt 'cross'}, +X{\tt 'watch'} +Xand +X{\tt 'plus'}. +XOn X11, there are many more (see +X{\tt <X11/cursorfont.h>}). +X\end{sloppypar} +X\funcitem{setdocsize}{point} +XSets the size of the drawing document. +X\funcitem{setorigin}{point} +XMoves the origin of the window to the given point in the document. +X\funcitem{setselection}{i, str} +XAttempts to set X11 selection number +X{\tt i} +Xto the string +X{\tt str}. +X(See stdwin method +X{\tt getselection()} +Xfor the meaning of +X{\tt i}.) +XReturns true if it succeeds. +XIf it succeeds, the window ``owns'' the selection until +X(a) another applications takes ownership of the selection; or +X(b) the window is deleted; or +X(c) the application clears ownership by calling +X{\tt stdwin.resetselection(i)}. +XWhen another application takes ownership of the selection, a +X{\tt WE\_LOST\_SEL} +Xevent is received for no particular window and with the selection number +Xas detail. +XIgnored on the Macintosh. +X\funcitem{settitle}{title} +XSets the window's title string. +X\funcitem{settimer}{dsecs} +XSchedules a timer event for the window in +X{\tt dsecs/10} +Xseconds. +X\funcitem{show}{rect} +XTries to ensure that the given rectangle of the document is visible in +Xthe window. +X\funcitem{textcreate}{rect} +XCreates a text-edit object in the document at the given rectangle. +XMethods of text-edit objects are described below. +X\end{description} +X +X\subsubsection{Drawing Object Methods} +X +XDrawing objects are created exclusively by the window method +X{\tt begindrawing()}. +XOnly one drawing object can exist at any given time; the drawing object +Xmust be deleted to finish drawing. +XNo drawing object may exist when +X{\tt stdwin.getevent()} +Xis called. +XDrawing objects have the following methods: +X\begin{description} +X\funcitem{box}{rect} +XDraws a box around a rectangle. +X\funcitem{circle}{center, radius} +X%.br +XDraws a circle with given center point and radius. +X\funcitem{elarc(center, (rh, rv), }{a1, a2)} +X%.br +XDraws an elliptical arc with given center point. +X{\tt (rh, rv)} +Xgives the half sizes of the horizontal and vertical radii. +X{\tt (a1, a2)} +Xgives the angles (in degrees) of the begin and end points. +X0 degrees is at 3 o'clock, 90 degrees is at 12 o'clock. +X\funcitem{erase}{rect} +XErases a rectangle. +X\funcitem{invert}{rect} +XInverts a rectangle. +X\funcitem{line}{p1, p2} +XDraws a line from point +X{\tt p1} +Xto +X{\tt p2}. +X\funcitem{paint}{rect} +XFills a rectangle. +X\funcitem{text}{p, str} +XDraws a string starting at point p (the point specifies the +Xtop left coordinate of the string). +X\funcitem{shade}{rect, percent} +X%.br +XFills a rectangle with a shading pattern that is about +X{\tt percent} +Xpercent filled. +X\funcitem{xorline}{p1, p2} +XDraws a line in XOR mode. +X\funcitem{baseline(), lineheight(), textbreak(), textwidth}{} +X%.br +XThese functions are similar to the corresponding functions described +Xabove for the +X{\tt stdwin} +Xmodule, but use the current font of the window instead of the (global) +Xdefault font. +X\end{description} +X +X\subsubsection{Menu Object Methods} +X +XA menu object represents a menu. +XThe menu is destroyed when the menu object is deleted. +XThe following methods are defined: +X\begin{description} +X\funcitem{additem}{text, shortcut} +X%.br +XAdds a menu item with given text. +XThe shortcut must be a string of length 1, or omitted (to specify no +Xshortcut). +X\funcitem{setitem}{i, text} +XSets the text of item number +X{\tt i}. +X\funcitem{enable}{i, flag} +XEnables or disables item +X{\tt i}. +X\funcitem{check}{i, flag} +XSets or clears the +X{\em check mark} +Xfor item +X{\tt i}. +X\end{description} +X +X\subsubsection{Text-edit Object Methods} +X +XA text-edit object represents a text-edit block. +XFor semantics, see the STDWIN documentation for C programmers. +XThe following methods exist: +X\begin{description} +X\funcitem{arrow}{code} +XPasses an arrow event to the text-edit block. +XThe +X{\tt code} +Xmust be one of +X{\tt WC\_LEFT}, +X{\tt WC\_RIGHT}, +X{\tt WC\_UP} +Xor +X{\tt WC\_DOWN} +X(see module +X{\tt stdwinevents}). +X\funcitem{draw}{rect} +XPasses a draw event to the text-edit block. +XThe rectangle specifies the redraw area. +X\funcitem{event}{type, window, detail} +X%.br +XPasses an event gotten from +X{\tt stdwin.getevent()} +Xto the text-edit block. +XReturns true if the event was handled. +X\funcitem{getfocus}{} +XReturns 2 integers representing the start and end positions of the +Xfocus, usable as slice indices on the string returned by +X{\tt getfocustext()}. +X\funcitem{getfocustext}{} +XReturns the text in the focus. +X\funcitem{getrect}{} +XReturns a rectangle giving the actual position of the text-edit block. +X(The bottom coordinate may differ from the initial position because +Xthe block automatically shrinks or grows to fit.) +X\funcitem{gettext}{} +XReturns the entire text buffer. +X\funcitem{move}{rect} +XSpecifies a new position for the text-edit block in the document. +X\funcitem{replace}{str} +XReplaces the focus by the given string. +XThe new focus is an insert point at the end of the string. +X\funcitem{setfocus}{i,~j} +XSpecifies the new focus. +XOut-of-bounds values are silently clipped. +X\end{description} +X +X\subsubsection{Example} +X +XHere is a simple example of using STDWIN in Python. +XIt creates a window and draws the string ``Hello world'' in the top +Xleft corner of the window. +XThe window will be correctly redrawn when covered and re-exposed. +XThe program quits when the close icon or menu item is requested. +X\bcode\begin{verbatim} +Ximport stdwin +Xfrom stdwinevents import * +X +Xdef main(): +X mywin = stdwin.open('Hello') +X # +X while 1: +X (type, win, detail) = stdwin.getevent() +X if type = WE_DRAW: +X draw = win.begindrawing() +X draw.text((0, 0), 'Hello, world') +X del draw +X elif type = WE_CLOSE: +X break +X +Xmain() +X\end{verbatim}\ecode +X +X\subsection{Built-in Module {\tt amoeba}} +X +XThis module provides some object types and operations useful for +XAmoeba applications. +XIt is only available on systems that support Amoeba operations. +XRPC errors and other Amoeba errors are reported as the exception +X{\tt amoeba.error = 'amoeba.error'}. +XThe module +X{\tt amoeba} +Xdefines the following items: +X\begin{description} +X\funcitem{name\_append}{path,~cap} +X%.br +XStores a capability in the Amoeba directory tree. +XArguments are the pathname (a string) and the capability (a capability +Xobject as returned by +X{\tt name\_lookup()}). +X\funcitem{name\_delete}{path} +X%.br +XDeletes a capability from the Amoeba directory tree. +XArgument is the pathname. +X\funcitem{name\_lookup}{path} +X%.br +XLooks up a capability. +XArgument is the pathname. +XReturns a +X{\em capability} +Xobject, to which various interesting operations apply, described below. +X\funcitem{name\_replace}{path,~cap} +X%.br +XReplaces a capability in the Amoeba directory tree. +XArguments are the pathname and the new capability. +X(This differs from +X{\tt name\_append()} +Xin the behavior when the pathname already exists: +X{\tt name\_append()} +Xfinds this an error while +X{\tt name\_replace()} +Xallows it, as its name suggests.) +X\funcitem{capv} +XA table representing the capability environment at the time the +Xinterpreter was started. +X(Alas, modifying this table does not affect the capability environment +Xof the interpreter.) +XFor example, +X{\tt amoeba.capv['ROOT']} +Xis the capability of your root directory, similar to +X{\tt getcap("ROOT")} +Xin C. +X\excitem{error}{amoeba.error} +X%.br +XThe exception raised when an Amoeba function returns an error. +XThe value accompanying this exception is a pair containing the numeric +Xerror code and the corresponding string, as returned by the C function +X{\tt err\_why()}. +X\funcitem{timeout}{msecs} +X%.br +XSets the transaction timeout, in milliseconds. +XReturns the previous timeout. +XInitially, the timeout is set to 2 seconds by the {\Python} interpreter. +X\end{description} +X +X\subsubsection{Capability Operations} +X +XCapabilities are written in a convenient ASCII format, also used by the +XAmoeba utilities +X{\em c2a}(U) +Xand +X{\em a2c}(U). +XFor example: +X\bcode\begin{verbatim} +X>>> amoeba.name_lookup('/profile/cap') +Xaa:1c:95:52:6a:fa/14(ff)/8e:ba:5b:8:11:1a +X>>> +X\end{verbatim}\ecode +XThe following methods are defined for capability objects. +X\begin{description} +X\funcitem{dir\_list}{} +XReturns a list of the names of the entries in an Amoeba directory. +X\funcitem{b\_read}{offset, maxsize} +X%.br +XReads (at most) +X{\tt maxsize} +Xbytes from a bullet file at offset +X{\tt offset.} +XThe data is returned as a string. +XEOF is reported as an empty string. +X\funcitem{b\_size}{} +XReturns the size of a bullet file. +X\funcitem{dir\_append(), dir\_delete(), dir\_lookup(), dir\_replace}{} +X%.br +X\itembreak +XLike the corresponding +X{\tt name\_*} +Xfunctions, but with a path relative to the capability. +X(For paths beginning with a slash the capability is ignored, since this +Xis the defined semantics for Amoeba.) +X\funcitem{std\_info}{} +XReturns the standard info string of the object. +X\funcitem{tod\_gettime}{} +XReturns the time (in seconds since the Epoch, in UCT, as for POSIX) from +Xa time server. +X\funcitem{tod\_settime}{t} +XSets the time kept by a time server. +X\end{description} +X +X\subsection{Built-in Module {\tt audio}} +X +XThis module provides rudimentary access to the audio I/O device +X{\tt /dev/audio} +Xon the Silicon Graphics Personal IRIS; see audio(7). +XIt supports the following operations: +X\begin{description} +X\funcitem{setoutgain}{n} +XSets the output gain (0-255). +X\funcitem{getoutgain}{} +XReturns the output gain. +X\funcitem{setrate}{n} +XSets the sampling rate: 1=32K/sec, 2=16K/sec, 3=8K/sec. +X\funcitem{setduration}{n} +XSets the `sound duration' in units of 1/100 seconds. +X\funcitem{read}{n} +XReads a chunk of +X{\tt n} +Xsampled bytes from the audio input (line in or microphone). +XThe chunk is returned as a string of length n. +XEach byte encodes one sample as a signed 8-bit quantity using linear +Xencoding. +XThis string can be converted to numbers using {\tt chr2num()} described +Xbelow. +X\funcitem{write}{buf} +XWrites a chunk of samples to the audio output (speaker). +X\end{description} +X +XThese operations support asynchronous audio I/O: +X\begin{description} +X\funcitem{start\_recording}{n} +X%.br +XStarts a second thread (a process with shared memory) that begins reading +X{\tt n} +Xbytes from the audio device. +XThe main thread immediately continues. +X\funcitem{wait\_recording}{} +X%.br +XWaits for the second thread to finish and returns the data read. +X\funcitem{stop\_recording}{} +X%.br +XMakes the second thread stop reading as soon as possible. +XReturns the data read so far. +X\funcitem{poll\_recording}{} +X%.br +XReturns true if the second thread has finished reading (so +X{\tt wait\_recording()} would return the data without delay). +X\item[{\tt start\_playing(chunk)}, {\tt wait\_playing()}, +X{\tt stop\_playing()}, {\tt poll\_playing()}] +X%.br +X\begin{sloppypar} +XSimilar but for output. +X{\tt stop\_playing()} +Xreturns a lower bound for the number of bytes actually played (not very +Xaccurate). +X\end{sloppypar} +X\end{description} +X +XThe following operations do not affect the audio device but are +Ximplemented in C for efficiency: +X\begin{description} +X\funcitem{amplify}{buf, f1, f2} +X%.br +XAmplifies a chunk of samples by a variable factor changing from +X{\tt f1}/256 to {\tt f2}/256. +XNegative factors are allowed. +XResulting values that are to large to fit in a byte are clipped. +X\funcitem{reverse}{buf} +X%.br +XReturns a chunk of samples backwards. +X\funcitem{add}{buf1, buf2} +X%.br +XBytewise adds two chunks of samples. +XBytes that exceed the range are clipped. +XIf one buffer shorter, it is assumed to be padded with zeros. +X\funcitem{chr2num}{buf} +X%.br +XConverts a string of sampled bytes as returned by {\tt read()} into +Xa list containing the numeric values of the samples. +X\funcitem{num2chr}{list} +X%.br +X\begin{sloppypar} +XConverts a list as returned by +X{\tt chr2num()} +Xback to a buffer acceptable by +X{\tt write()}. +X\end{sloppypar} +X\end{description} +X +X\subsection{Built-in Module {\tt gl}} +X +XThis module provides access to the Silicon Graphics +X{\em Graphics Library}. +XIt is available only on Silicon Graphics machines. +X +X{\bf Warning:} +XSome illegal calls to the GL library cause the {\Python} interpreter to dump +Xcore. +XIn particular, the use of most GL calls is unsafe before the first +Xwindow is opened. +X +XThe module is too large to document here in its entirety, but the +Xfollowing should help you to get started. +XThe parameter conventions for the C functions are translated to {\Python} as +Xfollows: +X +X\begin{itemize} +X\item +XAll (short, long, unsigned) int values are represented by {\Python} +Xintegers. +X\item +XAll float and double values are represented by {\Python} floating point +Xnumbers. +XIn most cases, {\Python} integers are also allowed. +X\item +XAll arrays are represented by one-dimensional {\Python} lists. +XIn most cases, tuples are also allowed. +X\item +X\begin{sloppypar} +XAll string and character arguments are represented by {\Python} strings, +Xfor instance, +X{\tt winopen('Hi~There!')} +Xand +X{\tt rotate(900,~'z')}. +X\end{sloppypar} +X\item +XAll (short, long, unsigned) integer arguments or return values that are +Xonly used to specify the length of an array argument are omitted. +XFor example, the C call +X\bcode\begin{verbatim} +Xlmdef(deftype, index, np, props) +X\end{verbatim}\ecode +Xis translated to {\Python} as +X\bcode\begin{verbatim} +Xlmdef(deftype, index, props) +X\end{verbatim}\ecode +X\item +XOutput arguments are omitted from the argument list; they are +Xtransmitted as function return values instead. +XIf more than one value must be returned, the return value is a tuple. +XIf the C function has both a regular return value (that is not omitted +Xbecause of the previous rule) and an output argument, the return value +Xcomes first in the tuple. +XExamples: the C call +X\bcode\begin{verbatim} +Xgetmcolor(i, &red, &green, &blue) +X\end{verbatim}\ecode +Xis translated to {\Python} as +X\bcode\begin{verbatim} +Xred, green, blue = getmcolor(i) +X\end{verbatim}\ecode +X\end{itemize} +X +XThe following functions are non-standard or have special argument +Xconventions: +X\begin{description} +X\funcitem{varray}{} +XEquivalent to but faster than a number of +X{\tt v3d()} +Xcalls. +XThe argument is a list (or tuple) of points. +XEach point must be a tuple of coordinates (x, y, z) or (x, y). +XThe points may be 2- or 3-dimensional but must all have the +Xsame dimension. +XFloat and int values may be mixed however. +XThe points are always converted to 3D double precision points +Xby assuming z=0.0 if necessary (as indicated in the man page), +Xand for each point +X{\tt v3d()} +Xis called. +X\funcitem{nvarray}{} +XEquivalent to but faster than a number of +X{\tt n3f} +Xand +X{\tt v3f} +Xcalls. +XThe argument is an array (list or tuple) of pairs of normals and points. +XEach pair is a tuple of a point and a normal for that point. +XEach point or normal must be a tuple of coordinates (x, y, z). +XThree coordinates must be given. +XFloat and int values may be mixed. +XFor each pair, +X{\tt n3f()} +Xis called for the normal, and then +X{\tt v3f()} +Xis called for the point. +X\funcitem{vnarray}{} +XSimilar to +X{\tt nvarray()} +Xbut the pairs have the point first and the normal second. +X\funcitem{nurbssurface}{s\_k[], t\_k[], ctl[][], s\_ord, t\_ord, type} +X%.br +X\itembreak +XDefines a nurbs surface. +XThe dimensions of +X{\tt ctl[][]} +Xare computed as follows: +X{\tt [len(s\_k)~-~s\_ord]}, +X{\tt [len(t\_k)~-~t\_ord]}. +X\funcitem{nurbscurve}{knots, ctlpoints, order, type} +X%.br +XDefines a nurbs curve. +XThe length of ctlpoints is +X{\tt len(knots)~-~order}. +X\funcitem{pwlcurve}{points, type} +X%.br +XDefines a piecewise-linear curve. +X{\tt points} +Xis a list of points. +X{\tt type} +Xmust be +X{\tt N\_ST}. +X\funcitem{pick(n), select}{n} +X%.br +XThe only argument to these functions specifies the desired size of the +Xpick or select buffer. +X\funcitem{endpick(), endselect}{} +X%.br +XThese functions have no arguments. +XThey return a list of integers representing the used part of the +Xpick/select buffer. +XNo method is provided to detect buffer overrun. +X\end{description} +X +XHere is a tiny but complete example GL program in {\Python}: +X\bcode\begin{verbatim} +Ximport gl, GL, time +X +Xdef main(): +X gl.foreground() +X gl.prefposition(500, 900, 500, 900) +X w = gl.winopen('CrissCross') +X gl.ortho2(0.0, 400.0, 0.0, 400.0) +X gl.color(GL.WHITE) +X gl.clear() +X gl.color(GL.RED) +X gl.bgnline() +X gl.v2f(0.0, 0.0) +X gl.v2f(400.0, 400.0) +X gl.endline() +X gl.bgnline() +X gl.v2f(400.0, 0.0) +X gl.v2f(0.0, 400.0) +X gl.endline() +X time.sleep(5) +X +Xmain() +X\end{verbatim}\ecode +X +X\subsection{Built-in Module {\tt pnl}} +X +XThis module provides access to the +X{\em Panel Library} +Xbuilt by NASA Ames (to get it, send e-mail to +X{\tt [email protected]}). +XAll access to it should be done through the standard module +X{\tt panel}, +Xwhich transparantly exports most functions from +X{\tt pnl} +Xbut redefines +X{\tt pnl.dopanel()}. +X +X{\bf Warning:} +Xthe {\Python} interpreter will dump core if you don't create a GL window +Xbefore calling +X{\tt pnl.mkpanel()}. +X +XThe module is too large to document here in its entirety. +EOF +fi +if test -s 'src/sc_interpr.c' +then echo '*** I will not over-write existing file src/sc_interpr.c' +else +echo 'x - src/sc_interpr.c' +sed 's/^X//' > 'src/sc_interpr.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X#if 0 +X#define STACK_TRACE +X#define SCDEBUG +X#endif +X#include <stdio.h> +X +X#include <ailamoeba.h> +X +X#include "PROTO.h" +X#include "sc_global.h" +X#include "object.h" +X#include "objimpl.h" +X#include "stringobject.h" +X#include "errors.h" +X#include "sc_errors.h" +X#include "stubcode.h" +X#include "tupleobject.h" +X#include "intobject.h" +X#include "listobject.h" +X +Xtypedef struct s_loopstruct { +X struct s_loopstruct *l_next; /* Make a list of it */ +X TscOperand l_label; /* Indentify the loop */ +X int l_index; /* The index of the list */ +X int l_size; /* The size of the list */ +X int l_retaddr; /* Addres to jump back */ +X int l_endaddr; /* Addres to jump to end */ +X object *l_list; /* The list to append to */ +X} TsLoop, *TpsLoop; +X +X +X/* +X** This file contains the Stubcode interpreter. +X** All the instructions have there own function. The interpreter +X** reads an instruction from the data and if needed also an operand. +X** After this it calls the function that executes the instruction. +X*/ +X +Xstruct sc_ProcessBlock { +X object **stack; +X unsigned char *buffer, *data; +X int sp, bp, pc, maxbufsize, datsize; +X header hdr; +X TpsLoop loops; +X}; +X +Xextern getcapability(); +X +X/* +X * Clean up the mess the loops make. +X */ +X +Xstatic void +XxCleanUpLoops(sc_pb) +X struct sc_ProcessBlock *sc_pb; +X{ +X TpsLoop prev, this; +X +X if (sc_pb->loops == NULL) +X return; +X prev = sc_pb->loops; +X this = sc_pb->loops->l_next; +X while(this) { +X free((char *)prev); +X prev = this; +X this = this->l_next; +X } +X free((char *)prev); +X} +X +Xstatic int +Xfindendloop(label, sc_pb) +X TscOperand label; +X struct sc_ProcessBlock *sc_pb; +X{ +X TscOperand operand; +X TscOpcode opcode; +X int walk = sc_pb->pc, found = 0; +X +X while (!found && (walk < sc_pb->datsize)) { +X memcpy(&opcode, &sc_pb->data[walk], sizeof(TscOpcode)); +X walk += sizeof(TscOpcode); +X if (opcode & (FLAGS | OPERAND)) { +X memcpy(&operand, &sc_pb->data[walk], sizeof(TscOperand)); +X walk += sizeof(TscOperand); +X } +X if (opcode == EndLoop) +X if (operand == label) found = 1; +X } +X if (found) +X return walk; +X return -1; +X} +X +Xstatic int +Xfindloop(ret, label, sc_pb) +X TpsLoop *ret; +X TscOperand label; +X struct sc_ProcessBlock *sc_pb; +X{ +X TpsLoop walk; +X +X for (walk = sc_pb->loops; walk != NULL; walk = walk->l_next) { +X if (walk->l_label == label) break; +X } +X if (walk == NULL) { +X TpsLoop newloop; +X +X newloop = (TpsLoop)malloc(sizeof(TsLoop)); +X if (newloop == NULL) { +X err_nomem(); +X return -1; +X } +X newloop->l_label = label; +X newloop->l_index = 0; +X newloop->l_retaddr = sc_pb->pc - (sizeof(TscOpcode) + sizeof(TscOperand)); +X /* +X ** We need a correction because the pc points to +X ** the instruction after the XXXLoop. +X */ +X if ((newloop->l_endaddr = findendloop(label, sc_pb)) < 0) { +X free((char *)newloop); +X err_scerr(NoEndLoop); +X return -1; +X } +X newloop->l_list = NULL; +X newloop->l_next = sc_pb->loops; +X sc_pb->loops = newloop; +X *ret = newloop; +X return 1; +X } +X *ret = walk; +X return 0; +X} +X +X#ifdef 0 +X +Xstatic void +Xremoveloop(this, sc_pb) +X TpsLoop this; +X struct sc_ProcessBlock *sc_pb; +X{ +X TpsLoop walk, prev = NULL; +X +X for (walk = sc_pb->loops; walk != NULL; walk = walk->l_next) { +X if (walk->l_label == this->l_label) { +X if (prev != NULL) { +X prev->l_next = walk->l_next; +X } else { +X loop = walk->l_next; +X } +X free((char *)this); +X break; +X } +X prev = walk; +X } +X} +X +X#endif +X +Xstatic int +Xinit(self, sc_pb) +X object *self; +X struct sc_ProcessBlock *sc_pb; +X{ +Xobject *string; +Xint datasize; +X +X string = gettupleitem(self, STUBC); +X if (string == NULL) +X return -1; +X sc_pb->data = getstringvalue(string); +X if (sc_pb->data == NULL) +X return -1; +X datasize = (int)getstringsize(string); +X if (datasize == -1) +X return -1; +X sc_pb->stack = (object **)malloc(STKSIZE * sizeof(object *)); +X if (sc_pb->stack == NULL) { +X err_nomem(); +X return -1; +X } +X sc_pb->bp = sc_pb->sp = sc_pb->pc = 0; +X sc_pb->loops = NULL; +X return datasize; +X} +X +Xstatic void reinit(sc_pb) +X struct sc_ProcessBlock *sc_pb; +X{ +X int i; +X +X sc_pb->bp = 0; +X for (i = 0; i < sc_pb->sp; i++) { +X DECREF(sc_pb->stack[i]); +X } +X sc_pb->sp = 0; +X} +X +Xstatic void UnInit(self, sc_pb) +X object *self; +X struct sc_ProcessBlock *sc_pb; +X{ +X int i; +X +X free(sc_pb->buffer); +X reinit(sc_pb); +X free((char *)sc_pb->stack); +X xCleanUpLoops(sc_pb); +X} +X +Xstatic object * +Xstacktop(sc_pb) +X struct sc_ProcessBlock *sc_pb; +X{ +X +X if (sc_pb->sp == 0) +X return err_scerr(StackUnderflow); +X if (sc_pb->sp == (STKSIZE + 1)) +X return err_scerr(StackOverflow); +X return sc_pb->stack[sc_pb->sp - 1]; +X} +X +X/* +X * Push an object on the stack. +X */ +Xstatic int +XxPush(element, sc_pb) +X object *element; +X struct sc_ProcessBlock *sc_pb; +X{ +X +X if (sc_pb->sp >= STKSIZE) { +X err_scerr(StackOverflow); +X return -1; +X } +X if (element == NULL) { +X err_scerr(ElementIsNull); +X return -1; +X } +X INCREF(element); +X#ifdef STACK_TRACE +X printf("pushed :"); +X printobject(element, stdout, 0); +X printf("\n"); +X#endif +X sc_pb->stack[sc_pb->sp++] = element; +X return 0; +X} +X +X/* +X * Perform the RPC. +X */ +Xstatic int +XxTrans(self,cmd, sc_pb) +X object *self; +X TscOperand cmd; +X struct sc_ProcessBlock *sc_pb; +X{ +X short ret; +X capability cap; +X object *capobj; +X +X if ((capobj = gettupleitem(self, CAP)) == NULL) +X return -1; +X if (getcapability(capobj, &cap) == -1) +X return -1; +X sc_pb->hdr.h_port = cap.cap_port; +X sc_pb->hdr.h_priv = cap.cap_priv; +X sc_pb->hdr.h_command = (command)cmd; +X#ifdef SCDEBUG +X printf("bp = %d maxbufsize = %d\n",sc_pb->bp, sc_pb->maxbufsize); +X { +X int i; +X +X for (i = 0; i < sc_pb->bp; i++) { +X printf("%x ", sc_pb->buffer[i]); +X } +X } +X printf("\n"); +X#endif +X ret = trans(&sc_pb->hdr, sc_pb->buffer, (bufsize) sc_pb->bp, +X &sc_pb->hdr, sc_pb->buffer, (bufsize)sc_pb->maxbufsize); +X#ifdef SCDEBUG +X printf("after Trans:ret = %d\n",ret); +X { +X int i; +X +X for (i = 0; i < ret; i++) { +X printf("%x ", sc_pb->buffer[i]); +X } +X } +X printf("\n"); +X#endif +X if (ERR_STATUS(ret)) { +X amoeba_error(ERR_CONVERT(ret)); +X return -1; +X } +X if (sc_pb->hdr.h_status != 0) { +X object *v; +X +X if ((v = newintobject(sc_pb->hdr.h_status)) == NULL) +X return -1; +X err_scerrset(TransError, v, "Trans"); +X DECREF(v); +X return -1; +X } +X reinit(sc_pb); +X return 0; +X} +X +X/* +X * Test the tuple size. +X */ +Xstatic int +XxTTupleS(size, sc_pb) +X TscOperand size; +X struct sc_ProcessBlock *sc_pb; +X{ +X object *tuple; +X +X if ((tuple = stacktop(sc_pb)) == NULL) +X return -1; +X if (!is_tupleobject(tuple)) +X return err_scerrset(TypeFailure, tuple, "TTupleS"); +X if (gettuplesize(tuple) != (unsigned int)size) +X return err_scerrset(SizeError, tuple, "TTupleS"); +X return 0; +X} +X +X/* +X * Unpack a tuple +X */ +Xstatic int +XxUnpack(size, sc_pb) +X TscOperand size; +X struct sc_ProcessBlock *sc_pb; +X{ +X object *tuple, *element; +X int i; +X +X if (size < (TscOperand)2) { +X element = newintobject(size); +X if (element == NULL) +X return -1; +X return err_scerrset(SizeError, element, "Unpack"); +X } +X if ((tuple = stacktop(sc_pb)) == NULL) +X return -1; +X INCREF(tuple); +X if (xPop((TscOperand) 1, sc_pb) != 0) { +X DECREF(tuple); +X return -1; +X } +X for (i = 0; i < (int)size; i++) { +X if ((element = gettupleitem(tuple, i)) == NULL) { +X DECREF(tuple); +X return -1; +X } +X if (xPush(element, sc_pb) != 0) { +X DECREF(tuple); +X return -1; +X } +X } +X DECREF(tuple); +X return 0; +X} +X +X/* +X * Marshal the Ailword to a headerfiels. +X */ +Xstatic int +XxAilword(headerfield, sc_pb) +X TscOperand headerfield; +X struct sc_ProcessBlock *sc_pb; +X{ +X +X switch(headerfield) { +X +X case H_EXTRA: +X sc_pb->hdr.h_extra = (uint16)_ailword; +X return 0; +X +X case H_SIZE: +X sc_pb->hdr.h_size = (bufsize)_ailword; +X return 0; +X +X case H_OFFSET: +X sc_pb->hdr.h_offset = (int32)_ailword; +X return 0; +X +X default: +X { +X object *v; +X +X if ((v = newintobject(headerfield)) == NULL) +X return -1; +X return err_scerrset(FlagError, v, "Ailword"); +X } +X } +X} +X +Xstatic int +XxStringS(sc_pb) +X struct sc_ProcessBlock *sc_pb; +X{ +X object *size, *string; +X int s; +X +X if ((string = stacktop(sc_pb)) == NULL) +X return -1; +X if (!is_stringobject(string)) +X return err_scerrset(TypeFailure, string, "StringS"); +X if ((s = getstringsize(string)) < 0) +X return -1; +X if (xPop((TscOperand) 1, sc_pb) != 0) +X return -1; +X if ((size = newintobject(s)) == NULL) +X return -1; +X if (xPush(size, sc_pb) != 0) { +X DECREF(size); +X return -1; +X } +X DECREF(size); +X return 0; +X} +X +X/* +X * +X */ +Xstatic int +XxListS(sc_pb) +X struct sc_ProcessBlock *sc_pb; +X{ +X object *size, *list; +X int s; +X +X if ((list = stacktop(sc_pb)) == NULL) +X return -1; +X if (!is_listobject(list)) +X return err_scerrset(TypeFailure, list, "ListS"); +X if ((s = getlistsize(list)) < 0) +X return -1; +X if (xPop((TscOperand) 1, sc_pb) != 0) +X return -1; +X if ((size = newintobject(s)) == NULL) +X return -1; +X if (xPush(size, sc_pb) != 0) { +X DECREF(size); +X return -1; +X } +X DECREF(size); +X return 0; +X} +X +X/* +X * Marshal a fixed string to the buffer. +X */ +Xstatic int +XxPutFS(size, sc_pb) +X TscOperand size; +X struct sc_ProcessBlock *sc_pb; +X{ +X object *string; +X char *str; +X +X if ((string = stacktop(sc_pb)) == NULL) { +X return -1; +X } +X if (!is_stringobject(string)) +X return err_scerrset(TypeFailure, string, "PutFS"); +X if (getstringsize(string) != size) +X return err_scerrset(SizeError, string, "PutFS"); +X if ((str = getstringvalue(string)) == NULL) +X return -1; +X if ((size + sc_pb->bp) > sc_pb->maxbufsize) { +X err_scerr(BufferOverflow); +X return -1; +X } +X memcpy(&sc_pb->buffer[sc_pb->bp], str, (int)size); +X sc_pb->bp += size; +X return xPop((TscOperand) 1, sc_pb); +X} +X +X +X/* +X * Test the size of a string or list +X */ +Xstatic int +XxTStringSeq(size, sc_pb) +X TscOperand size; +X struct sc_ProcessBlock *sc_pb; +X{ +X object *string; +X +X if ((string = stacktop(sc_pb)) == NULL) +X return -1; +X if (!is_stringobject(string)) +X return err_scerrset(TypeFailure, string, "TStringSeq"); +X if (getstringsize(string) != size) +X return err_scerrset(SizeError, string, "TStringSeq"); +X return 0; +X} +X +Xstatic int +XxTStringSlt(size, sc_pb) +X TscOperand size; +X struct sc_ProcessBlock *sc_pb; +X{ +X object *string; +X +X if ((string = stacktop(sc_pb)) == NULL) +X return -1; +X if (!is_stringobject(string)) +X return err_scerrset(TypeFailure, string, "TStringSlt"); +X if (getstringsize(string) > size) +X return err_scerrset(SizeError, string, "TStringSlt"); +X return 0; +X} +X +Xstatic int +XxTListSeq(size, sc_pb) +X TscOperand size; +X struct sc_ProcessBlock *sc_pb; +X{ +X object *list; +X +X if ((list = stacktop(sc_pb)) == NULL) +X return -1; +X if (!is_listobject(list)) +X return err_scerrset(TypeFailure, list, "TListSeq"); +X if (getlistsize(list) != size) +X return err_scerrset(SizeError, list, "TListSeq"); +X return 0; +X} +X +Xstatic int +XxTListSlt(size, sc_pb) +X TscOperand size; +X struct sc_ProcessBlock *sc_pb; +X{ +X object *list; +X +X if ((list = stacktop(sc_pb)) == NULL) +X return -1; +X if (!is_listobject(list)) +X return err_scerrset(TypeFailure, list, "TListSlt"); +X if (getlistsize(list) > size) +X return err_scerrset(SizeError, list, "TListSlt"); +X return 0; +X} +X +Xstatic int +XxPutVS(sc_pb) +X struct sc_ProcessBlock *sc_pb; +X{ +X object *string; +X char *str; +X int size; +X +X if ((string = stacktop(sc_pb)) == NULL) +X return -1; +X if ((size = getstringsize(string)) < 0) +X return (size == -1 ? -1 : err_scerrset(SizeError, string, "PutVS")); +X if ((str = getstringvalue(string)) == NULL) +X return -1; +X if (sc_pb->bp + size > sc_pb->maxbufsize) { +X err_scerr(BufferOverflow); +X return -1; +X } +X memcpy(&sc_pb->buffer[sc_pb->bp], str, size); +X sc_pb->bp += size; +X return xPop((TscOperand) 1, sc_pb); +X} +X +X/* +X * The loop instructions. +X */ +Xstatic int +XxLoopPut(label, sc_pb) +X TscOperand label; +X struct sc_ProcessBlock *sc_pb; +X{ +X TpsLoop this; +X object *list, *element; +X +X if (findloop(&this, label, sc_pb) < 0) +X return -1; +X if ((list = stacktop(sc_pb)) == NULL) +X return -1; +X if (!is_listobject(list)) +X return err_scerrset(TypeFailure, list, "LoopPut"); +X if (this->l_index >= getlistsize(list)) { +X sc_pb->pc = this->l_endaddr; +X /* +X ** Pop the list from the stack +X */ +X return xPop((TscOperand)1, sc_pb); +X } +X if ((element = getlistitem(list, this->l_index)) == NULL) +X return -1; +X return xPush(element, sc_pb); +X} +X +Xstatic int +XxLoopGet(label, sc_pb) +X TscOperand label; +X struct sc_ProcessBlock *sc_pb; +X{ +X TpsLoop this; +X object *element, *integer; +X int i; +X +X if ((i = findloop(&this, label, sc_pb)) < 0) +X return -1; +X else if (i == 1) { +X /* +X * It is the first time we enter LoopGet label +X */ +X if ((this->l_list = newlistobject(0)) == NULL) +X return -1; +X if ((integer = stacktop(sc_pb)) == NULL) +X return -1; +X if (!is_intobject(integer)) +X return err_scerrset(TypeFailure, integer, "LoopGet"); +X this->l_size = getintvalue(integer); +X if (xPop((TscOperand) 1, sc_pb) != 0) +X return -1; +X } else { +X if ((element = stacktop(sc_pb)) == NULL) +X return -1; +X if (addlistitem(this->l_list, element) != 0) +X return -1; +X if (xPop((TscOperand) 1, sc_pb) != 0) +X return -1; +X } +X if (this->l_index >= this->l_size) { +X int ret; +X +X sc_pb->pc = this->l_endaddr; +X ret = xPush(this->l_list, sc_pb); +X DECREF(this->l_list); +X return ret; +X } +X return 0; +X} +X +Xstatic int +XxEndLoop(label, sc_pb) +X TscOperand label; +X struct sc_ProcessBlock *sc_pb; +X{ +X TpsLoop this; +X +X if (findloop(&this, label, sc_pb) < 0) +X return -1; +X this ->l_index += 1; +X sc_pb->pc = this->l_retaddr; +X return 0; +X} +X +Xstatic int +XxPutI(flags, sc_pb) +X TscOperand flags; +X struct sc_ProcessBlock *sc_pb; +X{ +X object *integer; +X +X if ((integer = stacktop(sc_pb)) == NULL) +X return -1; +X if (!is_intobject(integer)) +X return err_scerrset(TypeFailure, integer, "PutI"); +X if (flags & ALL_FIELDS) { +X long i; +X +X /* +X * The integer must be marshalles in the header. +X * No type casting according to the type flag because +X * we have to cast to the headerfield types. +X */ +X i = getintvalue(integer); +X switch(flags & ALL_FIELDS) { +X +X case H_EXTRA: +X sc_pb->hdr.h_extra = (uint16)i; +X break; +X +X case H_SIZE: +X sc_pb->hdr.h_size = (bufsize)i; +X break; +X +X case H_OFFSET: +X sc_pb->hdr.h_offset = (int32)i; +X break; +X +X default: +X if ((integer = newintobject(flags & ALL_FIELDS)) == NULL) +X return -1; +X err_scerrset(FlagError, integer, "Ailword"); +X DECREF(integer); +X return -1; +X } +X } else { +X long i; +X +X i = getintvalue(integer); +X switch(flags & ALLTYPES) { +X +X case 0: +X { +X int16 x; +X +X x = (int16)i; +X if ((sc_pb->bp + sizeof(int16)) > sc_pb->maxbufsize) { +X err_scerr(BufferOverflow); +X return -1; +X } +X memcpy(&sc_pb->buffer[sc_pb->bp], &x, sizeof(int16)); +X sc_pb->bp += sizeof(int16); +X break; +X } +X +X case NOSIGN: +X { +X uint16 x; +X +X x = (uint16)i; +X if ((sc_pb->bp + sizeof(uint16)) > sc_pb->maxbufsize) { +X err_scerr(BufferOverflow); +X return -1; +X } +X memcpy(&sc_pb->buffer[sc_pb->bp], &x, sizeof(uint16)); +X sc_pb->bp += sizeof(uint16); +X break; +X } +X +X case INT32: +X { +X int32 x; +X +X x = (int32)i; +X if ((sc_pb->bp + sizeof(int32)) > sc_pb->maxbufsize) { +X err_scerr(BufferOverflow); +X return -1; +X } +X memcpy(&sc_pb->buffer[sc_pb->bp], &x, sizeof(int32)); +X sc_pb->bp += sizeof(int32); +X break; +X } +X +X case INT32 | NOSIGN: +X { +X uint32 x; +X +X x = (uint32)i; +X if ((sc_pb->bp + sizeof(uint32)) > sc_pb->maxbufsize) { +X err_scerr(BufferOverflow); +X return -1; +X } +X memcpy(&sc_pb->buffer[sc_pb->bp], &x, sizeof(uint32)); +X sc_pb->bp += sizeof(uint32); +X break; +X } +X default: +X { +X object *x; +X +X if ((x = newintobject(flags)) == NULL) +X return -1; +X err_scerrset(FlagError, x, "PutI"); +X DECREF(x); +X return -1; +X } +X } +X } +X return xPop((TscOperand)1, sc_pb); +X} +X +Xstatic int +XxPutC(sc_pb) +X struct sc_ProcessBlock *sc_pb; +X{ +X capability cap; +X object *capobj; +X +X if ((capobj = stacktop(sc_pb)) == NULL) +X return -1; +X if (!is_capobj(capobj)) +X return err_scerrset(TypeFailure, capobj, "xPutC"); +X if (getcapability(capobj, &cap) != 0) +X return -1; +X if ((sc_pb->bp + CAPSIZE) > sc_pb->maxbufsize) { +X err_scerr(BufferOverflow); +X return -1; +X } +X memcpy(&sc_pb->buffer[sc_pb->bp], &cap, CAPSIZE); +X sc_pb->bp += CAPSIZE; +X return xPop((TscOperand) 1, sc_pb); +X} +X +Xstatic int +XxDup(n, sc_pb) +X TscOperand n; +X struct sc_ProcessBlock *sc_pb; +X{ +X +X if ((int)n > sc_pb->sp) { +X object *i; +X +X if ((i = newintobject((long)n)) == NULL) +X return -1; +X err_scerrset(RangeError, i, "Dup"); +X DECREF(i); +X return -1; +X } +X return xPush(sc_pb->stack[sc_pb->sp - n], sc_pb); +X} +X +Xstatic int +XxPop(n, sc_pb) +X TscOperand n; +X struct sc_ProcessBlock *sc_pb; +X{ +X int i; +X +X if ((sc_pb->sp - (int)n) < 0) { +X err_scerr(StackUnderflow); +X return -1; +X } +X for (i = 0; i < (int)n; i++) { +X sc_pb->sp--; +X#ifdef STACK_TRACE +X printf("popped :"); +X printobject(sc_pb->stack[sc_pb->sp], stdout, 0); +X printf("\n"); +X#endif +X DECREF(sc_pb->stack[sc_pb->sp]); +X } +X return 0; +X} +X +Xstatic int +XxAlign(n, sc_pb) +X TscOperand n; +X struct sc_ProcessBlock *sc_pb; +X{ +X int align = sc_pb->bp % (int)n; +X +X#ifdef SCDEBUG +X printf("Old bp = %d\n", sc_pb->bp); +X#endif +X sc_pb->bp += (align == 0) ? 0 : ((int)n - align); +X#ifdef SCDEBUG +X printf("New bp = %d\n", sc_pb->bp); +X#endif +X return 0; +X} +X +Xstatic int +XxPack(size, sc_pb) +X TscOperand size; +X struct sc_ProcessBlock *sc_pb; +X{ +X object *element, *tuple; +X int i, ret; +X +X if ((tuple = newtupleobject((int)size)) == NULL) +X return -1; +X for (i = 0; i < (int)size; i++) { +X if ((element = stacktop(sc_pb)) == NULL) +X return -1; +X if (settupleitem(tuple, (int)size - i - 1, element) != 0) +X return -1; +X INCREF(element); +X if (xPop((TscOperand) 1, sc_pb) != 0) +X return -1; +X } +X ret = xPush(tuple, sc_pb); +X DECREF(tuple); +X return ret; +X} +X +Xstatic int +XxGetVS(sc_pb) +X struct sc_ProcessBlock *sc_pb; +X{ +X object *string, *integer; +X int size; +X +X if ((integer = stacktop(sc_pb)) == NULL) +X return -1; +X if (!is_intobject(integer)) +X return err_scerrset(TypeFailure, integer, "GetVS"); +X size = getintvalue(integer); +X if ((sc_pb->bp + size) > sc_pb->maxbufsize) { +X err_scerr(BufferOverflow); +X return -1; +X } +X if ((string = newsizedstringobject(&sc_pb->buffer[sc_pb->bp], size)) == NULL) +X return -1; +X sc_pb->bp += size; +X if (xPop((TscOperand) 1, sc_pb) != 0) +X return -1; +X if (xPush(string, sc_pb) != 0) { +X return -1; +X } +X DECREF(string); +X return 0; +X} +X +Xstatic int +XxGetFS(size, sc_pb) +X TscOperand size; +X struct sc_ProcessBlock *sc_pb; +X{ +X object *string; +X +X if ((sc_pb->bp + (int)size) > sc_pb->maxbufsize) { +X err_scerr(BufferOverflow); +X return -1; +X } +X if ((string = newsizedstringobject(&sc_pb->buffer[sc_pb->bp], (int)size)) == NULL) +X return -1; +X sc_pb->bp += (int)size; +X if(xPush(string, sc_pb) != 0) { +X return -1; +X } +X DECREF(string); +X return 0; +X} +X +Xstatic int +XxGetI(flags, sc_pb) +X TscOperand flags; +X struct sc_ProcessBlock *sc_pb; +X{ +X object *integer; +X long i; +X +X if (flags & ALL_FIELDS) { +X +X switch(flags & ALL_FIELDS) { +X +X case H_EXTRA: +X i = (long)sc_pb->hdr.h_extra; +X break; +X +X case H_SIZE: +X i = (long)sc_pb->hdr.h_size; +X break; +X +X case H_OFFSET: +X i = (long)sc_pb->hdr.h_offset; +X break; +X +X default: +X if ((integer = newintobject(flags & ALL_FIELDS)) == NULL) +X return -1; +X err_scerrset(FlagError, integer, "Ailword"); +X DECREF(integer); +X return -1; +X } +X } else { +X switch(flags & ALLTYPES) { +X +X case 0: +X { +X int16 x; +X +X if ((sc_pb->bp + sizeof(int16)) > sc_pb->maxbufsize) { +X err_scerr(BufferOverflow); +X return -1; +X } +X memcpy(&x, &sc_pb->buffer[sc_pb->bp], sizeof(int16)); +X sc_pb->bp += sizeof(int16); +X i = (long)x; +X break; +X } +X +X case NOSIGN: +X { +X uint16 x; +X +X if ((sc_pb->bp + sizeof(uint16)) > sc_pb->maxbufsize) { +X err_scerr(BufferOverflow); +X return -1; +X } +X memcpy(&x, &sc_pb->buffer[sc_pb->bp], sizeof(uint16)); +X sc_pb->bp += sizeof(uint16); +X i = (long)x; +X break; +X } +X +X case INT32: +X { +X int32 x; +X +X if ((sc_pb->bp + sizeof(int32)) > sc_pb->maxbufsize) { +X err_scerr(BufferOverflow); +X return -1; +X } +X memcpy(&x, &sc_pb->buffer[sc_pb->bp], sizeof(int32)); +X sc_pb->bp += sizeof(int32); +X i = (long)x; +X break; +X } +X +X case INT32 | NOSIGN: +X { +X uint32 x; +X +X if ((sc_pb->bp + sizeof(uint32)) > sc_pb->maxbufsize) { +X err_scerr(BufferOverflow); +X return -1; +X } +X memcpy(&x, &sc_pb->buffer[sc_pb->bp], sizeof(uint32)); +X sc_pb->bp += sizeof(uint32); +X i = (long)x; +X break; +X } +X default: +X { +X if ((integer = newintobject(flags)) == NULL) +X return -1; +X err_scerrset(FlagError, integer, "GetI"); +X DECREF(integer); +X return -1; +X } +X } +X } +X if ((integer = newintobject(i)) == NULL) +X return -1; +X if (xPush(integer, sc_pb) != 0) { +X DECREF(integer); +X return -1; +X } +X DECREF(integer); +X return 0; +X} +X +Xstatic int +XxGetC(flags, sc_pb) +X TscOperand flags; +X struct sc_ProcessBlock *sc_pb; +X{ +X extern object *newcapobject(); +X object *capobj; +X capability cap; +X +X if ((int)flags != 0) { +X switch ((int)flags) { +X +X case PSEUDOFIELD: +X cap.cap_port = sc_pb->hdr.h_port; +X cap.cap_priv = sc_pb->hdr.h_priv; +X break; +X } +X } else { +X if ((CAPSIZE + sc_pb->bp) > sc_pb->maxbufsize) { +X err_scerr(BufferOverflow); +X return -1; +X } +X memcpy(&cap, &sc_pb->buffer[sc_pb->bp], CAPSIZE); +X } +X if ((capobj = newcapobject(&cap)) == NULL) +X return -1; +X return xPush(capobj, sc_pb); +X} +X +Xstatic int +XxEqual(sc_pb) +X struct sc_ProcessBlock *sc_pb; +X{ +X object *int1, *int2; +X +X if (sc_pb->sp < 2) { +X err_scerr(StackUnderflow); +X return -1; +X } +X int1 = sc_pb->stack[sc_pb->sp - 1]; +X int2 = sc_pb->stack[sc_pb->sp - 2]; +X if ((int1 == NULL) || (int2 == NULL)) +X return -1; +X if (!is_intobject(int1)) +X return err_scerrset(TypeFailure, int1, "Equal"); +X if (!is_intobject(int2)) +X return err_scerrset(TypeFailure, int2, "Equal"); +X if (getintvalue(int1) != getintvalue(int2)) { +X object *tmptuple; +X +X if ((tmptuple = newtupleobject(2)) == NULL) +X return -1; +X INCREF(int1); +X if (settupleitem(tmptuple, 0, int1) != 0) { +X DECREF(tmptuple); +X DECREF(int1); +X return -1; +X } +X if (settupleitem(tmptuple, 1, int2) != 0) { +X DECREF(tmptuple); +X DECREF(int2); +X return -1; +X } +X return err_scerrset(SizeError, tmptuple, "Equal"); +X } +X return 0; +X} +X +Xobject * +Xsc_interpreter(self, args) +X object *self, *args; +X{ +XTscOpcode opcode; +XTscOperand operand; +Xint datasize, ret; +Xobject *returnobject; +Xstruct sc_ProcessBlock sc_pb; +X +X if ((datasize = init(self, &sc_pb)) < 0) +X return NULL; +X memcpy(&opcode, sc_pb.data, sizeof(TscOpcode)); +X sc_pb.datsize = datasize; +X sc_pb.pc += sizeof(TscOpcode); +X if (opcode != BufSize) { +X free((char *)sc_pb.stack); +X return err_scerr(NoBufSize); +X } +X memcpy(&operand, &sc_pb.data[sc_pb.pc], sizeof(TscOperand)); +X sc_pb.pc += sizeof(TscOperand); +X sc_pb.buffer = (unsigned char *)malloc(operand); +X sc_pb.maxbufsize = (int)operand; +X if (sc_pb.buffer == NULL) { +X free((char *)sc_pb.stack); +X return err_nomem(); +X } +X memcpy(&opcode, &sc_pb.data[sc_pb.pc], sizeof(TscOpcode)); +X if (opcode != NoArgs) { +X if (xPush(args, &sc_pb) != 0) { +X UnInit(self, &sc_pb); +X return NULL; +X } +X } +X while (sc_pb.pc < datasize) { +X memcpy(&opcode, &sc_pb.data[sc_pb.pc], sizeof(TscOpcode)); +X sc_pb.pc += sizeof(TscOpcode); +X if (opcode & (OPERAND | FLAGS)) { +X memcpy(&operand, &sc_pb.data[sc_pb.pc], sizeof(TscOperand)); +X sc_pb.pc += sizeof(TscOperand); +X } +X#ifdef SCDEBUG +X xPrintCode(opcode); +X if ((opcode & FLAGS) && (opcode & OPERAND)) +X xPrintFlags(operand); +X else if (opcode & OPERAND) +X xPrintNum(operand); +X printf("\n"); +X fflush(stdout); +X#endif +X#ifdef STACK_TRACE +X { +X register i; +X +X printf("Stack trace :\n"); +X for(i = 0; i < sc_pb.sp; i++) { +X printobject(sc_pb.stack[i], stdout, 0); +X printf("\n"); +X } +X } +X#endif +X switch(opcode) { +X +X case NoArgs: +X ret = 0; +X if (args != NULL) { +X err_scerrset(TypeFailure, args, "NoArgs"); +X ret = -1; +X } +X break; +X +X case BufSize: +X UnInit(self, &sc_pb); +X return err_scerr(TwoBufSize); +X +X case Trans: +X ret = xTrans(self, operand, &sc_pb); +X break; +X +X case TTupleS: +X ret = xTTupleS(operand, &sc_pb); +X break; +X +X case Unpack: +X ret = xUnpack(operand, &sc_pb); +X break; +X +X case AilWord: +X ret = xAilword(operand, &sc_pb); +X break; +X +X case StringS: +X ret = xStringS(&sc_pb); +X break; +X +X case ListS: +X ret = xListS(&sc_pb); +X break; +X +X case PutFS: +X ret = xPutFS(operand, &sc_pb); +X break; +X +X case TStringSeq: +X ret = xTStringSeq(operand, &sc_pb); +X break; +X +X case TStringSlt: +X ret = xTStringSlt(operand, &sc_pb); +X break; +X +X case PutVS: +X ret = xPutVS(&sc_pb); +X break; +X +X case TListSeq: +X ret = xTListSeq(operand, &sc_pb); +X break; +X +X case TListSlt: +X +ret = xTListSlt(operand, &sc_pb); +X break; +X +X case LoopPut: +X ret = xLoopPut(operand, &sc_pb); +X break; +X +X case EndLoop: +X ret = xEndLoop(operand, &sc_pb); +X break; +X +X case PutI: +X ret = xPutI(operand, &sc_pb); +X break; +X +X case PutC: +X ret = xPutC(&sc_pb); +X break; +X +X case Dup: +X ret = xDup(operand, &sc_pb); +X break; +X +X case Pop: +X ret = xPop(operand, &sc_pb); +X break; +X +X case Align: +X ret = xAlign(operand, &sc_pb); +X break; +X +X case Pack: +X ret = xPack(operand, &sc_pb); +X break; +X +X case GetVS: +X ret = xGetVS(&sc_pb); +X break; +X +X case LoopGet: +X ret = xLoopGet(operand, &sc_pb); +X break; +X +X case GetFS: +X ret = xGetFS(operand, &sc_pb); +X break; +X +X case GetI: +X ret = xGetI(operand, &sc_pb); +X break; +X +X case GetC: +X ret = xGetC(operand, &sc_pb); +X break; +X +X case PushI: +X { +X object *element; +X +X element = newintobject((long)operand); +X if (element == NULL) { +X UnInit(self, &sc_pb); +X return NULL; +X } +X ret = xPush(element, &sc_pb); +X if (ret == 0) +X DECREF(element); +X } +X break; +X +X case Equal: +X ret = xEqual(&sc_pb); +X break; +X +X default: +X { +X char errstr[256]; +X +X UnInit(self, &sc_pb); +X sprintf(errstr, "Unknow stubcode %d", opcode); +X err_setstr(RuntimeError, errstr); +X return NULL; +X } +X } +X if (ret != 0) { +X UnInit(self, &sc_pb); +X return NULL; +X } +X } +X if (sc_pb.sp > 0) { +X INCREF(sc_pb.stack[sc_pb.sp - 1]); +X returnobject = sc_pb.stack[sc_pb.sp - 1]; +X } else { +X INCREF(None); +X returnobject = None; +X } +X UnInit(self, &sc_pb); +X return returnobject; +X} +EOF +fi +echo 'Part 06 out of 21 of pack.out complete.' +exit 0 diff --git a/shar/python-0.9.1-07-21.shar b/shar/python-0.9.1-07-21.shar new file mode 100644 index 0000000..e242423 --- /dev/null +++ b/shar/python-0.9.1-07-21.shar @@ -0,0 +1,2518 @@ +: This is a shell archive. +: Extract with 'sh this_file'. +: +: Extract part 01 first since it makes all directories +echo 'Start of pack.out, part 07 out of 21:' +if test -s 'demo/sgi/gl/mclock.py' +then echo '*** I will not over-write existing file demo/sgi/gl/mclock.py' +else +echo 'x - demo/sgi/gl/mclock.py' +sed 's/^X//' > 'demo/sgi/gl/mclock.py' << 'EOF' +X#! /ufs/guido/bin/sgi/python +X +X############################################################################# +X# NOTA BENE: Before installing, fix TZDIFF to reflect your local time zone! # +X############################################################################# +X +X# "M Clock" +X# +X# An implementation in software of an original design by Rob Juda. +X# Clock implementation: Guido van Rossum. +X# Alarm and Gong features: Sape Mullender. +X# +X# XXX TO DO: +X# find out local time zone difference automatically +X# add a date indicator +X# allow multiple alarms +X# allow the menu to change more parameters +X +Ximport sys +X +Xfrom gl import * +Xfrom GL import * +Xfrom DEVICE import * +Ximport time +Ximport getopt +Ximport string +Ximport path +Xfrom math import pi +Ximport math +Ximport posix +X +XFULLC = 3600 # Full circle in 1/10-ths of a degree +XMIDN = 900 # Angle of the 12 o'clock position +XR, G, B = 0, 1, 2 # Indices of colors in RGB list +X +XHOUR = 3600 # Number of seconds per hour +XMINUTE = 60 # Number of seconds per minute +X +Xclass struct(): pass # Class to define featureless structures +XGl = struct() # Object to hold writable global variables +X +X# Default constants (used in multiple places) +X +XSCREENBG = 127, 156, 191 +XNPARTS = 9 +XTITLE = 'M Clock' +XTZDIFF = -1*HOUR # <--- change this to reflect your local time zone +X +X# Default parameters +X +XGl.foreground = 0 # If set, run in the foreground +XGl.fullscreen = 0 # If set, run on full screen +XGl.tzdiff = TZDIFF # Seconds west of Greenwich (winter time) +XGl.nparts = NPARTS # Number of parts each circle is divided in (>= 2) +XGl.debug = 0 # If set, print debug output +XGl.doublebuffer = 1 # If set, use double buffering +XGl.update = 0 # Update interval; seconds hand is suppressed if > 1 +XGl.colorsubset = 0 # If set, display only a subset of the colors +XGl.cyan = 0 # If set, display cyan overlay (big hand) +XGl.magenta = 0 # If set, display magenta overlay (little hand) +XGl.yellow = 0 # If set, display yellow overlay (fixed background) +XGl.black = 0 # If set, display black overlay (hands) +XGl.colormap = 0 # If set, use colormap mode instead of RGB mode +XGl.warnings = 0 # If set, print warnings +XGl.title = '- - ' # Window title (default set later) +XGl.border = 1 # If set, use a window border (and title) +XGl.bg = 0, 0, 0 # Background color R, G, B value +XGl.iconic = 0 # Set in iconic state +XGl.fg = 255, 0, 0 # Alarm background RGB (either normal or alarm) +XGl.ox,Gl.oy = 0,0 # Window origin +XGl.cx,Gl.cy = 0,0 # Window size +XGl.alarm_set = 0 # Alarm on or off +XGl.alarm_on = 0 # Alarm is ringing +XGl.alarm_time = 0 # Alarm time in seconds after midnight +XGl.alarm_hours = 0 # Alarm hour setting, 24 hour clock +XGl.alarm_minutes = 0 # Alarm minutes setting +XGl.alarm_rgb = 0,0,0 # Alarm display RGB colors +XGl.alarm_cmd = '' # Command to execute when alarm goes off +XGl.mouse2down = 0 # Mouse button state +XGl.mouse3down = 0 # Mouse button state +XGl.gong_cmd = '' # Command to execute when chimes go off +XGl.gong_int = 3600 # Gong interval +XGl.indices = R, G, B # Colors (permuted when alarm is on) +X +Xdef main(): +X # +X sys.stdout = sys.stderr # All output is errors/warnings etc. +X # +X try: +X args = getoptions() +X except string.atoi_error, value: +X usage(string.atoi_error, value) +X except getopt.error, msg: +X usage(getopt.error, msg) +X # +X if args: +X realtime = 0 +X hours = string.atoi(args[0]) +X minutes = seconds = 0 +X if args[1:]: minutes = string.atoi(args[1]) +X if args[2:]: seconds = string.atoi(args[2]) +X localtime = ((hours*60)+minutes)*60+seconds +X else: +X realtime = 1 +X # +X if Gl.title = '- - ': +X if realtime: +X Gl.title = TITLE +X else: +X title = '' +X for arg in args: title = title + ' ' + arg +X Gl.title = title[1:] +X del title +X # +X wid = makewindow() +X Gl.ox,Gl.oy = getorigin() +X Gl.cx,Gl.cy = getsize() +X initmenu() +X clearall() +X # +X if not Gl.update: +X Gl.update = 60 +X # +X if Gl.update <= 1: +X Gl.timernoise = 6 +X else: +X Gl.timernoise = 60 +X noise(TIMER0, Gl.timernoise) +X # +X qdevice(WINSHUT) +X qdevice(WINQUIT) +X qdevice(ESCKEY) +X if realtime: +X qdevice(TIMER0) +X qdevice(REDRAW) +X qdevice(WINFREEZE) +X qdevice(WINTHAW) +X qdevice(MENUBUTTON) # MOUSE1 +X qdevice(MOUSE3) # Left button +X qdevice(MOUSE2) # Middle button +X unqdevice(INPUTCHANGE) +X # +X lasttime = 0 +X Gl.change = 1 +X while 1: +X if realtime: +X localtime = time.time() - Gl.tzdiff +X if Gl.alarm_set: +X if localtime%(24*HOUR) = Gl.alarm_time: +X # Ring the alarm! +X if Gl.debug: +X print 'Rrrringg!' +X Gl.alarm_on = 1 +X if Gl.alarm_cmd <> '': +X d = posix.system(Gl.alarm_cmd+' '+`Gl.alarm_time/3600`+' '+`(Gl.alarm_time/60)%60` + ' &') +X Gl.change = 1 +X clearall() +X if Gl.alarm_on: +X if (localtime - Gl.alarm_time) % (24*HOUR) > 300: +X # More than 5 minutes away from alarm +X Gl.alarm_on = 0 +X if Gl.debug: +X print 'Alarm turned off' +X Gl.change = 1 +X clearall() +X Gl.indices = R, G, B +X else: +X if localtime % 2 = 0: +X # Permute color indices +X Gl.indices = Gl.indices[2:] + Gl.indices[:2] +X Gl.change = 1 +X if Gl.gong_cmd <> '' and localtime%Gl.gong_int = 0: +X d = posix.system(Gl.gong_cmd+' '+`(localtime/3600)%24`+' '+`(localtime/60)%60` + ' &') +X if localtime/Gl.update <> lasttime/Gl.update: +X if Gl.debug: print 'new time' +X Gl.change = 1 +X if Gl.change: +X if Gl.debug: print 'drawing' +X doit(localtime) +X lasttime = localtime +X Gl.change = 0 +X dev, data = qread() +X if Gl.debug and dev <> TIMER0: +X print dev, data +X if dev = TIMER0: +X if Gl.debug > 1: +X print dev, data +X elif dev = MOUSE3: +X mousex = getvaluator(MOUSEX) +X mousey = getvaluator(MOUSEY) +X if mouseclick(3, data, mousex, mousey): +X Gl.change = 1 +X elif dev = MOUSE2: +X mousex = getvaluator(MOUSEX) +X mousey = getvaluator(MOUSEY) +X if mouseclick(2, data, mousex, mousey): +X Gl.change = 1 +X elif dev = MOUSEX: +X mousex = data +X if Gl.mouse2down: +X mouse2track(mousex, mousey) +X if Gl.mouse3down: +X mouse3track(mousex, mousey) +X elif dev = MOUSEY: +X mousey = data +X if Gl.mouse2down: +X mouse2track(mousex, mousey) +X if Gl.mouse3down: +X mouse3track(mousex, mousey) +X elif dev = REDRAW or dev = REDRAWICONIC: +X if Gl.debug: +X if dev = REDRAW: print 'REDRAW' +X else: print 'REDRAWICONIC' +X reshapeviewport() +X Gl.ox,Gl.oy = getorigin() +X Gl.cx,Gl.cy = getsize() +X Gl.change = 1 +X clearall() +X elif dev = MENUBUTTON: +X if Gl.debug: print 'MENUBUTTON' +X handlemenu() +X elif dev = WINFREEZE: +X if Gl.debug: print 'WINFREEZE' +X Gl.iconic = 1 +X noise(TIMER0, 60*60) # Redraw every 60 seconds only +X elif dev = WINTHAW: +X if Gl.debug: print 'WINTHAW' +X Gl.iconic = 0 +X noise(TIMER0, Gl.timernoise) +X Gl.change = 1 +X elif dev = ESCKEY or dev = WINSHUT or dev = WINQUIT: +X if Gl.debug: print 'Exit' +X sys.exit(0) +X +Xdef getoptions(): +X optlist, args = getopt.getopt(sys.argv[1:], 'A:a:B:bc:dFfG:g:n:sT:t:u:wCMYK') +X for optname, optarg in optlist: +X if optname = '-A': +X Gl.fg = eval(optarg) # Should be (r,g,b) +X elif optname = '-a': +X Gl.alarm_cmd = optarg +X elif optname = '-B': +X Gl.bg = eval(optarg) # Should be (r,g,b) +X elif optname = '-b': +X Gl.border = 0 +X elif optname = '-c': +X Gl.colormap = string.atoi(optarg) +X elif optname = '-d': +X Gl.debug = Gl.debug + 1 +X Gl.warnings = 1 +X elif optname = '-F': +X Gl.foreground = 1 +X elif optname = '-f': +X Gl.fullscreen = 1 +X elif optname = '-G': +X Gl.gong_int = 60*string.atoi(optarg) +X elif optname = '-g': +X Gl.gong_cmd = optarg +X elif optname = '-n': +X Gl.nparts = string.atoi(optarg) +X elif optname = '-s': +X Gl.doublebuffer = 0 +X elif optname = '-T': +X Gl.title = optarg +X elif optname = '-t': +X Gl.tzdiff = string.atoi(optarg) +X elif optname = '-u': +X Gl.update = string.atoi(optarg) +X elif optname = '-w': +X Gl.warnings = 1 +X elif optname = '-C': +X Gl.cyan = Gl.colorsubset = 1 +X elif optname = '-M': +X Gl.magenta = Gl.colorsubset = 1 +X elif optname = '-Y': +X Gl.yellow = Gl.colorsubset = 1 +X elif optname = '-K': +X Gl.black = Gl.colorsubset = 1 +X else: +X print 'Unsupported option', optname +X return args +X +Xdef usage(exc, msg): +X if sys.argv: +X progname = path.basename(sys.argv[0]) +X else: +X progname = 'mclock' +X # +X print progname + ':', +X if exc = string.atoi_error: +X print 'non-numeric argument:', +X print msg +X # +X print 'usage:', progname, '[options] [hh [mm [ss]]]' +X # +X print '-A r,g,b : alarm background red,green,blue [255,0,0]' +X print '-a cmd : shell command executed when alarm goes off' +X print '-B r,g,b : background red,green,blue [0,0,0]' +X print ' (-B SCREENBG uses the default screen background)' +X print '-b : suppress window border and title' +X print '-c cmapid : select explicit colormap' +X print '-d : more debug output (implies -F, -w)' +X print '-F : run in foreground' +X print '-f : use full screen' +X print '-G intrvl : interval between chimes in minutes [60]' +X print '-g cmd : shell command executed when chimes go off' +X print '-s : single buffer mode' +X print '-w : print various warnings' +X print '-n nparts : number of parts [' + `NPARTS` + ']' +X print '-T title : alternate window title [\'' + TITLE + '\']' +X print '-t tzdiff : time zone difference [' + `TZDIFF` + ']' +X print '-u update : update interval [60]' +X print '-CMYK : Cyan, Magenta, Yellow or blacK overlay only' +X print 'if hh [mm [ss]] is specified, display that time statically' +X print 'on machines with < 12 bitplanes, -c and -s are forced on' +X # +X sys.exit(2) +X +Xdef doit(localtime): +X hands = makehands(localtime) +X list = makelist(hands) +X render(list, hands) +X +Xdef makehands(localtime): +X localtime = localtime % (12*HOUR) +X seconds_hand = MIDN + FULLC - (localtime*60) % FULLC +X big_hand = (MIDN + FULLC - (localtime%HOUR)) % FULLC +X little_hand = (MIDN + FULLC - ((localtime/12) % HOUR)) % FULLC +X return little_hand, big_hand, seconds_hand +X +Xdef makelist(little_hand, big_hand, seconds_hand): +X total = [] +X if Gl.cyan or not Gl.colorsubset: +X total = total + makesublist(big_hand, Gl.indices[0]) +X if Gl.magenta or not Gl.colorsubset: +X total = total + makesublist(little_hand, Gl.indices[1]) +X if Gl.yellow or not Gl.colorsubset: +X total = total + makesublist(MIDN, Gl.indices[2]) +X total.sort() +X return total +X +Xdef makesublist(first, icolor): +X list = [] +X alpha = FULLC/Gl.nparts +X a = first - alpha/2 +X for i in range(Gl.nparts): +X angle = (a + i*alpha + FULLC) % FULLC +X value = 255*(Gl.nparts-1-i)/(Gl.nparts-1) +X list.append(angle, icolor, value) +X list.sort() +X a, icolor, value = list[0] +X if a <> 0: +X a, icolor, value = list[len(list)-1] +X t = 0, icolor, value +X list.insert(0, t) +X return list +X +Xdef rgb_fg(): +X return Gl.fg +X # Obsolete code: +X if Gl.alarm_on: +X return Gl.bg +X else: +X return Gl.fg +X +Xdef rgb_bg(): +X return Gl.bg +X # Obsolete code: +X if Gl.alarm_on: +X return Gl.fg +X else: +X return Gl.bg +X +Xdef clearall(): +X Gl.c3i(rgb_bg()) +X clear() +X if Gl.doublebuffer: +X swapbuffers() +X clear() +X +Xdef draw_alarm(color): +X frontbuffer(TRUE) +X Gl.c3i(color) +X pushmatrix() +X rotate(-((Gl.alarm_time/12)%3600), 'z') +X bgnpolygon() +X v2f( 0.00,1.00) +X v2f( 0.04,1.05) +X v2f(-0.04,1.05) +X endpolygon() +X popmatrix() +X # +X pushmatrix() +X rotate(-((Gl.alarm_time)%3600), 'z') +X bgnpolygon() +X v2f( 0.00,1.05) +X v2f( 0.07,1.10) +X v2f(-0.07,1.10) +X endpolygon() +X popmatrix() +X # +X cmov2(-1.06, -1.06) +X charstr(string.rjust(`Gl.alarm_time/3600`,2)) +X charstr(':') +X charstr(string.zfill((Gl.alarm_time/60)%60,2)) +X frontbuffer(FALSE) +X +Xdef render(list, (little_hand, big_hand, seconds_hand)): +X # +X if Gl.colormap: +X resetindex() +X # +X if not list: +X Gl.c3i(255, 255, 255) # White +X circf(0.0, 0.0, 1.0) +X else: +X list.append(3600, 0, 255) # Sentinel +X # +X rgb = [255, 255, 255] +X a_prev = 0 +X for a, icolor, value in list: +X if a <> a_prev: +X [r, g, b] = rgb +X if Gl.debug > 1: +X print rgb, a_prev, a +X Gl.c3i(r, g, b) +X arcf(0.0, 0.0, 1.0, a_prev, a) +X rgb[icolor] = value +X a_prev = a +X # +X if Gl.black or not Gl.colorsubset: +X # +X # Draw the hands -- in black +X # +X Gl.c3i(0, 0, 0) +X # +X if Gl.update = 1 and not Gl.iconic: +X # Seconds hand is only drawn if we update every second +X pushmatrix() +X rotate(seconds_hand, 'z') +X bgnline() +X v2f(0.0, 0.0) +X v2f(1.0, 0.0) +X endline() +X popmatrix() +X # +X pushmatrix() +X rotate(big_hand, 'z') +X rectf(0.0, -0.01, 0.97, 0.01) +X circf(0.0, 0.0, 0.01) +X circf(0.97, 0.0, 0.01) +X popmatrix() +X # +X pushmatrix() +X rotate(little_hand, 'z') +X rectf(0.04, -0.02, 0.63, 0.02) +X circf(0.04, 0.0, 0.02) +X circf(0.63, 0.0, 0.02) +X popmatrix() +X # +X # Draw the alarm time, if set or being set +X # +X if Gl.alarm_set: +X draw_alarm(rgb_fg()) +X # +X if Gl.doublebuffer: swapbuffers() +X +Xdef makewindow(): +X # +X if Gl.debug or Gl.foreground: +X foreground() +X # +X if Gl.fullscreen: +X # XXX Should find out true screen size using getgdesc() +X prefposition(0, 1279, 0, 1023) +X else: +X keepaspect(1, 1) +X minsize(64, 64) +X # +X if not Gl.border: +X noborder() +X wid = winopen(Gl.title) +X # +X if not Gl.fullscreen: +X keepaspect(1, 1) +X minsize(10, 10) +X maxsize(2000, 2000) +X iconsize(66, 66) +X winconstraints() +X # +X nplanes = getplanes() +X nmaps = getgdesc(GD_NMMAPS) +X if Gl.warnings: +X print nplanes, 'color planes,', nmaps, 'color maps' +X # +X if nplanes < 12 or Gl.colormap: +X if not Gl.colormap: +X Gl.colormap = nmaps - 1 +X if Gl.warnings: +X print 'not enough color planes available', +X print 'for RGB mode; forcing colormap mode' +X print 'using color map number', Gl.colormap +X if not Gl.colorsubset: +X needed = 3 +X else: +X needed = Gl.cyan + Gl.magenta + Gl.yellow +X needed = needed*Gl.nparts +X if Gl.bg <> (0, 0, 0): +X needed = needed+1 +X if Gl.fg <> (0, 0, 0): +X needed = needed+1 +X if Gl.doublebuffer: +X if needed > available(nplanes/2): +X Gl.doublebuffer = 0 +X if Gl.warnings: +X print 'not enough colors available', +X print 'for double buffer mode;', +X print 'forcing single buffer mode' +X else: +X nplanes = nplanes/2 +X if needed > available(nplanes): +X # Do this warning always +X print 'still not enough colors available;', +X print 'parts will be left white' +X print '(needed', needed, 'but have only', +X print available(nplanes), 'colors available)' +X # +X if Gl.doublebuffer: +X doublebuffer() +X gconfig() +X # +X if Gl.colormap: +X Gl.c3i = pseudo_c3i +X fixcolormap() +X else: +X Gl.c3i = c3i +X RGBmode() +X gconfig() +X # +X if Gl.fullscreen: +X # XXX Should find out true screen size using getgdesc() +X ortho2(-1.1*1.280, 1.1*1.280, -1.1*1.024, 1.1*1.024) +X else: +X ortho2(-1.1, 1.1, -1.1, 1.1) +X # +X return wid +X +Xdef available(nplanes): +X return pow(2, nplanes) - 1 # Reserve one pixel for black +X +Xdef fixcolormap(): +X multimap() +X gconfig() +X nplanes = getplanes() +X if Gl.warnings: +X print 'multimap mode has', nplanes, 'color planes' +X imap = Gl.colormap +X Gl.startindex = pow(2, nplanes) - 1 +X Gl.stopindex = 1 +X setmap(imap) +X mapcolor(0, 0, 0, 0) # Fixed entry for black +X if Gl.bg <> (0, 0, 0): +X r, g, b = Gl.bg +X mapcolor(1, r, g, b) # Fixed entry for Gl.bg +X Gl.stopindex = 2 +X if Gl.fg <> (0, 0, 0): +X r, g, b = Gl.fg +X mapcolor(2, r, g, b) # Fixed entry for Gl.fg +X Gl.stopindex = 3 +X Gl.overflow_seen = 0 +X resetindex() +X +Xdef resetindex(): +X Gl.index = Gl.startindex +X +Xr0g0b0 = (0, 0, 0) +X +Xdef pseudo_c3i(rgb): +X if rgb = r0g0b0: +X index = 0 +X elif rgb = Gl.bg: +X index = 1 +X elif rgb = Gl.fg: +X index = 2 +X else: +X index = definecolor(rgb) +X color(index) +X +Xdef definecolor(rgb): +X index = Gl.index +X if index < Gl.stopindex: +X if Gl.debug: print 'definecolor hard case', rgb +X # First see if we already have this one... +X for index in range(Gl.stopindex, Gl.startindex+1): +X if rgb = getmcolor(index): +X if Gl.debug: print 'return', index +X return index +X # Don't clobber reserverd colormap entries +X if not Gl.overflow_seen: +X # Shouldn't happen any more, hence no Gl.warnings test +X print 'mclock: out of colormap entries' +X Gl.overflow_seen = 1 +X return Gl.stopindex +X r, g, b = rgb +X if Gl.debug > 1: print 'mapcolor', (index, r, g, b) +X mapcolor(index, r, g, b) +X Gl.index = index - 1 +X return index +X +X# Compute n**i +Xdef pow(n, i): +X x = 1 +X for j in range(i): x = x*n +X return x +X +Xdef mouseclick(mouse, updown, x, y): +X if updown = 1: +X # mouse button came down, start tracking +X if Gl.debug: +X print 'mouse', mouse, 'down at', x, y +X if mouse = 2: +X Gl.mouse2down = 1 +X mouse2track(x, y) +X elif mouse = 3: +X Gl.mouse3down = 1 +X mouse3track(x, y) +X else: +X print 'fatal error' +X qdevice(MOUSEX) +X qdevice(MOUSEY) +X return 0 +X else: +X # mouse button came up, stop tracking +X if Gl.debug: +X print 'mouse', mouse, 'up at', x, y +X unqdevice(MOUSEX) +X unqdevice(MOUSEY) +X if mouse = 2: +X mouse2track(x, y) +X Gl.mouse2down = 0 +X elif mouse = 3: +X mouse3track(x, y) +X Gl.mouse3down = 0 +X else: +X print 'fatal error' +X Gl.alarm_set = 1 +X return 1 +X +Xdef mouse3track(x, y): +X # first compute polar coordinates from x and y +X cx, cy = Gl.ox + Gl.cx/2, Gl.oy + Gl.cy/2 +X x, y = x - cx, y - cy +X if (x, y) = (0, 0): return # would cause an exception +X minutes = int(30.5 + 30.0*math.atan2(float(-x), float(-y))/pi) +X if minutes = 60: minutes = 0 +X a,b = Gl.alarm_minutes/15, minutes/15 +X if (a,b) = (0,3): +X # Moved backward through 12 o'clock: +X Gl.alarm_hours = Gl.alarm_hours - 1 +X if Gl.alarm_hours < 0: Gl.alarm_hours = Gl.alarm_hours + 24 +X if (a,b) = (3,0): +X # Moved forward through 12 o'clock: +X Gl.alarm_hours = Gl.alarm_hours + 1 +X if Gl.alarm_hours >= 24: Gl.alarm_hours = Gl.alarm_hours - 24 +X Gl.alarm_minutes = minutes +X seconds = Gl.alarm_hours * HOUR + Gl.alarm_minutes * MINUTE +X if seconds <> Gl.alarm_time: +X draw_alarm(rgb_bg()) +X Gl.alarm_time = seconds +X draw_alarm(rgb_fg()) +X +Xdef mouse2track(x, y): +X # first compute polar coordinates from x and y +X cx, cy = Gl.ox + Gl.cx/2, Gl.oy + Gl.cy/2 +X x, y = x - cx, y - cy +X if (x, y) = (0, 0): return # would cause an exception +X hours = int(6.5 - float(Gl.alarm_minutes)/60.0 + 6.0*math.atan2(float(-x), float(-y))/pi) +X if hours = 12: hours = 0 +X if (Gl.alarm_hours,hours) = (0,11): +X # Moved backward through midnight: +X Gl.alarm_hours = 23 +X elif (Gl.alarm_hours,hours) = (12,11): +X # Moved backward through noon: +X Gl.alarm_hours = 11 +X elif (Gl.alarm_hours,hours) = (11,0): +X # Moved forward through noon: +X Gl.alarm_hours = 12 +X elif (Gl.alarm_hours,hours) = (23,0): +X # Moved forward through midnight: +X Gl.alarm_hours = 0 +X elif Gl.alarm_hours < 12: +X Gl.alarm_hours = hours +X else: +X Gl.alarm_hours = hours + 12 +X seconds = Gl.alarm_hours * HOUR + Gl.alarm_minutes * MINUTE +X if seconds <> Gl.alarm_time: +X draw_alarm(rgb_bg()) +X Gl.alarm_time = seconds +X draw_alarm(rgb_fg()) +X +Xdef initmenu(): +X Gl.pup = pup = newpup() +X addtopup(pup, 'M Clock%t|Alarm On/Off|Seconds Hand On/Off|Quit', 0) +X +Xdef handlemenu(): +X item = dopup(Gl.pup) +X if item = 1: +X # Toggle alarm +X if Gl.alarm_set: +X Gl.alarm_set = 0 +X Gl.alarm_on = 0 +X else: +X Gl.alarm_set = 1 +X Gl.change = 1 +X clearall() +X elif item = 2: +X # Toggle Seconds Hand +X if Gl.update = 1: +X Gl.update = 60 +X Gl.timernoise = 60 +X else: +X Gl.update = 1 +X Gl.timernoise = 6 +X Gl.change = 1 +X elif item = 3: +X if Gl.debug: print 'Exit' +X sys.exit(0) +X +Xmain() +EOF +chmod +x 'demo/sgi/gl/mclock.py' +fi +if test -s 'src/ceval.c' +then echo '*** I will not over-write existing file src/ceval.c' +else +echo 'x - src/ceval.c' +sed 's/^X//' > 'src/ceval.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Execute compiled code */ +X +X#include "allobjects.h" +X +X#include "import.h" +X#include "sysmodule.h" +X#include "compile.h" +X#include "frameobject.h" +X#include "ceval.h" +X#include "opcode.h" +X#include "bltinmodule.h" +X#include "traceback.h" +X +X#ifndef NDEBUG +X#define TRACE +X#endif +X +X#ifdef TRACE +Xstatic int +Xprtrace(v, str) +X object *v; +X char *str; +X{ +X printf("%s ", str); +X printobject(v, stdout, 0); +X printf("\n"); +X} +X#endif +X +Xstatic frameobject *current_frame; +X +Xobject * +Xgetlocals() +X{ +X if (current_frame == NULL) +X return NULL; +X else +X return current_frame->f_locals; +X} +X +Xobject * +Xgetglobals() +X{ +X if (current_frame == NULL) +X return NULL; +X else +X return current_frame->f_globals; +X} +X +Xvoid +Xprinttraceback(fp) +X FILE *fp; +X{ +X object *v = tb_fetch(); +X if (v != NULL) { +X fprintf(fp, "Stack backtrace (innermost last):\n"); +X tb_print(v, fp); +X DECREF(v); +X } +X} +X +X +X/* XXX Mixing "print ...," and direct file I/O on stdin/stdout +X XXX has some bad consequences. The needspace flag should +X XXX really be part of the file object. */ +X +Xstatic int needspace; +X +Xvoid +Xflushline() +X{ +X FILE *fp = sysgetfile("stdout", stdout); +X if (needspace) { +X fprintf(fp, "\n"); +X needspace = 0; +X } +X} +X +X +X/* Test a value used as condition, e.g., in a for or if statement */ +X +Xstatic int +Xtestbool(v) +X object *v; +X{ +X if (is_intobject(v)) +X return getintvalue(v) != 0; +X if (is_floatobject(v)) +X return getfloatvalue(v) != 0.0; +X if (v->ob_type->tp_as_sequence != NULL) +X return (*v->ob_type->tp_as_sequence->sq_length)(v) != 0; +X if (v->ob_type->tp_as_mapping != NULL) +X return (*v->ob_type->tp_as_mapping->mp_length)(v) != 0; +X if (v == None) +X return 0; +X /* All other objects are 'true' */ +X return 1; +X} +X +Xstatic object * +Xadd(v, w) +X object *v, *w; +X{ +X if (v->ob_type->tp_as_number != NULL) +X v = (*v->ob_type->tp_as_number->nb_add)(v, w); +X else if (v->ob_type->tp_as_sequence != NULL) +X v = (*v->ob_type->tp_as_sequence->sq_concat)(v, w); +X else { +X err_setstr(TypeError, "+ not supported by operands"); +X return NULL; +X } +X return v; +X} +X +Xstatic object * +Xsub(v, w) +X object *v, *w; +X{ +X if (v->ob_type->tp_as_number != NULL) +X return (*v->ob_type->tp_as_number->nb_subtract)(v, w); +X err_setstr(TypeError, "bad operand type(s) for -"); +X return NULL; +X} +X +Xstatic object * +Xmul(v, w) +X object *v, *w; +X{ +X typeobject *tp; +X if (is_intobject(v) && w->ob_type->tp_as_sequence != NULL) { +X /* int*sequence -- swap v and w */ +X object *tmp = v; +X v = w; +X w = tmp; +X } +X tp = v->ob_type; +X if (tp->tp_as_number != NULL) +X return (*tp->tp_as_number->nb_multiply)(v, w); +X if (tp->tp_as_sequence != NULL) { +X if (!is_intobject(w)) { +X err_setstr(TypeError, +X "can't multiply sequence with non-int"); +X return NULL; +X } +X if (tp->tp_as_sequence->sq_repeat == NULL) { +X err_setstr(TypeError, "sequence does not support *"); +X return NULL; +X } +X return (*tp->tp_as_sequence->sq_repeat) +X (v, (int)getintvalue(w)); +X } +X err_setstr(TypeError, "bad operand type(s) for *"); +X return NULL; +X} +X +Xstatic object * +Xdivide(v, w) +X object *v, *w; +X{ +X if (v->ob_type->tp_as_number != NULL) +X return (*v->ob_type->tp_as_number->nb_divide)(v, w); +X err_setstr(TypeError, "bad operand type(s) for /"); +X return NULL; +X} +X +Xstatic object * +Xrem(v, w) +X object *v, *w; +X{ +X if (v->ob_type->tp_as_number != NULL) +X return (*v->ob_type->tp_as_number->nb_remainder)(v, w); +X err_setstr(TypeError, "bad operand type(s) for %"); +X return NULL; +X} +X +Xstatic object * +Xneg(v) +X object *v; +X{ +X if (v->ob_type->tp_as_number != NULL) +X return (*v->ob_type->tp_as_number->nb_negative)(v); +X err_setstr(TypeError, "bad operand type(s) for unary -"); +X return NULL; +X} +X +Xstatic object * +Xpos(v) +X object *v; +X{ +X if (v->ob_type->tp_as_number != NULL) +X return (*v->ob_type->tp_as_number->nb_positive)(v); +X err_setstr(TypeError, "bad operand type(s) for unary +"); +X return NULL; +X} +X +Xstatic object * +Xnot(v) +X object *v; +X{ +X int outcome = testbool(v); +X object *w = outcome == 0 ? True : False; +X INCREF(w); +X return w; +X} +X +Xstatic object * +Xcall_builtin(func, arg) +X object *func; +X object *arg; +X{ +X if (is_methodobject(func)) { +X method meth = getmethod(func); +X object *self = getself(func); +X return (*meth)(self, arg); +X } +X if (is_classobject(func)) { +X if (arg != NULL) { +X err_setstr(TypeError, +X "classobject() allows no arguments"); +X return NULL; +X } +X return newclassmemberobject(func); +X } +X err_setstr(TypeError, "call of non-function"); +X return NULL; +X} +X +Xstatic object * +Xcall_function(func, arg) +X object *func; +X object *arg; +X{ +X object *newarg = NULL; +X object *newlocals, *newglobals; +X object *co, *v; +X +X if (is_classmethodobject(func)) { +X object *self = classmethodgetself(func); +X func = classmethodgetfunc(func); +X if (arg == NULL) { +X arg = self; +X } +X else { +X newarg = newtupleobject(2); +X if (newarg == NULL) +X return NULL; +X INCREF(self); +X INCREF(arg); +X settupleitem(newarg, 0, self); +X settupleitem(newarg, 1, arg); +X arg = newarg; +X } +X } +X else { +X if (!is_funcobject(func)) { +X err_setstr(TypeError, "call of non-function"); +X return NULL; +X } +X } +X +X co = getfunccode(func); +X if (co == NULL) { +X XDECREF(newarg); +X return NULL; +X } +X if (!is_codeobject(co)) { +X fprintf(stderr, "XXX Bad code\n"); +X abort(); +X } +X newlocals = newdictobject(); +X if (newlocals == NULL) { +X XDECREF(newarg); +X return NULL; +X } +X +X newglobals = getfuncglobals(func); +X INCREF(newglobals); +X +X v = eval_code((codeobject *)co, newglobals, newlocals, arg); +X +X DECREF(newlocals); +X DECREF(newglobals); +X +X XDECREF(newarg); +X +X return v; +X} +X +Xstatic object * +Xapply_subscript(v, w) +X object *v, *w; +X{ +X typeobject *tp = v->ob_type; +X if (tp->tp_as_sequence == NULL && tp->tp_as_mapping == NULL) { +X err_setstr(TypeError, "unsubscriptable object"); +X return NULL; +X } +X if (tp->tp_as_sequence != NULL) { +X int i; +X if (!is_intobject(w)) { +X err_setstr(TypeError, "sequence subscript not int"); +X return NULL; +X } +X i = getintvalue(w); +X return (*tp->tp_as_sequence->sq_item)(v, i); +X } +X return (*tp->tp_as_mapping->mp_subscript)(v, w); +X} +X +Xstatic object * +Xloop_subscript(v, w) +X object *v, *w; +X{ +X sequence_methods *sq = v->ob_type->tp_as_sequence; +X int i, n; +X if (sq == NULL) { +X err_setstr(TypeError, "loop over non-sequence"); +X return NULL; +X } +X i = getintvalue(w); +X n = (*sq->sq_length)(v); +X if (i >= n) +X return NULL; /* End of loop */ +X return (*sq->sq_item)(v, i); +X} +X +Xstatic int +Xslice_index(v, isize, pi) +X object *v; +X int isize; +X int *pi; +X{ +X if (v != NULL) { +X if (!is_intobject(v)) { +X err_setstr(TypeError, "slice index must be int"); +X return -1; +X } +X *pi = getintvalue(v); +X if (*pi < 0) +X *pi += isize; +X } +X return 0; +X} +X +Xstatic object * +Xapply_slice(u, v, w) /* return u[v:w] */ +X object *u, *v, *w; +X{ +X typeobject *tp = u->ob_type; +X int ilow, ihigh, isize; +X if (tp->tp_as_sequence == NULL) { +X err_setstr(TypeError, "only sequences can be sliced"); +X return NULL; +X } +X ilow = 0; +X isize = ihigh = (*tp->tp_as_sequence->sq_length)(u); +X if (slice_index(v, isize, &ilow) != 0) +X return NULL; +X if (slice_index(w, isize, &ihigh) != 0) +X return NULL; +X return (*tp->tp_as_sequence->sq_slice)(u, ilow, ihigh); +X} +X +Xstatic int +Xassign_subscript(w, key, v) /* w[key] = v */ +X object *w; +X object *key; +X object *v; +X{ +X typeobject *tp = w->ob_type; +X sequence_methods *sq; +X mapping_methods *mp; +X int (*func)(); +X if ((sq = tp->tp_as_sequence) != NULL && +X (func = sq->sq_ass_item) != NULL) { +X if (!is_intobject(key)) { +X err_setstr(TypeError, +X "sequence subscript must be integer"); +X return -1; +X } +X else +X return (*func)(w, (int)getintvalue(key), v); +X } +X else if ((mp = tp->tp_as_mapping) != NULL && +X (func = mp->mp_ass_subscript) != NULL) { +X return (*func)(w, key, v); +X } +X else { +X err_setstr(TypeError, +X "can't assign to this subscripted object"); +X return -1; +X } +X} +X +Xstatic int +Xassign_slice(u, v, w, x) /* u[v:w] = x */ +X object *u, *v, *w, *x; +X{ +X sequence_methods *sq = u->ob_type->tp_as_sequence; +X int ilow, ihigh, isize; +X if (sq == NULL) { +X err_setstr(TypeError, "assign to slice of non-sequence"); +X return -1; +X } +X if (sq == NULL || sq->sq_ass_slice == NULL) { +X err_setstr(TypeError, "unassignable slice"); +X return -1; +X } +X ilow = 0; +X isize = ihigh = (*sq->sq_length)(u); +X if (slice_index(v, isize, &ilow) != 0) +X return -1; +X if (slice_index(w, isize, &ihigh) != 0) +X return -1; +X return (*sq->sq_ass_slice)(u, ilow, ihigh, x); +X} +X +Xstatic int +Xcmp_exception(err, v) +X object *err, *v; +X{ +X if (is_tupleobject(v)) { +X int i, n; +X n = gettuplesize(v); +X for (i = 0; i < n; i++) { +X if (err == gettupleitem(v, i)) +X return 1; +X } +X return 0; +X } +X return err == v; +X} +X +Xstatic int +Xcmp_member(v, w) +X object *v, *w; +X{ +X int i, n, cmp; +X object *x; +X sequence_methods *sq; +X /* Special case for char in string */ +X if (is_stringobject(w)) { +X register char *s, *end; +X register char c; +X if (!is_stringobject(v) || getstringsize(v) != 1) { +X err_setstr(TypeError, +X "string member test needs char left operand"); +X return -1; +X } +X c = getstringvalue(v)[0]; +X s = getstringvalue(w); +X end = s + getstringsize(w); +X while (s < end) { +X if (c == *s++) +X return 1; +X } +X return 0; +X } +X sq = w->ob_type->tp_as_sequence; +X if (sq == NULL) { +X err_setstr(TypeError, +X "'in' or 'not in' needs sequence right argument"); +X return -1; +X } +X n = (*sq->sq_length)(w); +X for (i = 0; i < n; i++) { +X x = (*sq->sq_item)(w, i); +X cmp = cmpobject(v, x); +X XDECREF(x); +X if (cmp == 0) +X return 1; +X } +X return 0; +X} +X +Xstatic object * +Xcmp_outcome(op, v, w) +X enum cmp_op op; +X register object *v; +X register object *w; +X{ +X register int cmp; +X register int res = 0; +X switch (op) { +X case IS: +X case IS_NOT: +X res = (v == w); +X if (op == IS_NOT) +X res = !res; +X break; +X case IN: +X case NOT_IN: +X res = cmp_member(v, w); +X if (res < 0) +X return NULL; +X if (op == NOT_IN) +X res = !res; +X break; +X case EXC_MATCH: +X res = cmp_exception(v, w); +X break; +X default: +X cmp = cmpobject(v, w); +X switch (op) { +X case LT: res = cmp < 0; break; +X case LE: res = cmp <= 0; break; +X case EQ: res = cmp == 0; break; +X case NE: res = cmp != 0; break; +X case GT: res = cmp > 0; break; +X case GE: res = cmp >= 0; break; +X /* XXX no default? (res is initialized to 0 though) */ +X } +X } +X v = res ? True : False; +X INCREF(v); +X return v; +X} +X +Xstatic int +Ximport_from(locals, v, name) +X object *locals; +X object *v; +X char *name; +X{ +X object *w, *x; +X w = getmoduledict(v); +X if (name[0] == '*') { +X int i; +X int n = getdictsize(w); +X for (i = 0; i < n; i++) { +X name = getdictkey(w, i); +X if (name == NULL || name[0] == '_') +X continue; +X x = dictlookup(w, name); +X if (x == NULL) { +X /* XXX can't happen? */ +X err_setstr(NameError, name); +X return -1; +X } +X if (dictinsert(locals, name, x) != 0) +X return -1; +X } +X return 0; +X } +X else { +X x = dictlookup(w, name); +X if (x == NULL) { +X err_setstr(NameError, name); +X return -1; +X } +X else +X return dictinsert(locals, name, x); +X } +X} +X +Xstatic object * +Xbuild_class(v, w) +X object *v; /* None or tuple containing base classes */ +X object *w; /* dictionary */ +X{ +X if (is_tupleobject(v)) { +X int i; +X for (i = gettuplesize(v); --i >= 0; ) { +X object *x = gettupleitem(v, i); +X if (!is_classobject(x)) { +X err_setstr(TypeError, +X "base is not a class object"); +X return NULL; +X } +X } +X } +X else { +X v = NULL; +X } +X if (!is_dictobject(w)) { +X err_setstr(SystemError, "build_class with non-dictionary"); +X return NULL; +X } +X return newclassobject(v, w); +X} +X +X +X/* Status code for main loop (reason for stack unwind) */ +X +Xenum why_code { +X WHY_NOT, /* No error */ +X WHY_EXCEPTION, /* Exception occurred */ +X WHY_RERAISE, /* Exception re-raised by 'finally' */ +X WHY_RETURN, /* 'return' statement */ +X WHY_BREAK /* 'break' statement */ +X}; +X +X/* Interpreter main loop */ +X +Xobject * +Xeval_code(co, globals, locals, arg) +X codeobject *co; +X object *globals; +X object *locals; +X object *arg; +X{ +X register unsigned char *next_instr; +X register int opcode; /* Current opcode */ +X register int oparg; /* Current opcode argument, if any */ +X register object **stack_pointer; +X register enum why_code why; /* Reason for block stack unwind */ +X register int err; /* Error status -- nonzero if error */ +X register object *x; /* Result object -- NULL if error */ +X register object *v; /* Temporary objects popped off stack */ +X register object *w; +X register object *u; +X register object *t; +X register frameobject *f; /* Current frame */ +X int lineno; /* Current line number */ +X object *retval; /* Return value iff why == WHY_RETURN */ +X char *name; /* Name used by some instructions */ +X FILE *fp; /* Used by print operations */ +X#ifdef TRACE +X int trace = dictlookup(globals, "__trace__") != NULL; +X#endif +X +X/* Code access macros */ +X +X#define GETCONST(i) Getconst(f, i) +X#define GETNAME(i) Getname(f, i) +X#define FIRST_INSTR() (GETUSTRINGVALUE(f->f_code->co_code)) +X#define INSTR_OFFSET() (next_instr - FIRST_INSTR()) +X#define NEXTOP() (*next_instr++) +X#define NEXTARG() (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2]) +X#define JUMPTO(x) (next_instr = FIRST_INSTR() + (x)) +X#define JUMPBY(x) (next_instr += (x)) +X +X/* Stack manipulation macros */ +X +X#define STACK_LEVEL() (stack_pointer - f->f_valuestack) +X#define EMPTY() (STACK_LEVEL() == 0) +X#define TOP() (stack_pointer[-1]) +X#define BASIC_PUSH(v) (*stack_pointer++ = (v)) +X#define BASIC_POP() (*--stack_pointer) +X +X#ifdef TRACE +X#define PUSH(v) (BASIC_PUSH(v), trace && prtrace(TOP(), "push")) +X#define POP() (trace && prtrace(TOP(), "pop"), BASIC_POP()) +X#else +X#define PUSH(v) BASIC_PUSH(v) +X#define POP() BASIC_POP() +X#endif +X +X f = newframeobject( +X current_frame, /*back*/ +X co, /*code*/ +X globals, /*globals*/ +X locals, /*locals*/ +X 50, /*nvalues*/ +X 20); /*nblocks*/ +X if (f == NULL) +X return NULL; +X +X current_frame = f; +X +X next_instr = GETUSTRINGVALUE(f->f_code->co_code); +X +X stack_pointer = f->f_valuestack; +X +X if (arg != NULL) { +X INCREF(arg); +X PUSH(arg); +X } +X +X why = WHY_NOT; +X err = 0; +X x = None; /* Not a reference, just anything non-NULL */ +X lineno = -1; +X +X for (;;) { +X static ticker; +X +X /* Do periodic things */ +X +X if (--ticker < 0) { +X ticker = 100; +X if (intrcheck()) { +X err_set(KeyboardInterrupt); +X why = WHY_EXCEPTION; +X tb_here(f, INSTR_OFFSET(), lineno); +X break; +X } +X } +X +X /* Extract opcode and argument */ +X +X opcode = NEXTOP(); +X if (HAS_ARG(opcode)) +X oparg = NEXTARG(); +X +X#ifdef TRACE +X /* Instruction tracing */ +X +X if (trace) { +X if (HAS_ARG(opcode)) { +X printf("%d: %d, %d\n", +X (int) (INSTR_OFFSET() - 3), +X opcode, oparg); +X } +X else { +X printf("%d: %d\n", +X (int) (INSTR_OFFSET() - 1), opcode); +X } +X } +X#endif +X +X /* Main switch on opcode */ +X +X switch (opcode) { +X +X /* BEWARE! +X It is essential that any operation that fails sets either +X x to NULL, err to nonzero, or why to anything but WHY_NOT, +X and that no operation that succeeds does this! */ +X +X /* case STOP_CODE: this is an error! */ +X +X case POP_TOP: +X v = POP(); +X DECREF(v); +X break; +X +X case ROT_TWO: +X v = POP(); +X w = POP(); +X PUSH(v); +X PUSH(w); +X break; +X +X case ROT_THREE: +X v = POP(); +X w = POP(); +X x = POP(); +X PUSH(v); +X PUSH(x); +X PUSH(w); +X break; +X +X case DUP_TOP: +X v = TOP(); +X INCREF(v); +X PUSH(v); +X break; +X +X case UNARY_POSITIVE: +X v = POP(); +X x = pos(v); +X DECREF(v); +X PUSH(x); +X break; +X +X case UNARY_NEGATIVE: +X v = POP(); +X x = neg(v); +X DECREF(v); +X PUSH(x); +X break; +X +X case UNARY_NOT: +X v = POP(); +X x = not(v); +X DECREF(v); +X PUSH(x); +X break; +X +X case UNARY_CONVERT: +X v = POP(); +X x = reprobject(v); +X DECREF(v); +X PUSH(x); +X break; +X +X case UNARY_CALL: +X v = POP(); +X if (is_classmethodobject(v) || is_funcobject(v)) +X x = call_function(v, (object *)NULL); +X else +X x = call_builtin(v, (object *)NULL); +X DECREF(v); +X PUSH(x); +X break; +X +X case BINARY_MULTIPLY: +X w = POP(); +X v = POP(); +X x = mul(v, w); +X DECREF(v); +X DECREF(w); +X PUSH(x); +X break; +X +X case BINARY_DIVIDE: +X w = POP(); +X v = POP(); +X x = divide(v, w); +X DECREF(v); +X DECREF(w); +X PUSH(x); +X break; +X +X case BINARY_MODULO: +X w = POP(); +X v = POP(); +X x = rem(v, w); +X DECREF(v); +X DECREF(w); +X PUSH(x); +X break; +X +X case BINARY_ADD: +X w = POP(); +X v = POP(); +X x = add(v, w); +X DECREF(v); +X DECREF(w); +X PUSH(x); +X break; +X +X case BINARY_SUBTRACT: +X w = POP(); +X v = POP(); +X x = sub(v, w); +X DECREF(v); +X DECREF(w); +X PUSH(x); +X break; +X +X case BINARY_SUBSCR: +X w = POP(); +X v = POP(); +X x = apply_subscript(v, w); +X DECREF(v); +X DECREF(w); +X PUSH(x); +X break; +X +X case BINARY_CALL: +X w = POP(); +X v = POP(); +X if (is_classmethodobject(v) || is_funcobject(v)) +X x = call_function(v, w); +X else +X x = call_builtin(v, w); +X DECREF(v); +X DECREF(w); +X PUSH(x); +X break; +X +X case SLICE+0: +X case SLICE+1: +X case SLICE+2: +X case SLICE+3: +X if ((opcode-SLICE) & 2) +X w = POP(); +X else +X w = NULL; +X if ((opcode-SLICE) & 1) +X v = POP(); +X else +X v = NULL; +X u = POP(); +X x = apply_slice(u, v, w); +X DECREF(u); +X XDECREF(v); +X XDECREF(w); +X PUSH(x); +X break; +X +X case STORE_SLICE+0: +X case STORE_SLICE+1: +X case STORE_SLICE+2: +X case STORE_SLICE+3: +X if ((opcode-STORE_SLICE) & 2) +X w = POP(); +X else +X w = NULL; +X if ((opcode-STORE_SLICE) & 1) +X v = POP(); +X else +X v = NULL; +X u = POP(); +X t = POP(); +X err = assign_slice(u, v, w, t); /* u[v:w] = t */ +X DECREF(t); +X DECREF(u); +X XDECREF(v); +X XDECREF(w); +X break; +X +X case DELETE_SLICE+0: +X case DELETE_SLICE+1: +X case DELETE_SLICE+2: +X case DELETE_SLICE+3: +X if ((opcode-DELETE_SLICE) & 2) +X w = POP(); +X else +X w = NULL; +X if ((opcode-DELETE_SLICE) & 1) +X v = POP(); +X else +X v = NULL; +X u = POP(); +X err = assign_slice(u, v, w, (object *)NULL); +X /* del u[v:w] */ +X DECREF(u); +X XDECREF(v); +X XDECREF(w); +X break; +X +X case STORE_SUBSCR: +X w = POP(); +X v = POP(); +X u = POP(); +X /* v[w] = u */ +X err = assign_subscript(v, w, u); +X DECREF(u); +X DECREF(v); +X DECREF(w); +X break; +X +X case DELETE_SUBSCR: +X w = POP(); +X v = POP(); +X /* del v[w] */ +X err = assign_subscript(v, w, (object *)NULL); +X DECREF(v); +X DECREF(w); +X break; +X +X case PRINT_EXPR: +X v = POP(); +X fp = sysgetfile("stdout", stdout); +X /* Print value except if procedure result */ +X if (v != None) { +X flushline(); +X printobject(v, fp, 0); +X fprintf(fp, "\n"); +X } +X DECREF(v); +X break; +X +X case PRINT_ITEM: +X v = POP(); +X fp = sysgetfile("stdout", stdout); +X if (needspace) +X fprintf(fp, " "); +X if (is_stringobject(v)) { +X char *s = getstringvalue(v); +X int len = getstringsize(v); +X fwrite(s, 1, len, fp); +X if (len > 0 && s[len-1] == '\n') +X needspace = 0; +X else +X needspace = 1; +X } +X else { +X printobject(v, fp, 0); +X needspace = 1; +X } +X DECREF(v); +X break; +X +X case PRINT_NEWLINE: +X fp = sysgetfile("stdout", stdout); +X fprintf(fp, "\n"); +X needspace = 0; +X break; +X +X case BREAK_LOOP: +X why = WHY_BREAK; +X break; +X +X case RAISE_EXCEPTION: +X v = POP(); +X w = POP(); +X if (!is_stringobject(w)) +X err_setstr(TypeError, +X "exceptions must be strings"); +X else +X err_setval(w, v); +X DECREF(v); +X DECREF(w); +X why = WHY_EXCEPTION; +X break; +X +X case LOAD_LOCALS: +X v = f->f_locals; +X INCREF(v); +X PUSH(v); +X break; +X +X case RETURN_VALUE: +X retval = POP(); +X why = WHY_RETURN; +X break; +X +X case REQUIRE_ARGS: +X if (EMPTY()) { +X err_setstr(TypeError, +X "function expects argument(s)"); +X why = WHY_EXCEPTION; +X } +X break; +X +X case REFUSE_ARGS: +X if (!EMPTY()) { +X err_setstr(TypeError, +X "function expects no argument(s)"); +X why = WHY_EXCEPTION; +X } +X break; +X +X case BUILD_FUNCTION: +X v = POP(); +X x = newfuncobject(v, f->f_globals); +X DECREF(v); +X PUSH(x); +X break; +X +X case POP_BLOCK: +X { +X block *b = pop_block(f); +X while (STACK_LEVEL() > b->b_level) { +X v = POP(); +X DECREF(v); +X } +X } +X break; +X +X case END_FINALLY: +X v = POP(); +X if (is_intobject(v)) { +X why = (enum why_code) getintvalue(v); +X if (why == WHY_RETURN) +X retval = POP(); +X } +X else if (is_stringobject(v)) { +X w = POP(); +X err_setval(v, w); +X DECREF(w); +X w = POP(); +X tb_store(w); +X DECREF(w); +X why = WHY_RERAISE; +X } +X else if (v != None) { +X err_setstr(SystemError, +X "'finally' pops bad exception"); +X why = WHY_EXCEPTION; +X } +X DECREF(v); +X break; +X +X case BUILD_CLASS: +X w = POP(); +X v = POP(); +X x = build_class(v, w); +X PUSH(x); +X DECREF(v); +X DECREF(w); +X break; +X +X case STORE_NAME: +X name = GETNAME(oparg); +X v = POP(); +X err = dictinsert(f->f_locals, name, v); +X DECREF(v); +X break; +X +X case DELETE_NAME: +X name = GETNAME(oparg); +X if ((err = dictremove(f->f_locals, name)) != 0) +X err_setstr(NameError, name); +X break; +X +X case UNPACK_TUPLE: +X v = POP(); +X if (!is_tupleobject(v)) { +X err_setstr(TypeError, "unpack non-tuple"); +X why = WHY_EXCEPTION; +X } +X else if (gettuplesize(v) != oparg) { +X err_setstr(RuntimeError, +X "unpack tuple of wrong size"); +X why = WHY_EXCEPTION; +X } +X else { +X for (; --oparg >= 0; ) { +X w = gettupleitem(v, oparg); +X INCREF(w); +X PUSH(w); +X } +X } +X DECREF(v); +X break; +X +X case UNPACK_LIST: +X v = POP(); +X if (!is_listobject(v)) { +X err_setstr(TypeError, "unpack non-list"); +X why = WHY_EXCEPTION; +X } +X else if (getlistsize(v) != oparg) { +X err_setstr(RuntimeError, +X "unpack list of wrong size"); +X why = WHY_EXCEPTION; +X } +X else { +X for (; --oparg >= 0; ) { +X w = getlistitem(v, oparg); +X INCREF(w); +X PUSH(w); +X } +X } +X DECREF(v); +X break; +X +X case STORE_ATTR: +X name = GETNAME(oparg); +X v = POP(); +X u = POP(); +X err = setattr(v, name, u); /* v.name = u */ +X DECREF(v); +X DECREF(u); +X break; +X +X case DELETE_ATTR: +X name = GETNAME(oparg); +X v = POP(); +X err = setattr(v, name, (object *)NULL); +X /* del v.name */ +X DECREF(v); +X break; +X +X case LOAD_CONST: +X x = GETCONST(oparg); +X INCREF(x); +X PUSH(x); +X break; +X +X case LOAD_NAME: +X name = GETNAME(oparg); +X x = dictlookup(f->f_locals, name); +X if (x == NULL) { +X x = dictlookup(f->f_globals, name); +X if (x == NULL) +X x = getbuiltin(name); +X } +X if (x == NULL) +X err_setstr(NameError, name); +X else +X INCREF(x); +X PUSH(x); +X break; +X +X case BUILD_TUPLE: +X x = newtupleobject(oparg); +X if (x != NULL) { +X for (; --oparg >= 0;) { +X w = POP(); +X err = settupleitem(x, oparg, w); +X if (err != 0) +X break; +X } +X PUSH(x); +X } +X break; +X +X case BUILD_LIST: +X x = newlistobject(oparg); +X if (x != NULL) { +X for (; --oparg >= 0;) { +X w = POP(); +X err = setlistitem(x, oparg, w); +X if (err != 0) +X break; +X } +X PUSH(x); +X } +X break; +X +X case BUILD_MAP: +X x = newdictobject(); +X PUSH(x); +X break; +X +X case LOAD_ATTR: +X name = GETNAME(oparg); +X v = POP(); +X x = getattr(v, name); +X DECREF(v); +X PUSH(x); +X break; +X +X case COMPARE_OP: +X w = POP(); +X v = POP(); +X x = cmp_outcome((enum cmp_op)oparg, v, w); +X DECREF(v); +X DECREF(w); +X PUSH(x); +X break; +X +X case IMPORT_NAME: +X name = GETNAME(oparg); +X x = import_module(name); +X XINCREF(x); +X PUSH(x); +X break; +X +X case IMPORT_FROM: +X name = GETNAME(oparg); +X v = TOP(); +X err = import_from(f->f_locals, v, name); +X break; +X +X case JUMP_FORWARD: +X JUMPBY(oparg); +X break; +X +X case JUMP_IF_FALSE: +X if (!testbool(TOP())) +X JUMPBY(oparg); +X break; +X +X case JUMP_IF_TRUE: +X if (testbool(TOP())) +X JUMPBY(oparg); +X break; +X +X case JUMP_ABSOLUTE: +X JUMPTO(oparg); +X break; +X +X case FOR_LOOP: +X /* for v in s: ... +X On entry: stack contains s, i. +X On exit: stack contains s, i+1, s[i]; +X but if loop exhausted: +X s, i are popped, and we jump */ +X w = POP(); /* Loop index */ +X v = POP(); /* Sequence object */ +X u = loop_subscript(v, w); +X if (u != NULL) { +X PUSH(v); +X x = newintobject(getintvalue(w)+1); +X PUSH(x); +X DECREF(w); +X PUSH(u); +X } +X else { +X DECREF(v); +X DECREF(w); +X /* A NULL can mean "s exhausted" +X but also an error: */ +X if (err_occurred()) +X why = WHY_EXCEPTION; +X else +X JUMPBY(oparg); +X } +X break; +X +X case SETUP_LOOP: +X case SETUP_EXCEPT: +X case SETUP_FINALLY: +X setup_block(f, opcode, INSTR_OFFSET() + oparg, +X STACK_LEVEL()); +X break; +X +X case SET_LINENO: +X#ifdef TRACE +X if (trace) +X printf("--- Line %d ---\n", oparg); +X#endif +X lineno = oparg; +X break; +X +X default: +X fprintf(stderr, +X "XXX lineno: %d, opcode: %d\n", +X lineno, opcode); +X err_setstr(SystemError, "eval_code: unknown opcode"); +X why = WHY_EXCEPTION; +X break; +X +X } /* switch */ +X +X +X /* Quickly continue if no error occurred */ +X +X if (why == WHY_NOT) { +X if (err == 0 && x != NULL) +X continue; /* Normal, fast path */ +X why = WHY_EXCEPTION; +X x = None; +X err = 0; +X } +X +X#ifndef NDEBUG +X /* Double-check exception status */ +X +X if (why == WHY_EXCEPTION || why == WHY_RERAISE) { +X if (!err_occurred()) { +X fprintf(stderr, "XXX ghost error\n"); +X err_setstr(SystemError, "ghost error"); +X why = WHY_EXCEPTION; +X } +X } +X else { +X if (err_occurred()) { +X fprintf(stderr, "XXX undetected error\n"); +X why = WHY_EXCEPTION; +X } +X } +X#endif +X +X /* Log traceback info if this is a real exception */ +X +X if (why == WHY_EXCEPTION) { +X int lasti = INSTR_OFFSET() - 1; +X if (HAS_ARG(opcode)) +X lasti -= 2; +X tb_here(f, lasti, lineno); +X } +X +X /* For the rest, treat WHY_RERAISE as WHY_EXCEPTION */ +X +X if (why == WHY_RERAISE) +X why = WHY_EXCEPTION; +X +X /* Unwind stacks if a (pseudo) exception occurred */ +X +X while (why != WHY_NOT && f->f_iblock > 0) { +X block *b = pop_block(f); +X while (STACK_LEVEL() > b->b_level) { +X v = POP(); +X XDECREF(v); +X } +X if (b->b_type == SETUP_LOOP && why == WHY_BREAK) { +X why = WHY_NOT; +X JUMPTO(b->b_handler); +X break; +X } +X if (b->b_type == SETUP_FINALLY || +X b->b_type == SETUP_EXCEPT && +X why == WHY_EXCEPTION) { +X if (why == WHY_EXCEPTION) { +X object *exc, *val; +X err_get(&exc, &val); +X if (val == NULL) { +X val = None; +X INCREF(val); +X } +X v = tb_fetch(); +X /* Make the raw exception data +X available to the handler, +X so a program can emulate the +X Python main loop. Don't do +X this for 'finally'. */ +X if (b->b_type == SETUP_EXCEPT) { +X#if 0 /* Oops, this breaks too many things */ +X sysset("exc_traceback", v); +X#endif +X sysset("exc_value", val); +X sysset("exc_type", exc); +X err_clear(); +X } +X PUSH(v); +X PUSH(val); +X PUSH(exc); +X } +X else { +X if (why == WHY_RETURN) +X PUSH(retval); +X v = newintobject((long)why); +X PUSH(v); +X } +X why = WHY_NOT; +X JUMPTO(b->b_handler); +X break; +X } +X } /* unwind stack */ +X +X /* End the loop if we still have an error (or return) */ +X +X if (why != WHY_NOT) +X break; +X +X } /* main loop */ +X +X /* Pop remaining stack entries */ +X +X while (!EMPTY()) { +X v = POP(); +X XDECREF(v); +X } +X +X /* Restore previous frame and release the current one */ +X +X current_frame = f->f_back; +X DECREF(f); +X +X if (why == WHY_RETURN) +X return retval; +X else +X return NULL; +X} +EOF +fi +if test -s 'src/object.h' +then echo '*** I will not over-write existing file src/object.h' +else +echo 'x - src/object.h' +sed 's/^X//' > 'src/object.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X#define NDEBUG +X/* Object and type object interface */ +X +X/* +X123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 +X +XObjects are structures allocated on the heap. Special rules apply to +Xthe use of objects to ensure they are properly garbage-collected. +XObjects are never allocated statically or on the stack; they must be +Xaccessed through special macros and functions only. (Type objects are +Xexceptions to the first rule; the standard types are represented by +Xstatically initialized type objects.) +X +XAn object has a 'reference count' that is increased or decreased when a +Xpointer to the object is copied or deleted; when the reference count +Xreaches zero there are no references to the object left and it can be +Xremoved from the heap. +X +XAn object has a 'type' that determines what it represents and what kind +Xof data it contains. An object's type is fixed when it is created. +XTypes themselves are represented as objects; an object contains a +Xpointer to the corresponding type object. The type itself has a type +Xpointer pointing to the object representing the type 'type', which +Xcontains a pointer to itself!). +X +XObjects do not float around in memory; once allocated an object keeps +Xthe same size and address. Objects that must hold variable-size data +Xcan contain pointers to variable-size parts of the object. Not all +Xobjects of the same type have the same size; but the size cannot change +Xafter allocation. (These restrictions are made so a reference to an +Xobject can be simply a pointer -- moving an object would require +Xupdating all the pointers, and changing an object's size would require +Xmoving it if there was another object right next to it.) +X +XObjects are always accessed through pointers of the type 'object *'. +XThe type 'object' is a structure that only contains the reference count +Xand the type pointer. The actual memory allocated for an object +Xcontains other data that can only be accessed after casting the pointer +Xto a pointer to a longer structure type. This longer type must start +Xwith the reference count and type fields; the macro OB_HEAD should be +Xused for this (to accomodate for future changes). The implementation +Xof a particular object type can cast the object pointer to the proper +Xtype and back. +X +XA standard interface exists for objects that contain an array of items +Xwhose size is determined when the object is allocated. +X +X123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 +X*/ +X +X#ifndef NDEBUG +X +X/* Turn on heavy reference debugging */ +X#define TRACE_REFS +X +X/* Turn on reference counting */ +X#define REF_DEBUG +X +X#endif /* NDEBUG */ +X +X#ifdef TRACE_REFS +X#define OB_HEAD \ +X struct _object *_ob_next, *_ob_prev; \ +X int ob_refcnt; \ +X struct _typeobject *ob_type; +X#define OB_HEAD_INIT(type) 0, 0, 1, type, +X#else +X#define OB_HEAD \ +X unsigned int ob_refcnt; \ +X struct _typeobject *ob_type; +X#define OB_HEAD_INIT(type) 1, type, +X#endif +X +X#define OB_VARHEAD \ +X OB_HEAD \ +X unsigned int ob_size; /* Number of items in variable part */ +X +Xtypedef struct _object { +X OB_HEAD +X} object; +X +Xtypedef struct { +X OB_VARHEAD +X} varobject; +X +X +X/* +X123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 +X +XType objects contain a string containing the type name (to help somewhat +Xin debugging), the allocation parameters (see newobj() and newvarobj()), +Xand methods for accessing objects of the type. Methods are optional,a +Xnil pointer meaning that particular kind of access is not available for +Xthis type. The DECREF() macro uses the tp_dealloc method without +Xchecking for a nil pointer; it should always be implemented except if +Xthe implementation can guarantee that the reference count will never +Xreach zero (e.g., for type objects). +X +XNB: the methods for certain type groups are now contained in separate +Xmethod blocks. +X*/ +X +Xtypedef struct { +X object *(*nb_add) FPROTO((object *, object *)); +X object *(*nb_subtract) FPROTO((object *, object *)); +X object *(*nb_multiply) FPROTO((object *, object *)); +X object *(*nb_divide) FPROTO((object *, object *)); +X object *(*nb_remainder) FPROTO((object *, object *)); +X object *(*nb_power) FPROTO((object *, object *)); +X object *(*nb_negative) FPROTO((object *)); +X object *(*nb_positive) FPROTO((object *)); +X} number_methods; +X +Xtypedef struct { +X int (*sq_length) FPROTO((object *)); +X object *(*sq_concat) FPROTO((object *, object *)); +X object *(*sq_repeat) FPROTO((object *, int)); +X object *(*sq_item) FPROTO((object *, int)); +X object *(*sq_slice) FPROTO((object *, int, int)); +X int (*sq_ass_item) FPROTO((object *, int, object *)); +X int (*sq_ass_slice) FPROTO((object *, int, int, object *)); +X} sequence_methods; +X +Xtypedef struct { +X int (*mp_length) FPROTO((object *)); +X object *(*mp_subscript) FPROTO((object *, object *)); +X int (*mp_ass_subscript) FPROTO((object *, object *, object *)); +X} mapping_methods; +X +Xtypedef struct _typeobject { +X OB_VARHEAD +X char *tp_name; /* For printing */ +X unsigned int tp_basicsize, tp_itemsize; /* For allocation */ +X +X /* Methods to implement standard operations */ +X +X void (*tp_dealloc) FPROTO((object *)); +X void (*tp_print) FPROTO((object *, FILE *, int)); +X object *(*tp_getattr) FPROTO((object *, char *)); +X int (*tp_setattr) FPROTO((object *, char *, object *)); +X int (*tp_compare) FPROTO((object *, object *)); +X object *(*tp_repr) FPROTO((object *)); +X +X /* Method suites for standard classes */ +X +X number_methods *tp_as_number; +X sequence_methods *tp_as_sequence; +X mapping_methods *tp_as_mapping; +X} typeobject; +X +Xextern typeobject Typetype; /* The type of type objects */ +X +X#define is_typeobject(op) ((op)->ob_type == &Typetype) +X +X/* Generic operations on objects */ +Xextern void printobject PROTO((object *, FILE *, int)); +Xextern object * reprobject PROTO((object *)); +Xextern int cmpobject PROTO((object *, object *)); +Xextern object *getattr PROTO((object *, char *)); +Xextern int setattr PROTO((object *, char *, object *)); +X +X/* Flag bits for printing: */ +X#define PRINT_RAW 1 /* No string quotes etc. */ +X +X/* +X123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 +X +XThe macros INCREF(op) and DECREF(op) are used to increment or decrement +Xreference counts. DECREF calls the object's deallocator function; for +Xobjects that don't contain references to other objects or heap memory +Xthis can be the standard function free(). Both macros can be used +Xwhereever a void expression is allowed. The argument shouldn't be a +XNIL pointer. The macro NEWREF(op) is used only to initialize reference +Xcounts to 1; it is defined here for convenience. +X +XWe assume that the reference count field can never overflow; this can +Xbe proven when the size of the field is the same as the pointer size +Xbut even with a 16-bit reference count field it is pretty unlikely so +Xwe ignore the possibility. (If you are paranoid, make it a long.) +X +XType objects should never be deallocated; the type pointer in an object +Xis not considered to be a reference to the type object, to save +Xcomplications in the deallocation function. (This is actually a +Xdecision that's up to the implementer of each new type so if you want, +Xyou can count such references to the type object.) +X +X*** WARNING*** The DECREF macro must have a side-effect-free argument +Xsince it may evaluate its argument multiple times. (The alternative +Xwould be to mace it a proper function or assign it to a global temporary +Xvariable first, both of which are slower; and in a multi-threaded +Xenvironment the global variable trick is not safe.) +X*/ +X +X#ifdef TRACE_REFS +X#ifndef REF_DEBUG +X#define REF_DEBUG +X#endif +X#endif +X +X#ifndef TRACE_REFS +X#define DELREF(op) (*(op)->ob_type->tp_dealloc)((object *)(op)) +X#define UNREF(op) /*empty*/ +X#endif +X +X#ifdef REF_DEBUG +Xextern long ref_total; +X#ifndef TRACE_REFS +X#define NEWREF(op) (ref_total++, (op)->ob_refcnt = 1) +X#endif +X#define INCREF(op) (ref_total++, (op)->ob_refcnt++) +X#define DECREF(op) \ +X if (--ref_total, --(op)->ob_refcnt > 0) \ +X ; \ +X else \ +X DELREF(op) +X#else +X#define NEWREF(op) ((op)->ob_refcnt = 1) +X#define INCREF(op) ((op)->ob_refcnt++) +X#define DECREF(op) \ +X if (--(op)->ob_refcnt > 0) \ +X ; \ +X else \ +X DELREF(op) +X#endif +X +X/* Macros to use in case the object pointer may be NULL: */ +X +X#define XINCREF(op) if ((op) == NULL) ; else INCREF(op) +X#define XDECREF(op) if ((op) == NULL) ; else DECREF(op) +X +X/* Definition of NULL, so you don't have to include <stdio.h> */ +X +X#ifndef NULL +X#define NULL 0 +X#endif +X +X +X/* +XNoObject is an object of undefined type which can be used in contexts +Xwhere NULL (nil) is not suitable (since NULL often means 'error'). +X +XDon't forget to apply INCREF() when returning this value!!! +X*/ +X +Xextern object NoObject; /* Don't use this directly */ +X +X#define None (&NoObject) +X +X +X/* +X123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 +X +XMore conventions +X================ +X +XArgument Checking +X----------------- +X +XFunctions that take objects as arguments normally don't check for nil +Xarguments, but they do check the type of the argument, and return an +Xerror if the function doesn't apply to the type. +X +XFailure Modes +X------------- +X +XFunctions may fail for a variety of reasons, including running out of +Xmemory. This is communicated to the caller in two ways: an error string +Xis set (see errors.h), and the function result differs: functions that +Xnormally return a pointer return NULL for failure, functions returning +Xan integer return -1 (which could be a legal return value too!), and +Xother functions return 0 for success and -1 for failure. +XCallers should always check for errors before using the result. +X +XReference Counts +X---------------- +X +XIt takes a while to get used to the proper usage of reference counts. +X +XFunctions that create an object set the reference count to 1; such new +Xobjects must be stored somewhere or destroyed again with DECREF(). +XFunctions that 'store' objects such as settupleitem() and dictinsert() +Xdon't increment the reference count of the object, since the most +Xfrequent use is to store a fresh object. Functions that 'retrieve' +Xobjects such as gettupleitem() and dictlookup() also don't increment +Xthe reference count, since most frequently the object is only looked at +Xquickly. Thus, to retrieve an object and store it again, the caller +Xmust call INCREF() explicitly. +X +XNOTE: functions that 'consume' a reference count like dictinsert() even +Xconsume the reference if the object wasn't stored, to simplify error +Xhandling. +X +XIt seems attractive to make other functions that take an object as +Xargument consume a reference count; however this may quickly get +Xconfusing (even the current practice is already confusing). Consider +Xit carefully, it may safe lots of calls to INCREF() and DECREF() at +Xtimes. +X +X123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 +X*/ +EOF +fi +echo 'Part 07 out of 21 of pack.out complete.' +exit 0 diff --git a/shar/python-0.9.1-08-21.shar b/shar/python-0.9.1-08-21.shar new file mode 100644 index 0000000..7ac6f14 --- /dev/null +++ b/shar/python-0.9.1-08-21.shar @@ -0,0 +1,2349 @@ +: This is a shell archive. +: Extract with 'sh this_file'. +: +: Extract part 01 first since it makes all directories +echo 'Start of pack.out, part 08 out of 21:' +if test -s 'doc/mod1.tex' +then echo '*** I will not over-write existing file doc/mod1.tex' +else +echo 'x - doc/mod1.tex' +sed 's/^X//' > 'doc/mod1.tex' << 'EOF' +X\section{Introduction} +X +XThe {\Python} library consists of three parts, with different levels of +Xintegration with the interpreter. +XClosest to the interpreter are built-in types, exceptions and functions. +XNext are built-in modules, which are written in C and linked statically +Xwith the interpreter. +XFinally there are standard modules that are implemented entirely in +X{\Python}, but are always available. +XFor efficiency, some standard modules may become built-in modules in +Xfuture versions of the interpreter. +X +X\section{Built-in Types, Exceptions and Functions} +X +XNames for built-in exceptions and functions are found in a separate +Xread-only symbol table which cannot be modified. +XThis table is searched last, so local and global user-defined names can +Xoverride built-in names. +XBuilt-in types have no names but are created by syntactic constructs +X(such as constants) or built-in functions. +XThey are described together here for easy reference.% +X\footnote{ +XThe descriptions sorely lack explanations of the exceptions that +Xmay be raised---this will be fixed in a future version of this +Xdocument. +X} +X +X\subsection{Built-in Types} +X +XThe following sections describe the standard types that are built into the +Xinterpreter. +X\subsubsection{Numeric Types} +X +XThere are two numeric types: integers and floating point numbers. +XIntegers are implemented using {\tt long} in C, so they have at least 32 +Xbits of precision. +XFloating point numbers are implemented using {\tt double} in C. +XAll bets on precision are off. +XNumbers are created by numeric constants or as the result of built-in +Xfunctions and operators. +X +XNumeric types support the following operations: +X +X\begin{center} +X\begin{tabular}{|c|l|c|} +X\hline +XOperation & Result & Notes \\ +X\hline +X{\tt abs}({\em x}) & absolute value of {\em x} & \\ +X{\tt int}({\em x}) & {\em x} converted to integer & (1) \\ +X{\tt float}({\em x}) & {\em x} converted to floating point & \\ +X{\tt -}{\em x} & {\em x} negated & \\ +X{\tt +}{\em x} & {\em x} unchanged & \\ +X{\em x}{\tt +}{\em y} & sum of {\em x} and {\em y} & \\ +X{\em x}{\tt -}{\em y} & difference of {\em x} and {\em y} & \\ +X{\em x}{\tt *}{\em y} & product of {\em x} and {\em y} & \\ +X{\em x}{\tt /}{\em y} & quotient of {\em x} and {\em y} & (2) \\ +X{\em x}{\tt \%}{\em y} & remainder of {\em x}{\tt /}{\em y} & (3) \\ +X\hline +X\end{tabular} +X\end{center} +X +X\noindent +XNotes: +X\begin{description} +X\item[(1)] +XThis may round or truncate as in C; see functions {\tt floor} and +X{\tt ceil} in module {\tt math}. +X\item[(2)] +XInteger division is defined as in C: the result is an integer; with +Xpositive operands, it truncates towards zero; with a negative operand, +Xthe result is unspecified. +X\item[(3)] +XOnly defined for integers. +X\end{description} +X +XMixed arithmetic is not supported; both operands must have the same type. +XMixed comparisons return the wrong result (floats always compare smaller +Xthan integers).% +X\footnote{ +XThese restrictions are bugs in the language definitions and will be +Xfixed in the future. +X} +X\subsubsection{Sequence Types} +X +XThere are three sequence types: strings, lists and tuples. +XStrings constants are written in single quotes: {\tt 'xyzzy'}. +XLists are constructed with square brackets: {\tt [a,~b,~c]}. +XTuples are constructed by the comma operator or with an empty set of +Xparentheses: {\tt a,~b,~c} or {\tt ()}. +X +XSequence types support the following operations ({\em s} and {\em t} are +Xsequences of the same type; {\em n}, {\em i} and {\em j} are integers): +X +X\begin{center} +X\begin{tabular}{|c|l|c|} +X\hline +XOperation & Result & Notes \\ +X\hline +X{\tt len}({\em s}) & length of {\em s} & \\ +X{\tt min}({\em s}) & smallest item of {\em s} & \\ +X{\tt max}({\em s}) & largest item of {\em s} & \\ +X{\em x} {\tt in} {\em s} & +X true if an item of {\em s} is equal to {\em x} & \\ +X{\em x} {\tt not} {\tt in} {\em s} & +X false if an item of {\em s} is equal to {\em x} & \\ +X{\em s}{\tt +}{\em t} & the concatenation of {\em s} and {\em t} & \\ +X{\em s}{\tt *}{\em n}, {\em n}*{\em s} & +X {\em n} copies of {\em s} concatenated & (1) \\ +X{\em s}[{\em i}] & {\em i}'th item of {\em s} & \\ +X{\em s}[{\em i}:{\em j}] & +X slice of {\em s} from {\em i} to {\em j} & (2) \\ +X\hline +X\end{tabular} +X\end{center} +X +X\noindent +XNotes: +X\begin{description} +X\item[(1)] +XSequence repetition is only supported for strings. +X\item[(2)] +XThe slice of $s$ from $i$ to $j$ is defined as the sequence +Xof items with index $k$ such that $i \leq k < j$. +XSpecial rules apply for negative and omitted indices; see the Tutorial +Xor the Reference Manual. +X\end{description} +X +X\paragraph{Mutable Sequence Types.} +X +XList objects support additional operations that allow in-place +Xmodification of the object. +XThese operations would be supported by other mutable sequence types +X(when added to the language) as well. +XStrings and tuples are immutable sequence types and such objects cannot +Xbe modified once created. +XThe following operations are defined on mutable sequence types (where +X{\em x} is an arbitrary object): +X +X\begin{center} +X\begin{tabular}{|c|l|} +X\hline +XOperation & Result \\ +X\hline +X{\em s}[{\em i}] = {\em x} & +X item {\em i} of {\em s} is replaced by {\em x} \\ +X{\em s}[{\em i}:{\em j}] = {\em t} & +X slice of {\em s} from {\em i} to {\em j} is replaced by {\em t} \\ +X{\tt del} {\em s}[{\em i}:{\em j}] & +X same as {\em s}[{\em i}:{\em j}] = [] \\ +X{\em s}.{\tt append}({\em x}) & +X same as {\em s}[{\tt len}({\em x}):{\tt len}({\em x})] = [{\em x}] \\ +X{\em s}.{\tt insert}({\em i}, {\em x}) & +X same as {\em s}[{\em i}:{\em i}] = [{\em x}] \\ +X{\em s}.{\tt sort}() & +X the items of {\em s} are permuted to satisfy \\ +X & +X $s[i] \leq s[j]$ for $i < j$\\ +X\hline +X\end{tabular} +X\end{center} +X +X\subsubsection{Mapping Types} +X +XA +X{\em mapping} +Xobject maps values of one type (the key type) to arbitrary objects. +XMappings are mutable objects. +XThere is currently only one mapping type, the +X{\em dictionary}. +XA dictionary's keys are strings. +XAn empty dictionary is created by the expression \verb"{}". +XAn extension of this notation is used to display dictionaries when +Xwritten (see the example below). +X +XThe following operations are defined on mappings (where {\em a} is a +Xmapping, {\em k} is a key and {\em x} is an arbitrary object): +X +X\begin{center} +X\begin{tabular}{|c|l|c|} +X\hline +XOperation & Result & Notes\\ +X\hline +X{\tt len}({\em a}) & the number of elements in {\em a} & \\ +X{\em a}[{\em k}] & the item of {\em a} with key {\em k} & \\ +X{\em a}[{\em k}] = {\em x} & set {\em a}[{\em k}] to {\em x} & \\ +X{\tt del} {\em a}[{\em k}] & remove {\em a}[{\em k}] from {\em a} & \\ +X{\em a}.{\tt keys}() & a copy of {\em a}'s list of keys & (1) \\ +X{\em a}.{\tt has\_key}({\em k}) & true if {\em a} has a key {\em k} & \\ +X\hline +X\end{tabular} +X\end{center} +X +X\noindent +XNotes: +X\begin{description} +X\item[(1)] +XKeys are listed in random order. +X\end{description} +X +XA small example using a dictionary: +X\bcode\begin{verbatim} +X>>> tel = {} +X>>> tel['jack'] = 4098 +X>>> tel['sape'] = 4139 +X>>> tel['guido'] = 4127 +X>>> tel['jack'] +X4098 +X>>> tel +X{'sape': 4139; 'guido': 4127; 'jack': 4098} +X>>> del tel['sape'] +X>>> tel['irv'] = 4127 +X>>> tel +X{'guido': 4127; 'irv': 4127; 'jack': 4098} +X>>> tel.keys() +X['guido', 'irv', 'jack'] +X>>> tel.has_key('guido') +X1 +X>>> +X\end{verbatim}\ecode +X\subsubsection{Other Built-in Types} +X +XThe interpreter supports several other kinds of objects. +XMost of these support only one or two operations. +X +X\paragraph{Modules.} +X +XThe only operation on a module is member acces: {\em m}{\tt .}{\em name}, +Xwhere {\em m} is a module and {\em name} accesses a name defined in +X{\em m}'s symbol table. +XModule members can be assigned to. +X +X\paragraph{Classes and Class Objects.} +X +XXXX Classes will be explained at length in a later version of this +Xdocument. +X +X\paragraph{Functions.} +X +XFunction objects are created by function definitions. +XThe only operation on a function object is to call it: +X{\em func}({\em optional-arguments}). +X +XBuilt-in functions have a different type than user-defined functions, +Xbut they support the same operation. +X +X\paragraph{Methods.} +X +XMethods are functions that are called using the member acces notation. +XThere are two flavors: built-in methods (such as {\tt append()} on +Xlists) and class member methods. +XBuilt-in methods are described with the types that support them. +XXXX Class member methods will be described in a later version of this +Xdocument. +X +X\paragraph{Type Objects.} +X +XType objects represent the various object types. +XAn object's type is accessed by the built-in function +X{\tt type()}. +XThere are no operations on type objects. +X +X\paragraph{The Null Object.} +X +XThis object is returned by functions that don't explicitly return a +Xvalue. +XIt supports no operations. +XThere is exactly one null object, named {\tt None} +X(a built-in name). +X +X\paragraph{File Objects.} +X +XFile objects are implemented using C's +X{\em stdio} +Xpackage and can be created with the built-in function +X{\tt open()}. +XThey have the following methods: +X\begin{description} +X\funcitem{close}{} +XCloses the file. +XA closed file cannot be read or written anymore. +X\funcitem{read}{size} +XReads at most +X{\tt size} +Xbytes from the file (less if the read hits EOF). +XThe bytes are returned as a string object. +XAn empty string is returned when EOF is hit immediately. +X(For certain files, like ttys, it makes sense to continue reading after +Xan EOF is hit.) +X\funcitem{readline}{size} +XReads a line of at most +X{\tt size} +Xbytes from the file. +XA trailing newline character, if present, is kept in the string. +XThe size is optional and defaults to a large number (but not infinity). +XEOF is reported as by +X{\tt read().} +X\funcitem{write}{str} +XWrites a string to the file. +XReturns no value. +X\end{description} +X +X\subsection{Built-in Exceptions} +X +XThe following exceptions can be generated by the interpreter or +Xbuilt-in functions. +XExcept where mentioned, they have a string argument (also known as the +X`associated value' of an exception) indicating the detailed cause of the +Xerror. +XThe strings listed with the exception names are their values when used +Xin an expression or printed. +X\begin{description} +X\excitem{EOFError}{end-of-file read} +X(No argument.) +XRaised when a built-in function ({\tt input()} or {\tt raw\_input()}) +Xhits an end-of-file condition (EOF) without reading any data. +X(N.B.: the {\tt read()} and {\tt readline()} methods of file objects +Xreturn an empty string when they hit EOF.) +X\excitem{KeyboardInterrupt}{end-of-file read} +X(No argument.) +XRaised when the user hits the interrupt key (normally Control-C or DEL). +XDuring execution, a check for interrupts is made regularly. +XInterrupts typed when a built-in function ({\tt input()} or +X{\tt raw\_input()}) is waiting for input also raise this exception. +X\excitem{MemoryError}{out of memory} +X%.br +XRaised when an operation runs out of memory but the situation +Xmay still be rescued (by deleting some objects). +X\excitem{NameError}{undefined name} +X%.br +XRaised when a name is not found. +XThis applies to unqualified names, module names (on {\tt import}), +Xmodule members and object methods. +XThe string argument is the name that could not be found. +X\excitem{RuntimeError}{run-time error} +X%.br +XRaised for a variety of reasons, e.g., division by zero or index out of +Xrange. +X\excitem{SystemError}{system error} +X%.br +XRaised when the interpreter finds an internal error, but the situation +Xdoes not look so serious to cause it to abandon all hope. +X\excitem{TypeError}{type error} +X%.br +XRaised when an operation or built-in function is applied to an object of +Xinappropriate type. +X\end{description} +X +X\subsection{Built-in Functions} +X +XThe {\Python} interpreter has a small number of functions built into it that +Xare always available. +XThey are listed here in alphabetical order. +X\begin{description} +X\funcitem{abs}{x} +XReturns the absolute value of a number. +XThe argument may be an integer or floating point number. +X\funcitem{chr}{i} +XReturns a string of one character +Xwhose ASCII code is the integer {\tt i}, +Xe.g., {\tt chr(97)} returns the string {\tt 'a'}. +XThis is the inverse of {\tt ord()}. +X\funcitem{dir}{} +XWithout arguments, this function returns the list of names in the +Xcurrent local symbol table, sorted alphabetically. +XWith a module object as argument, it returns the sorted list of names in +Xthat module's global symbol table. +XFor example: +X\bcode\begin{verbatim} +X>>> import sys +X>>> dir() +X['sys'] +X>>> dir(sys) +X['argv', 'exit', 'modules', 'path', 'stderr', 'stdin', 'stdout'] +X>>> +X\end{verbatim}\ecode +X\funcitem{divmod}{a, b} +X%.br +XTakes two integers as arguments and returns a pair of integers +Xconsisting of their quotient and remainder. +XFor +X\bcode\begin{verbatim} +Xq, r = divmod(a, b) +X\end{verbatim}\ecode +Xthe invariants are: +X\bcode\begin{verbatim} +Xa = q*b + r +Xabs(r) < abs(b) +Xr has the same sign as b +X\end{verbatim}\ecode +XFor example: +X\bcode\begin{verbatim} +X>>> divmod(100, 7) +X(14, 2) +X>>> divmod(-100, 7) +X(-15, 5) +X>>> divmod(100, -7) +X(-15, -5) +X>>> divmod(-100, -7) +X(14, -2) +X>>> +X\end{verbatim}\ecode +X\funcitem{eval}{s} +XTakes a string as argument and parses and evaluates it as a {\Python} +Xexpression. +XThe expression is executed using the current local and global symbol +Xtables. +XSyntax errors are reported as exceptions. +XFor example: +X\bcode\begin{verbatim} +X>>> x = 1 +X>>> eval('x+1') +X2 +X>>> +X\end{verbatim}\ecode +X\funcitem{exec}{s} +XTakes a string as argument and parses and evaluates it as a sequence of +X{\Python} statements. +XThe string should end with a newline (\verb"'\n'"). +XThe statement is executed using the current local and global symbol +Xtables. +XSyntax errors are reported as exceptions. +XFor example: +X\bcode\begin{verbatim} +X>>> x = 1 +X>>> exec('x = x+1\n') +X>>> x +X2 +X>>> +X\end{verbatim}\ecode +X\funcitem{float}{x} +XConverts a number to floating point. +XThe argument may be an integer or floating point number. +X\funcitem{input}{s} +XEquivalent to +X{\tt eval(raw\_input(s))}. +XAs for +X{\tt raw\_input()}, +Xthe argument is optional. +X\funcitem{int}{x} +XConverts a number to integer. +XThe argument may be an integer or floating point number. +X\funcitem{len}{s} +XReturns the length (the number of items) of an object. +XThe argument may be a sequence (string, tuple or list) or a mapping +X(dictionary). +X\funcitem{max}{s} +XReturns the largest item of a non-empty sequence (string, tuple or list). +X\funcitem{min}{s} +XReturns the smallest item of a non-empty sequence (string, tuple or list). +X\funcitem{open}{name, mode} +X%.br +XReturns a file object (described earlier under Built-in Types). +XThe string arguments are the same as for stdio's +X{\tt fopen()}: +X{\tt 'r'} +Xopens the file for reading, +X{\tt 'w'} +Xopens it for writing (truncating an existing file), +X{\tt 'a'} +Xopens it for appending.% +X\footnote{ +XThis function should go into a built-in module +X{\tt io}. +X} +X\funcitem{ord}{c} +XTakes a string of one character and returns its +XASCII value, e.g., {\tt ord('a')} returns the integer {\tt 97}. +XThis is the inverse of {\tt chr()}. +X\funcitem{range}{} +XThis is a versatile function to create lists containing arithmetic +Xprogressions of integers. +XWith two integer arguments, it returns the ascending sequence of +Xintegers starting at the first and ending one before the second +Xargument. +XA single argument is used as the end point of the sequence, with 0 used +Xas the starting point. +XA third argument specifies the step size; negative steps are allowed and +Xwork as expected, but don't specify a zero step. +XThe resulting list may be empty. +XFor example: +X\bcode\begin{verbatim} +X>>> range(10) +X[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +X>>> range(1, 1+10) +X[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +X>>> range(0, 30, 5) +X[0, 5, 10, 15, 20, 25] +X>>> range(0, 10, 3) +X[0, 3, 6, 9] +X>>> range(0, -10, -1) +X[0, -1, -2, -3, -4, -5, -6, -7, -8, -9] +X>>> range(0) +X[] +X>>> range(1, 0) +X[] +X>>> +X\end{verbatim}\ecode +X\funcitem{raw\_input}{s} +X%.br +XThe argument is optional; if present, it is written to standard output +Xwithout a trailing newline. +XThe function then reads a line from input, converts it to a string +X(stripping a trailing newline), and returns that. +XEOF is reported as an exception. +XFor example: +X\bcode\begin{verbatim} +X>>> raw_input('Type anything: ') +XType anything: Mutant Teenage Ninja Turtles +X'Mutant Teenage Ninja Turtles' +X>>> +X\end{verbatim}\ecode +X\funcitem{reload}{module} +XCauses an already imported module to be re-parsed and re-initialized. +XThis is useful if you have edited the module source file and want to +Xtry out the new version without leaving {\Python}. +X\funcitem{type}{x} +XReturns the type of an object. +XTypes are objects themselves: +Xthe type of a type object is its own type. +X\end{description} +EOF +fi +if test -s 'src/Makefile' +then echo '*** I will not over-write existing file src/Makefile' +else +echo 'x - src/Makefile' +sed 's/^X//' > 'src/Makefile' << 'EOF' +X# /*********************************************************** +X# Copyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +X# Netherlands. +X# +X# All Rights Reserved +X# +X# Permission to use, copy, modify, and distribute this software and its +X# documentation for any purpose and without fee is hereby granted, +X# provided that the above copyright notice appear in all copies and that +X# both that copyright notice and this permission notice appear in +X# supporting documentation, and that the names of Stichting Mathematisch +X# Centrum or CWI not be used in advertising or publicity pertaining to +X# distribution of the software without specific, written prior permission. +X# +X# STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +X# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +X# FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +X# FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +X# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +X# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +X# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X# +X# ******************************************************************/ +X +X# Makefile for Python +X# =================== +X# +X# If you are in a hurry, you can just edit this Makefile to choose the +X# correct settings for SYSV and RANLIB below, and type "make" in this +X# directory. If you are using a recent version of SunOS (or Ultrix?) +X# you don't even have to edit: the Makefile comes pre-configured for +X# such systems with all configurable options turned off, building the +X# minimal portable version of the Python interpreter. +X# +X# If have more time, read the section on configurable options below. +X# It may still be wise to begin building the minimal portable Python, +X# to see if it works at all, and select options later. You don't have +X# to rebuild all objects when you turn on options; all dependencies +X# are concentrated in the file "config.c" which is rebuilt whenever +X# the Makefile changes. (Except if you turn on the GNU Readline option +X# you may have to toss out the tokenizer.o object.) +X +X +X# Operating System Defines (ALWAYS READ THIS) +X# =========================================== +X +X# Uncomment the following line if you are using a System V derivative. +X# This must be used, for instance, on an SGI IRIS. Don't use it for +X# SunOS. (This is only needed by posixmodule.c...) +X +X#SYSVDEF= -DSYSV +X +X# Choose one of the following two lines depending on whether your system +X# requires the use of 'ranlib' after creating a library, or not. +X +X#RANLIB = true # For System V +XRANLIB = ranlib # For BSD +X +X# If your system doesn't have symbolic links, uncomment the following +X# line. +X +X#NOSYMLINKDEF= -DNO_LSTAT +X +X +X# Installation Options +X# ==================== +X +X# You may want to change PYTHONPATH to reflect where you install the +X# Python module library. +X +XPYTHONPATH= .:/usr/local/lib/python:/ufs/guido/lib/python +X +X +X# For "Pure" BSD Systems +X# ====================== +X# +X# "Pure" BSD systems (as opposed to enhanced BSD derivatives like SunOS) +X# often miss certain standard library functions. Source for +X# these is provided, you just have to turn it on. This may work for +X# other systems as well, where these things are needed. +X +X# If your system does not have a strerror() function in the library, +X# uncomment the following two lines to use one I wrote. (Actually, this +X# is missing in most systems I have encountered, so it is turned on +X# in the Makefile. Turn it off if your system doesn't have sys_errlist.) +X +XSTRERROR_SRC= strerror.c +XSTRERROR_OBJ= strerror.o +X +X# If your BSD system does not have a fmod() function in the library, +X# uncomment the following two lines to use one I wrote. +X +X#FMOD_SRC= fmod.c +X#FMOD_OBJ= fmod.o +X +X# If your BSD system does not have a strtol() function in the library, +X# uncomment the following two lines to use one I wrote. +X +X#STRTOL_SRC= strtol.c +X#STRTOL_OBJ= strtol.o +X +X# If your BSD system does not have a getcwd() function in the library, +X# but it does have a getwd() function, uncomment the following two lines +X# to use one I wrote. (If you don't have getwd() either, turn on the +X# NO_GETWD #define in getcwd.c.) +X +X#GETCWD_SRC= getcwd.c +X#GETCWD_OBJ= getcwd.o +X +X# If your signal() function believes signal handlers return int, +X# uncomment the following line. +X +X#SIGTYPEDEF= -DSIGTYPE=int +X +X +X# Further porting hints +X# ===================== +X# +X# If you don't have the header file <string.h>, but you do have +X# <strings.h>, create a file "string.h" in this directory which contains +X# the single line "#include <strings.h>", and add "-I." to CFLAGS. +X# If you don't have the functions strchr and strrchr, add definitions +X# "-Dstrchr=index -Dstrrchr=rindex" to CFLAGS. (NB: CFLAGS is not +X# defined in this Makefile.) +X +X +X# Configurable Options +X# ==================== +X# +X# Python can be configured to interface to various system libraries that +X# are not available on all systems. It is also possible to configure +X# the input module to use the GNU Readline library for interactive +X# input. For each configuration choice you must uncomment the relevant +X# section of the Makefile below. Note: you may also have to change a +X# pathname and/or an architecture identifier that is hardcoded in the +X# Makefile. +X# +X# Read the comments to determine if you can use the option. (You can +X# always leave all options off and build a minimal portable version of +X# Python.) +X +X +X# BSD Time Option +X# =============== +X# +X# This option does not add a new module but adds two functions to +X# an existing module. +X# +X# It implements time.millisleep() and time.millitimer() +X# using the BSD system calls select() and gettimeofday(). +X# +X# Uncomment the following line to select this option. +X +X#BSDTIMEDEF= -DBSD_TIME +X +X +X# GNU Readline Option +X# =================== +X# +X# If you have the sources of the GNU Readline library you can have +X# full interactive command line editing and history in Python. +X# The GNU Readline library is distributed with the BASH shell +X# (I only know of version 1.05). You must build the GNU Readline +X# library and the alloca routine it needs in their own source +X# directories (which are subdirectories of the basg source directory), +X# and plant a pointer to the BASH source directory in this Makefile. +X# +X# Uncomment and edit the following block to use the GNU Readline option. +X# - Edit the definition of BASHDIR to point to the bash source tree. +X# You may have to fix the definition of LIBTERMCAP; leave the LIBALLOCA +X# definition commented if alloca() is in your C library. +X +X#BASHDIR= ../../bash-1.05 +X#LIBREADLINE= $(BASHDIR)/readline/libreadline.a +X#LIBALLOCA= $(BASHDIR)/alloc-files/alloca.o +X#LIBTERMCAP= -ltermcap +X#RL_USE = -DUSE_READLINE +X#RL_LIBS= $(LIBREADLINE) $(LIBALLOCA) $(LIBTERMCAP) +X#RL_LIBDEPS= $(LIBREADLINE) $(LIBALLOCA) +X +X +X# STDWIN Option +X# ============= +X# +X# If you have the sources of STDWIN (by the same author) you can +X# configure Python to incorporate the built-in module 'stdwin'. +X# This requires a fairly recent version of STDWIN (dated late 1990). +X# +X# Uncomment and edit the following block to use the STDWIN option. +X# - Edit the STDWINDIR defition to reflect the top of the STDWIN source +X# tree. +X# - Edit the ARCH definition to reflect your system's architecture +X# (usually the program 'arch' or 'machine' returns this). +X# You may have to edit the LIBX11 defition to reflect the location of +X# the X11 runtime library if it is non-standard. +X +X#STDWINDIR= ../../stdwin +X#ARCH= sgi +X#LIBSTDWIN= $(STDWINDIR)/Build/$(ARCH)/x11/lib/lib.a +X#LIBX11 = -lX11 +X#STDW_INCL= -I$(STDWINDIR)/H +X#STDW_USE= -DUSE_STDWIN +X#STDW_LIBS= $(LIBSTDWIN) $(LIBX11) +X#STDW_LIBDEPS= $(LIBSTDWIN) +X#STDW_SRC= stdwinmodule.c +X#STDW_OBJ= stdwinmodule.o +X +X +X# Amoeba Option +X# ============= +X# +X# If you have the Amoeba 4.0 distribution (Beta or otherwise) you can +X# configure Python to incorporate the built-in module 'amoeba'. +X# (Python can also be built for native Amoeba, but it requires more +X# work and thought. Contact the author.) +X# +X# Uncomment and edit the following block to use the Amoeba option. +X# - Edit the AMOEBADIR defition to reflect the top of the Amoeba source +X# tree. +X# - Edit the AM_CONF definition to reflect the machine/operating system +X# configuration needed by Amoeba (this is the name of a subdirectory +X# of $(AMOEBADIR)/conf/unix, e.g., vax.ultrix). +X +X#AMOEBADIR= /usr/amoeba +X#AM_CONF= mipseb.irix +X#LIBAMUNIX= $(AMOEBADIR)/conf/unix/$(AM_CONF)/lib/amunix/libamunix.a +X#AM_INCL= -I$(AMOEBADIR)/src/h +X#AM_USE = -DUSE_AMOEBA +X#AM_LIBDEPS= $(LIBAMUNIX) +X#AM_LIBS= $(LIBAMUNIX) +X#AM_SRC = amoebamodule.c sc_interpr.c sc_errors.c +X#AM_OBJ = amoebamodule.o sc_interpr.o sc_errors.o +X +X +X# Silicon Graphics IRIS Options +X# ============================= +X# +X# The following three options are only relevant if you are using a +X# Silicon Graphics IRIS machine. These have been tested with IRIX 3.3.1 +X# on a 4D/25. +X +X +X# GL Option +X# ========= +X# +X# This option incorporates the built-in module 'gl', which provides a +X# complete interface to the Silicon Graphics GL library. It adds +X# about 70K to the Python text size and about 260K to the unstripped +X# binary size. +X# +X# Note: the file 'glmodule.c' is created by a Python script. If you +X# lost the file and have no working Python interpreter, turn off the GL +X# and Panel options, rebuild the Python interpreter, use it to create +X# glmodule.c, and then turn the options back on. +X# +X# Uncomment the following block to use the GL option. +X +X#GL_USE = -DUSE_GL +X#GL_LIBDEPS= +X#GL_LIBS= -lgl_s +X#GL_SRC = glmodule.c cgensupport.c +X#GL_OBJ = glmodule.o cgensupport.o +X +X +X# Panel Option +X# ============ +X# +X# If you have source to the NASA Ames Panel Library, you can configure +X# Python to incorporate the built-in module 'pnl', which is used byu +X# the standard module 'panel' to provide an interface to most features +X# of the Panel Library. This option requires that you also turn on the +X# GL option. It adds about 100K to the Python text size and about 160K +X# to the unstripped binary size. +X# +X# Uncomment and edit the following block to use the Panel option. +X# - Edit the PANELDIR definition to point to the top-level directory +X# of the Panel distribution tree. +X +X#PANELDIR= /usr/people/guido/src/pl +X#PANELLIBDIR= $(PANELDIR)/library +X#LIBPANEL= $(PANELLIBDIR)/lib/libpanel.a +X#PANEL_USE= -DUSE_PANEL +X#PANEL_INCL= -I$(PANELLIBDIR)/include +X#PANEL_LIBDEPS= $(LIBPANEL) +X#PANEL_LIBS= $(LIBPANEL) +X#PANEL_SRC= panelmodule.c +X#PANEL_OBJ= panelmodule.o +X +X +X# Audio Option +X# ============ +X# +X# This option lets you play with /dev/audio on the IRIS 4D/25. +X# It incorporates the built-in module 'audio'. +X# Warning: using the asynchronous I/O facilities of this module can +X# create a second 'thread', which looks in the listings of 'ps' like a +X# forked child. However, it shares its address space with the parent. +X# +X# Uncomment the following block to use the Audio option. +X +X#AUDIO_USE= -DUSE_AUDIO +X#AUDIO_SRC= audiomodule.c asa.c +X#AUDIO_OBJ= audiomodule.o asa.o +X +X +X# Major Definitions +X# ================= +X +XSTANDARD_OBJ= acceler.o bltinmodule.o ceval.o classobject.o \ +X compile.o dictobject.o errors.o fgetsintr.o \ +X fileobject.o floatobject.o $(FMOD_OBJ) frameobject.o \ +X funcobject.o $(GETCWD_OBJ) \ +X graminit.o grammar1.o import.o \ +X intobject.o intrcheck.o listnode.o listobject.o \ +X mathmodule.o methodobject.o modsupport.o \ +X moduleobject.o node.o object.o parser.o \ +X parsetok.o posixmodule.o regexp.o regexpmodule.o \ +X strdup.o $(STRERROR_OBJ) \ +X stringobject.o $(STRTOL_OBJ) structmember.o \ +X sysmodule.o timemodule.o tokenizer.o traceback.o \ +X tupleobject.o typeobject.o +X +XSTANDARD_SRC= acceler.c bltinmodule.c ceval.c classobject.c \ +X compile.c dictobject.c errors.c fgetsintr.c \ +X fileobject.c floatobject.c $(FMOD_SRC) frameobject.c \ +X funcobject.c $(GETCWD_SRC) \ +X graminit.c grammar1.c import.c \ +X intobject.c intrcheck.c listnode.c listobject.c \ +X mathmodule.c methodobject.c modsupport.c \ +X moduleobject.c node.c object.c parser.c \ +X parsetok.c posixmodule.c regexp.c regexpmodule.c \ +X strdup.c $(STRERROR_SRC) \ +X stringobject.c $(STRTOL_SRC) structmember.c \ +X sysmodule.c timemodule.c tokenizer.c traceback.c \ +X tupleobject.c typeobject.c +X +XCONFIGDEFS= $(STDW_USE) $(AM_USE) $(AUDIO_USE) $(GL_USE) $(PANEL_USE) \ +X '-DPYTHONPATH="$(PYTHONPATH)"' +X +XCONFIGINCLS= $(STDW_INCL) +X +XLIBDEPS= libpython.a $(STDW_LIBDEPS) $(AM_LIBDEPS) \ +X $(GL_LIBDEPS) $(PANEL_LIBSDEP) $(RL_LIBDEPS) +X +X# NB: the ordering of items in LIBS is significant! +XLIBS= libpython.a $(STDW_LIBS) $(AM_LIBS) \ +X $(PANEL_LIBS) $(GL_LIBS) $(RL_LIBS) -lm +X +XLIBOBJECTS= $(STANDARD_OBJ) $(STDW_OBJ) $(AM_OBJ) $(AUDIO_OBJ) \ +X $(GL_OBJ) $(PANEL_OBJ) +X +XLIBSOURCES= $(STANDARD_SRC) $(STDW_SRC) $(AM_SRC) $(AUDIO_SRC) \ +X $(GL_SRC) $(PANEL_SRC) +X +XOBJECTS= pythonmain.o config.o +X +XSOURCES= $(LIBSOURCES) pythonmain.c config.c +X +XGENOBJECTS= acceler.o fgetsintr.o grammar1.o \ +X intrcheck.o listnode.o node.o parser.o \ +X parsetok.o strdup.o tokenizer.o bitset.o \ +X firstsets.o grammar.o metagrammar.o pgen.o \ +X pgenmain.o printgrammar.o +X +XGENSOURCES= acceler.c fgetsintr.c grammar1.c \ +X intrcheck.c listnode.c node.c parser.c \ +X parsetok.c strdup.c tokenizer.c bitset.c \ +X firstsets.c grammar.c metagrammar.c pgen.c \ +X pgenmain.c printgrammar.c +X +X +X# Main Targets +X# ============ +X +Xpython: libpython.a $(OBJECTS) $(LIBDEPS) Makefile +X $(CC) $(CFLAGS) $(OBJECTS) $(LIBS) -o @python +X mv @python python +X +Xlibpython.a: $(LIBOBJECTS) +X -rm -f @lib +X ar cr @lib $(LIBOBJECTS) +X $(RANLIB) @lib +X mv @lib libpython.a +X +Xpython_gen: $(GENOBJECTS) $(RL_LIBDEPS) +X $(CC) $(CFLAGS) $(GENOBJECTS) $(RL_LIBS) -o python_gen +X +X +X# Utility Targets +X# =============== +X +X# Don't take the output from lint too seriously. I have not attempted +X# to make Python lint-free. But I use function prototypes. +X +XLINTFLAGS= -h +X +XLINTCPPFLAGS= $(CONFIGDEFS) $(CONFIGINCLS) $(SYSVDEF) \ +X $(AM_INCL) $(PANEL_INCL) +X +XLINT= lint +X +Xlint:: $(SOURCES) +X $(LINT) $(LINTFLAGS) $(LINTCPPFLAGS) $(SOURCES) +X +Xlint:: $(GENSOURCES) +X $(LINT) $(LINTFLAGS) $(GENSOURCES) +X +X# Generating dependencies is only necessary if you intend to hack Python. +X# You may change $(MKDEP) to your favorite dependency generator (it should +X# edit the Makefile in place). +X +XMKDEP= mkdep +X +Xdepend:: +X $(MKDEP) $(LINTCPPFLAGS) $(SOURCES) $(GENSOURCES) +X +X# You may change $(CTAGS) to suit your taste... +X +XCTAGS= ctags -t -w +X +XHEADERS= *.h +X +Xtags: $(SOURCES) $(GENSOURCES) $(HEADERS) +X $(CTAGS) $(SOURCES) $(GENSOURCES) $(HEADERS) +X +Xclean:: +X -rm -f *.o core [,#@]* +X +Xclobber:: clean +X -rm -f python python_gen libpython.a tags +X +X +X# Build Special Objects +X# ===================== +X +X# You may change $(COMPILE) to reflect the default .c.o rule... +X +XCOMPILE= $(CC) -c $(CFLAGS) +X +Xamoebamodule.o: amoebamodule.c +X $(COMPILE) $(AM_INCL) $*.c +X +Xconfig.o: config.c Makefile +X $(COMPILE) $(CONFIGDEFS) $(CONFIGINCLS) $*.c +X +Xfgetsintr.o: fgetsintr.c +X $(COMPILE) $(SIGTYPEDEF) $*.c +X +Xintrcheck.o: intrcheck.c +X $(COMPILE) $(SIGTYPEDEF) $*.c +X +Xpanelmodule.o: panelmodule.c +X $(COMPILE) $(PANEL_INCL) $*.c +X +Xposixmodule.o: posixmodule.c +X $(COMPILE) $(SYSVDEF) $(NOSYMLINKDEF) $*.c +X +Xsc_interpr.o: sc_interpr.c +X $(COMPILE) $(AM_INCL) $*.c +X +Xsc_error.o: sc_error.c +X $(COMPILE) $(AM_INCL) $*.c +X +Xstdwinmodule.o: stdwinmodule.c +X $(COMPILE) $(STDW_INCL) $*.c +X +Xtimemodule.o: timemodule.c +X $(COMPILE) $(SIGTYPEDEF) $(BSDTIMEDEF) $*.c +X +Xtokenizer.o: tokenizer.c +X $(COMPILE) $(RL_USE) $*.c +X +X.PRECIOUS: python libpython.a glmodule.c graminit.c graminit.h +X +X +X# Generated Sources +X# ================= +X# +X# Some source files are (or may be) generated. +X# The rules for doing so are given here. +X +X# Build "glmodule.c", the GL interface. +X# Ignore the messages emitted by the cgen script. +X# Also ignore the warnings emitted while compiling glmodule.c; it works. +X +Xglmodule.c: cstubs cgen +X python cgen <cstubs >@glmodule.c +X mv @glmodule.c glmodule.c +X +X# The dependencies for graminit.[ch] are not turned on in the +X# distributed Makefile because the files themselves are distributed. +X# Turn them on if you want to hack the grammar. +X +X#graminit.c graminit.h: Grammar python_gen +X# python_gen Grammar +X +EOF +fi +if test -s 'src/amoebamodule.c' +then echo '*** I will not over-write existing file src/amoebamodule.c' +else +echo 'x - src/amoebamodule.c' +sed 's/^X//' > 'src/amoebamodule.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Amoeba module implementation */ +X +X/* Amoeba includes */ +X#include <amoeba.h> +X#include <cmdreg.h> +X#include <stdcom.h> +X#include <stderr.h> +X#include <caplist.h> +X#include <server/bullet/bullet.h> +X#include <server/tod/tod.h> +X#include <module/name.h> +X#include <module/direct.h> +X#include <module/mutex.h> +X#include <module/prv.h> +X#include <module/stdcmd.h> +X +X/* C includes */ +X#include <stdlib.h> +X#include <ctype.h> +X +X/* POSIX includes */ +X#include <fcntl.h> +X#include <sys/types.h> +X#include <sys/stat.h> +X +X/* Python includes */ +X#include "allobjects.h" +X#include "modsupport.h" +X#include "sc_global.h" +X#include "stubcode.h" +X +Xextern char *err_why(); +Xextern char *ar_cap(); +X +X#define STUBCODE "+stubcode" +X +Xstatic object *AmoebaError; +Xobject *StubcodeError; +X +Xstatic object *sc_dict; +X +X/* Module initialization */ +X +Xextern struct methodlist amoeba_methods[]; /* Forward */ +Xextern object *convertcapv(); /* Forward */ +X +Xstatic void +Xins(d, name, v) +X object *d; +X char *name; +X object *v; +X{ +X if (v == NULL || dictinsert(d, name, v) != 0) +X fatal("can't initialize amoeba module"); +X} +X +Xvoid +Xinitamoeba() +X{ +X object *m, *d, *v; +X +X m = initmodule("amoeba", amoeba_methods); +X d = getmoduledict(m); +X +X /* Define capv */ +X v = convertcapv(); +X ins(d, "capv", v); +X DECREF(v); +X +X /* Set timeout */ +X timeout((interval)2000); +X +X /* Initialize amoeba.error exception */ +X AmoebaError = newstringobject("amoeba.error"); +X ins(d, "error", AmoebaError); +X StubcodeError = newstringobject("amoeba.stubcode_error"); +X ins(d, "stubcode_error", StubcodeError); +X sc_dict = newdictobject(); +X} +X +X +X/* Set an Amoeba-specific error, and return NULL */ +X +Xobject * +Xamoeba_error(err) +X errstat err; +X{ +X object *v = newtupleobject(2); +X if (v != NULL) { +X settupleitem(v, 0, newintobject((long)err)); +X settupleitem(v, 1, newstringobject(err_why(err))); +X } +X err_setval(AmoebaError, v); +X if (v != NULL) +X DECREF(v); +X return NULL; +X} +X +X +X/* Capability object implementation */ +X +Xextern typeobject Captype; /* Forward */ +X +X#define is_capobject(v) ((v)->ob_type == &Captype) +X +Xtypedef struct { +X OB_HEAD +X capability ob_cap; +X} capobject; +X +Xobject * +Xnewcapobject(cap) +X capability *cap; +X{ +X capobject *v = NEWOBJ(capobject, &Captype); +X if (v == NULL) +X return NULL; +X v->ob_cap = *cap; +X return (object *)v; +X} +X +Xgetcapability(v, cap) +X object *v; +X capability *cap; +X{ +X +X if (!is_capobject(v)) +X return err_badarg(); +X *cap = ((capobject *)v)->ob_cap; +X return 0; +X} +X +X/* +X * is_capobj exports the is_capobject macro to the stubcode modules +X */ +X +Xint +Xis_capobj(v) +X object *v; +X{ +X +X return is_capobject(v); +X} +X +X/* Methods */ +X +Xstatic void +Xcapprint(v, fp, flags) +X capobject *v; +X FILE *fp; +X int flags; +X{ +X /* XXX needs lock when multi-threading */ +X fputs(ar_cap(&v->ob_cap), fp); +X} +X +Xstatic object * +Xcaprepr(v) +X capobject *v; +X{ +X /* XXX needs lock when multi-threading */ +X return newstringobject(ar_cap(&v->ob_cap)); +X} +X +Xextern object *sc_interpreter(); +X +Xextern struct methodlist cap_methods[]; /* Forward */ +X +Xobject * +Xsc_makeself(cap, stubcode, name) +X object *cap, *stubcode; +X char *name; +X{ +X object *sc_name, *sc_self; +X +X sc_name = newstringobject(name); +X if (sc_name == NULL) +X return NULL; +X sc_self = newtupleobject(3); +X if (sc_self == NULL) { +X DECREF(sc_name); +X return NULL; +X } +X if (settupleitem(sc_self, NAME, sc_name) != 0) { +X DECREF(sc_self); +X return NULL; +X } +X INCREF(cap); +X if (settupleitem(sc_self, CAP, cap) != 0) { +X DECREF(sc_self); +X return NULL; +X } +X INCREF(stubcode); +X if (settupleitem(sc_self, STUBC, stubcode) != 0) { +X DECREF(sc_self); +X return NULL; +X } +X return sc_self; +X} +X +X +Xstatic void +Xswapcode(code, len) +X char *code; +X int len; +X{ +X int i = sizeof(TscOperand); +X TscOpcode opcode; +X TscOperand operand; +X +X while (i < len) { +X memcpy(&opcode, &code[i], sizeof(TscOpcode)); +X SwapOpcode(opcode); +X memcpy(&code[i], &opcode, sizeof(TscOpcode)); +X i += sizeof(TscOpcode); +X if (opcode & OPERAND) { +X memcpy(&operand, &code[i], sizeof(TscOperand)); +X SwapOperand(operand); +X memcpy(&code[i], &operand, sizeof(TscOperand)); +X i += sizeof(TscOperand); +X } +X } +X} +X +Xobject * +Xsc_findstubcode(v, name) +X object *v; +X char *name; +X{ +X int fd, fsize; +X char *fname, *buffer; +X struct stat statbuf; +X object *sc_stubcode, *ret; +X TscOperand sc_magic; +X +X /* +X * Only look in the current directory for now. +X */ +X fname = malloc(strlen(name) + 4); +X if (fname == NULL) { +X return err_nomem(); +X } +X sprintf(fname, "%s.sc", name); +X if ((fd = open(fname, O_RDONLY)) == -1) { +X extern int errno; +X +X if (errno == 2) { +X /* +X ** errno == 2 is file not found. +X */ +X err_setstr(NameError, fname); +X return NULL; +X } +X free(fname); +X return err_errno(newstringobject(name)); +X } +X fstat(fd, &statbuf); +X fsize = (int)statbuf.st_size; +X buffer = malloc(fsize); +X if (buffer == NULL) { +X free(fname); +X close(fd); +X return err_nomem(); +X } +X if (read(fd, buffer, fsize) != fsize) { +X close(fd); +X free(fname); +X return err_errno(newstringobject(name)); +X } +X close(fd); +X free(fname); +X memcpy(&sc_magic, buffer, sizeof(TscOperand)); +X if (sc_magic != SC_MAGIC) { +X SwapOperand(sc_magic); +X if (sc_magic != SC_MAGIC) { +X free(buffer); +X return NULL; +X } else { +X swapcode(buffer, fsize); +X } +X } +X sc_stubcode = newsizedstringobject( &buffer[sizeof(TscOperand)], +X fsize - sizeof(TscOperand)); +X free(buffer); +X if (sc_stubcode == NULL) { +X return NULL; +X } +X if (dictinsert(sc_dict, name, sc_stubcode) != 0) { +X DECREF(sc_stubcode); +X return NULL; +X } +X DECREF(sc_stubcode); /* XXXX */ +X sc_stubcode = sc_makeself(v, sc_stubcode, name); +X if (sc_stubcode == NULL) { +X return NULL; +X } +X return sc_stubcode; +X} +X +Xobject * +Xcapgetattr(v, name) +X capobject *v; +X char *name; +X{ +X object *sc_method, *sc_stubcodemethod; +X +X if (sc_dict == NULL) { +X /* +X ** For some reason the dictionary has not been +X ** initialized. Try to find one of the built in +X ** methods. +X */ +X return findmethod(cap_methods, (object *)v, name); +X } +X sc_stubcodemethod = dictlookup(sc_dict, name); +X if (sc_stubcodemethod != NULL) { +X /* +X ** There is a stubcode method in the dictionary. +X ** Execute the stubcode interpreter with the right +X ** arguments. +X */ +X object *self, *ret; +X +X self = sc_makeself((object *)v, sc_stubcodemethod, name); +X if (self == NULL) { +X return NULL; +X } +X ret = findmethod(cap_methods, self, STUBCODE); +X DECREF(self); +X return ret; +X } +X err_clear(); +X sc_method = findmethod(cap_methods, (object *)v, name); +X if (sc_method == NULL) { +X /* +X ** The method is not built in and not in the +X ** dictionary. Try to find it as a stubcode file. +X */ +X object *self, *ret; +X +X err_clear(); +X self = sc_findstubcode((object *)v, name); +X if (self == NULL) { +X return NULL; +X } +X ret = findmethod(cap_methods, self, STUBCODE); +X DECREF(self); +X return ret; +X } +X return sc_method; +X} +X +Xint +Xcapcompare(v, w) +X capobject *v, *w; +X{ +X int cmp = bcmp((char *)&v->ob_cap.cap_port, +X (char *)&w->ob_cap, PORTSIZE); +X if (cmp != 0) +X return cmp; +X return prv_number(&v->ob_cap.cap_priv) - +X prv_number(&w->ob_cap.cap_priv); +X} +X +Xstatic typeobject Captype = { +X OB_HEAD_INIT(&Typetype) +X 0, +X "capability", +X sizeof(capobject), +X 0, +X free, /*tp_dealloc*/ +X capprint, /*tp_print*/ +X capgetattr, /*tp_getattr*/ +X 0, /*tp_setattr*/ +X capcompare, /*tp_comp +are*/ +X caprepr, /*tp_repr*/ +X 0, /*tp_as_number*/ +X 0, /*tp_as_sequence*/ +X 0, /*tp_as_mapping*/ +X}; +X +X +X/* Return a dictionary corresponding to capv */ +X +Xextern struct caplist *capv; +X +Xstatic object * +Xconvertcapv() +X{ +X object *d; +X struct caplist *c; +X d = newdictobject(); +X if (d == NULL) +X return NULL; +X if (capv == NULL) +X return d; +X for (c = capv; c->cl_name != NULL; c++) { +X object *v = newcapobject(c->cl_cap); +X if (v == NULL || dictinsert(d, c->cl_name, v) != 0) { +X DECREF(d); +X return NULL; +X } +X DECREF(v); +X } +X return d; +X} +X +X +X/* Strongly Amoeba-specific argument handlers */ +X +Xstatic int +Xgetcaparg(v, a) +X object *v; +X capability *a; +X{ +X if (v == NULL || !is_capobject(v)) +X return err_badarg(); +X *a = ((capobject *)v) -> ob_cap; +X return 1; +X} +X +Xstatic int +Xgetstrcapargs(v, a, b) +X object *v; +X object **a; +X capability *b; +X{ +X if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) +X return err_badarg(); +X return getstrarg(gettupleitem(v, 0), a) && +X getcaparg(gettupleitem(v, 1), b); +X} +X +X +X/* Amoeba methods */ +X +Xstatic object * +Xamoeba_name_lookup(self, args) +X object *self; +X object *args; +X{ +X object *name; +X capability cap; +X errstat err; +X if (!getstrarg(args, &name)) +X return NULL; +X err = name_lookup(getstringvalue(name), &cap); +X if (err != STD_OK) +X return amoeba_error(err); +X return newcapobject(&cap); +X} +X +Xstatic object * +Xamoeba_name_append(self, args) +X object *self; +X object *args; +X{ +X object *name; +X capability cap; +X errstat err; +X if (!getstrcapargs(args, &name, &cap)) +X return NULL; +X err = name_append(getstringvalue(name), &cap); +X if (err != STD_OK) +X return amoeba_error(err); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xamoeba_name_replace(self, args) +X object *self; +X object *args; +X{ +X object *name; +X capability cap; +X errstat err; +X if (!getstrcapargs(args, &name, &cap)) +X return NULL; +X err = name_replace(getstringvalue(name), &cap); +X if (err != STD_OK) +X return amoeba_error(err); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xamoeba_name_delete(self, args) +X object *self; +X object *args; +X{ +X object *name; +X errstat err; +X if (!getstrarg(args, &name)) +X return NULL; +X err = name_delete(getstringvalue(name)); +X if (err != STD_OK) +X return amoeba_error(err); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xamoeba_timeout(self, args) +X object *self; +X object *args; +X{ +X int i; +X object *v; +X interval tout; +X if (!getintarg(args, &i)) +X return NULL; +X tout = timeout((interval)i); +X v = newintobject((long)tout); +X if (v == NULL) +X timeout(tout); +X return v; +X} +X +Xstatic struct methodlist amoeba_methods[] = { +X {"name_append", amoeba_name_append}, +X {"name_delete", amoeba_name_delete}, +X {"name_lookup", amoeba_name_lookup}, +X {"name_replace", amoeba_name_replace}, +X {"timeout", amoeba_timeout}, +X {NULL, NULL} /* Sentinel */ +X}; +X +X/* Capability methods */ +X +Xstatic object * +Xcap_b_size(self, args) +X capobject *self; +X object *args; +X{ +X errstat err; +X b_fsize size; +X if (!getnoarg(args)) +X return NULL; +X err = b_size(&self->ob_cap, &size); +X if (err != STD_OK) +X return amoeba_error(err); +X return newintobject((long)size); +X} +X +Xstatic object * +Xcap_b_read(self, args) +X capobject *self; +X object *args; +X{ +X errstat err; +X char *buf; +X object *v; +X long offset, size; +X b_fsize nread; +X if (!getlonglongargs(args, &offset, &size)) +X return NULL; +X buf = malloc((unsigned int)size); +X if (buf == NULL) { +X return err_nomem(); +X } +X err = b_read(&self->ob_cap, (b_fsize)offset, buf, (b_fsize)size, +X &nread); +X if (err != STD_OK) { +X free(buf); +X return amoeba_error(err); +X } +X v = newsizedstringobject(buf, (int)nread); +X free(buf); +X return v; +X} +X +Xstatic object * +Xcap_dir_lookup(self, args) +X capobject *self; +X object *args; +X{ +X object *name; +X capability cap; +X errstat err; +X if (!getstrarg(args, &name)) +X return NULL; +X err = dir_lookup(&self->ob_cap, getstringvalue(name), &cap); +X if (err != STD_OK) +X return amoeba_error(err); +X return newcapobject(&cap); +X} +X +Xstatic object * +Xcap_dir_append(self, args) +X capobject *self; +X object *args; +X{ +X object *name; +X capability cap; +X errstat err; +X if (!getstrcapargs(args, &name, &cap)) +X return NULL; +X err = dir_append(&self->ob_cap, getstringvalue(name), &cap); +X if (err != STD_OK) +X return amoeba_error(err); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xcap_dir_delete(self, args) +X capobject *self; +X object *args; +X{ +X object *name; +X errstat err; +X if (!getstrarg(args, &name)) +X return NULL; +X err = dir_delete(&self->ob_cap, getstringvalue(name)); +X if (err != STD_OK) +X return amoeba_error(err); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xcap_dir_replace(self, args) +X capobject *self; +X object *args; +X{ +X object *name; +X capability cap; +X errstat err; +X if (!getstrcapargs(args, &name, &cap)) +X return NULL; +X err = dir_replace(&self->ob_cap, getstringvalue(name), &cap); +X if (err != STD_OK) +X return amoeba_error(err); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xcap_dir_list(self, args) +X capobject *self; +X object *args; +X{ +X errstat err; +X struct dir_open *dd; +X object *d; +X char *name; +X if (!getnoarg(args)) +X return NULL; +X if ((dd = dir_open(&self->ob_cap)) == NULL) +X return amoeba_error(STD_COMBAD); +X if ((d = newlistobject(0)) == NULL) { +X dir_close(dd); +X return NULL; +X } +X while ((name = dir_next(dd)) != NULL) { +X object *v; +X v = newstringobject(name); +X if (v == NULL) { +X DECREF(d); +X d = NULL; +X break; +X } +X if (addlistitem(d, v) != 0) { +X DECREF(v); +X DECREF(d); +X d = NULL; +X break; +X } +X DECREF(v); +X } +X dir_close(dd); +X return d; +X} +X +Xobject * +Xcap_std_info(self, args) +X capobject *self; +X object *args; +X{ +X char buf[256]; +X errstat err; +X int n; +X if (!getnoarg(args)) +X return NULL; +X err = std_info(&self->ob_cap, buf, sizeof buf, &n); +X if (err != STD_OK) +X return amoeba_error(err); +X return newsizedstringobject(buf, n); +X} +X +Xobject * +Xcap_tod_gettime(self, args) +X capobject *self; +X object *args; +X{ +X header h; +X errstat err; +X bufsize n; +X long sec; +X int msec, tz, dst; +X if (!getnoarg(args)) +X return NULL; +X h.h_port = self->ob_cap.cap_port; +X h.h_priv = self->ob_cap.cap_priv; +X h.h_command = TOD_GETTIME; +X n = trans(&h, NILBUF, 0, &h, NILBUF, 0); +X if (ERR_STATUS(n)) +X return amoeba_error(ERR_CONVERT(n)); +X tod_decode(&h, &sec, &msec, &tz, &dst); +X return newintobject(sec); +X} +X +Xobject * +Xcap_tod_settime(self, args) +X capobject *self; +X object *args; +X{ +X header h; +X errstat err; +X bufsize n; +X long sec; +X if (!getlongarg(args, &sec)) +X return NULL; +X h.h_port = self->ob_cap.cap_port; +X h.h_priv = self->ob_cap.cap_priv; +X h.h_command = TOD_SETTIME; +X tod_encode(&h, sec, 0, 0, 0); +X n = trans(&h, NILBUF, 0, &h, NILBUF, 0); +X if (ERR_STATUS(n)) +X return amoeba_error(ERR_CONVERT(n)); +X INCREF(None); +X return None; +X} +X +Xstatic struct methodlist cap_methods[] = { +X { STUBCODE, sc_interpreter}, +X {"b_read", cap_b_read}, +X {"b_size", cap_b_size}, +X {"dir_append", cap_dir_append}, +X {"dir_delete", cap_dir_delete}, +X {"dir_list", cap_dir_list}, +X {"dir_lookup", cap_dir_lookup}, +X {"dir_replace", cap_dir_replace}, +X {"std_info", cap_std_info}, +X {"tod_gettime", cap_tod_gettime}, +X {"tod_settime", cap_tod_settime}, +X {NULL, NULL} /* Sentinel */ +X}; +EOF +fi +if test -s 'src/tokenizer.c' +then echo '*** I will not over-write existing file src/tokenizer.c' +else +echo 'x - src/tokenizer.c' +sed 's/^X//' > 'src/tokenizer.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Tokenizer implementation */ +X +X/* XXX This is rather old, should be restructured perhaps */ +X/* XXX Need a better interface to report errors than writing to stderr */ +X/* XXX Should use editor resource to fetch true tab size on Macintosh */ +X +X#include "pgenheaders.h" +X +X#include <ctype.h> +X#include "string.h" +X +X#include "fgetsintr.h" +X#include "tokenizer.h" +X#include "errcode.h" +X +X#ifdef THINK_C +X#define TABSIZE 4 +X#endif +X +X#ifndef TABSIZE +X#define TABSIZE 8 +X#endif +X +X/* Forward */ +Xstatic struct tok_state *tok_new PROTO((void)); +Xstatic int tok_nextc PROTO((struct tok_state *tok)); +Xstatic void tok_backup PROTO((struct tok_state *tok, int c)); +X +X/* Token names */ +X +Xchar *tok_name[] = { +X "ENDMARKER", +X "NAME", +X "NUMBER", +X "STRING", +X "NEWLINE", +X "INDENT", +X "DEDENT", +X "LPAR", +X "RPAR", +X "LSQB", +X "RSQB", +X "COLON", +X "COMMA", +X "SEMI", +X "PLUS", +X "MINUS", +X "STAR", +X "SLASH", +X "VBAR", +X "AMPER", +X "LESS", +X "GREATER", +X "EQUAL", +X "DOT", +X "PERCENT", +X "BACKQUOTE", +X "LBRACE", +X "RBRACE", +X "OP", +X "<ERRORTOKEN>", +X "<N_TOKENS>" +X}; +X +X +X/* Create and initialize a new tok_state structure */ +X +Xstatic struct tok_state * +Xtok_new() +X{ +X struct tok_state *tok = NEW(struct tok_state, 1); +X if (tok == NULL) +X return NULL; +X tok->buf = tok->cur = tok->end = tok->inp = NULL; +X tok->done = E_OK; +X tok->fp = NULL; +X tok->tabsize = TABSIZE; +X tok->indent = 0; +X tok->indstack[0] = 0; +X tok->atbol = 1; +X tok->pendin = 0; +X tok->prompt = tok->nextprompt = NULL; +X tok->lineno = 0; +X return tok; +X} +X +X +X/* Set up tokenizer for string */ +X +Xstruct tok_state * +Xtok_setups(str) +X char *str; +X{ +X struct tok_state *tok = tok_new(); +X if (tok == NULL) +X return NULL; +X tok->buf = tok->cur = str; +X tok->end = tok->inp = strchr(str, '\0'); +X return tok; +X} +X +X +X/* Set up tokenizer for string */ +X +Xstruct tok_state * +Xtok_setupf(fp, ps1, ps2) +X FILE *fp; +X char *ps1, *ps2; +X{ +X struct tok_state *tok = tok_new(); +X if (tok == NULL) +X return NULL; +X if ((tok->buf = NEW(char, BUFSIZ)) == NULL) { +X DEL(tok); +X return NULL; +X } +X tok->cur = tok->inp = tok->buf; +X tok->end = tok->buf + BUFSIZ; +X tok->fp = fp; +X tok->prompt = ps1; +X tok->nextprompt = ps2; +X return tok; +X} +X +X +X/* Free a tok_state structure */ +X +Xvoid +Xtok_free(tok) +X struct tok_state *tok; +X{ +X /* XXX really need a separate flag to say 'my buffer' */ +X if (tok->fp != NULL && tok->buf != NULL) +X DEL(tok->buf); +X DEL(tok); +X} +X +X +X/* Get next char, updating state; error code goes into tok->done */ +X +Xstatic int +Xtok_nextc(tok) +X register struct tok_state *tok; +X{ +X if (tok->done != E_OK) +X return EOF; +X +X for (;;) { +X if (tok->cur < tok->inp) +X return *tok->cur++; +X if (tok->fp == NULL) { +X tok->done = E_EOF; +X return EOF; +X } +X if (tok->inp > tok->buf && tok->inp[-1] == '\n') +X tok->inp = tok->buf; +X if (tok->inp == tok->end) { +X int n = tok->end - tok->buf; +X char *new = tok->buf; +X RESIZE(new, char, n+n); +X if (new == NULL) { +X fprintf(stderr, "tokenizer out of mem\n"); +X tok->done = E_NOMEM; +X return EOF; +X } +X tok->buf = new; +X tok->inp = tok->buf + n; +X tok->end = tok->inp + n; +X } +X#ifdef USE_READLINE +X if (tok->prompt != NULL) { +X extern char *readline PROTO((char *prompt)); +X static int been_here; +X if (!been_here) { +X /* Force rebind of TAB to insert-tab */ +X extern int rl_insert(); +X rl_bind_key('\t', rl_insert); +X been_here++; +X } +X if (tok->buf != NULL) +X free(tok->buf); +X tok->buf = readline(tok->prompt); +X (void) intrcheck(); /* Clear pending interrupt */ +X if (tok->nextprompt != NULL) +X tok->prompt = tok->nextprompt; +X /* XXX different semantics w/o readline()! */ +X if (tok->buf == NULL) { +X tok->done = E_EOF; +X } +X else { +X unsigned int n = strlen(tok->buf); +X if (n > 0) +X add_history(tok->buf); +X /* Append the '\n' that readline() +X doesn't give us, for the tokenizer... */ +X tok->buf = realloc(tok->buf, n+2); +X if (tok->buf == NULL) +X tok->done = E_NOMEM; +X else { +X tok->end = tok->buf + n; +X *tok->end++ = '\n'; +X *tok->end = '\0'; +X tok->inp = tok->end; +X tok->cur = tok->buf; +X } +X } +X } +X else +X#endif +X { +X tok->cur = tok->inp; +X if (tok->prompt != NULL && tok->inp == tok->buf) { +X fprintf(stderr, "%s", tok->prompt); +X tok->prompt = tok->nextprompt; +X } +X tok->done = fgets_intr(tok->inp, +X (int)(tok->end - tok->inp), tok->fp); +X } +X if (tok->done != E_OK) { +X if (tok->prompt != NULL) +X fprintf(stderr, "\n"); +X return EOF; +X } +X tok->inp = strchr(tok->inp, '\0'); +X } +X} +X +X +X/* Back-up one character */ +X +Xstatic void +Xtok_backup(tok, c) +X register struct tok_state *tok; +X register int c; +X{ +X if (c != EOF) { +X if (--tok->cur < tok->buf) { +X fprintf(stderr, "tok_backup: begin of buffer\n"); +X abort(); +X } +X if (*tok->cur != c) +X *tok->cur = c; +X } +X} +X +X +X/* Return the token corresponding to a single character */ +X +Xint +Xtok_1char(c) +X int c; +X{ +X switch (c) { +X case '(': return LPAR; +X case ')': return RPAR; +X case '[': return LSQB; +X case ']': return RSQB; +X case ':': return COLON; +X case ',': return COMMA; +X case ';': return SEMI; +X case '+': return PLUS; +X case '-': return MINUS; +X case '*': return STAR; +X case '/': return SLASH; +X case '|': return VBAR; +X case '&': return AMPER; +X case '<': return LESS; +X case '>': return GREATER; +X case '=': return EQUAL; +X case '.': return DOT; +X case '%': return PERCENT; +X case '`': return BACKQUOTE; +X case '{': return LBRACE; +X case '}': return RBRACE; +X default: return OP; +X } +X} +X +X +X/* Get next token, after space stripping etc. */ +X +Xint +Xtok_get(tok, p_start, p_end) +X register struct tok_state *tok; /* In/out: tokenizer state */ +X char **p_start, **p_end; /* Out: point to start/end of token */ +X{ +X register int c; +X +X /* Get indentation level */ +X if (tok->atbol) { +X register int col = 0; +X tok->atbol = 0; +X tok->lineno++; +X for (;;) { +X c = tok_nextc(tok); +X if (c == ' ') +X col++; +X else if (c == '\t') +X col = (col/tok->tabsize + 1) * tok->tabsize; +X else +X break; +X } +X tok_backup(tok, c); +X if (col == tok->indstack[tok->indent]) { +X /* No change */ +X } +X else if (col > tok->indstack[tok->indent]) { +X /* Indent -- always one */ +X if (tok->indent+1 >= MAXINDENT) { +X fprintf(stderr, "excessive indent\n"); +X tok->done = E_TOKEN; +X return ERRORTOKEN; +X } +X tok->pendin++; +X tok->indstack[++tok->indent] = col; +X } +X else /* col < tok->indstack[tok->indent] */ { +X /* Dedent -- any number, must be consistent */ +X while (tok->indent > 0 && +X col < tok->indstack[tok->indent]) { +X tok->indent--; +X tok->pendin--; +X } +X if (col != tok->indstack[tok->indent]) { +X fprintf(stderr, "inconsistent dedent\n"); +X tok->done = E_TOKEN; +X return ERRORTOKEN; +X } +X } +X } +X +X *p_start = *p_end = tok->cur; +X +X /* Return pending indents/dedents */ +X if (tok->pendin != 0) { +X if (tok->pendin < 0) { +X tok->pendin++; +X return DEDENT; +X } +X else { +X tok->pendin--; +X return INDENT; +X } +X } +X +X again: +X /* Skip spaces */ +X do { +X c = tok_nextc(tok); +X } while (c == ' ' || c == '\t'); +X +X /* Set start of current token */ +X *p_start = tok->cur - 1; +X +X /* Skip comment */ +X if (c == '#') { +X /* Hack to allow overriding the tabsize in the file. +X This is also recognized by vi, when it occurs near the +X beginning or end of the file. (Will vi never die...?) */ +X int x; +X /* XXX The case to (unsigned char *) is needed by THINK C 3.0 */ +X if (sscanf(/*(unsigned char *)*/tok->cur, +X " vi:set tabsize=%d:", &x) == 1 && +X x >= 1 && x <= 40) { +X fprintf(stderr, "# vi:set tabsize=%d:\n", x); +X tok->tabsize = x; +X } +X do { +X c = tok_nextc(tok); +X } while (c != EOF && c != '\n'); +X } +X +X /* Check for EOF and errors now */ +X if (c == EOF) +X return tok->done == E_EOF ? ENDMARKER : ERRORTOKEN; +X +X /* Identifier (most frequent token!) */ +X if (isalpha(c) || c == '_') { +X do { +X c = tok_nextc(tok); +X } while (isalnum(c) || c == '_'); +X tok_backup(tok, c); +X *p_end = tok->cur; +X return NAME; +X } +X +X /* Newline */ +X if (c == '\n') { +X tok->atbol = 1; +X *p_end = tok->cur - 1; /* Leave '\n' out of the string */ +X return NEWLINE; +X } +X +X /* Number */ +X if (isdigit(c)) { +X if (c == '0') { +X /* Hex or octal */ +X c = tok_nextc(tok); +X if (c == '.') +X goto fraction; +X if (c == 'x' || c == 'X') { +X /* Hex */ +X do { +X c = tok_nextc(tok); +X } while (isxdigit(c)); +X } +X else { +X /* Octal; c is first char of it */ +X /* There's no 'isoctdigit' macro, sigh */ +X while ('0' <= c && c < '8') { +X c = tok_nextc(tok); +X } +X } +X } +X else { +X /* Decimal */ +X do { +X c = tok_nextc(tok); +X } while (isdigit(c)); +X /* Accept floating point numbers. +X XXX This accepts incomplete things like 12e or 1e+; +X worry about that at run-time. +X XXX Doesn't accept numbers starting with a dot */ +X if (c == '.') { +X fraction: +X /* Fraction */ +X do { +X c = tok_nextc(tok); +X } while (isdigit(c)); +X } +X if (c == 'e' || c == 'E') { +X /* Exponent part */ +X c = tok_nextc(tok); +X if (c == '+' || c == '-') +X c = tok_nextc(tok); +X while (isdigit(c)) { +X c = tok_nextc(tok); +X } +X } +X } +X tok_backup(tok, c); +X *p_end = tok->cur; +X return NUMBER; +X } +X +X /* String */ +X if (c == '\'') { +X for (;;) { +X c = tok_nextc(tok); +X if (c == '\n' || c == EOF) { +X tok->done = E_TOKEN; +X return ERRORTOKEN; +X } +X if (c == '\\') { +X c = tok_nextc(tok); +X *p_end = tok->cur; +X if (c == '\n' || c == EOF) { +X tok->done = E_TOKEN; +X return ERRORTOKEN; +X } +X continue; +X } +X if (c == '\'') +X break; +X } +X *p_end = tok->cur; +X return STRING; +X } +X +X /* Line continuation */ +X if (c == '\\') { +X c = tok_nextc(tok); +X if (c != '\n') { +X tok->done = E_TOKEN; +X return ERRORTOKEN; +X } +X tok->lineno++; +X goto again; /* Read next line */ +X } +X +X /* Punctuation character */ +X *p_end = tok->cur; +X return tok_1char(c); +X} +X +X +X#ifdef DEBUG +X +Xvoid +Xtok_dump(type, start, end) +X int type; +X char *start, *end; +X{ +X printf("%s", tok_name[type]); +X if (type == NAME || type == NUMBER || type == STRING || type == OP) +X printf("(%.*s)", (int)(end - start), start); +X} +X +X#endif +EOF +fi +echo 'Part 08 out of 21 of pack.out complete.' +exit 0 diff --git a/shar/python-0.9.1-09-21.shar b/shar/python-0.9.1-09-21.shar new file mode 100644 index 0000000..0aee04d --- /dev/null +++ b/shar/python-0.9.1-09-21.shar @@ -0,0 +1,2688 @@ +: This is a shell archive. +: Extract with 'sh this_file'. +: +: Extract part 01 first since it makes all directories +echo 'Start of pack.out, part 09 out of 21:' +if test -s 'doc/mod3.tex' +then echo '*** I will not over-write existing file doc/mod3.tex' +else +echo 'x - doc/mod3.tex' +sed 's/^X//' > 'doc/mod3.tex' << 'EOF' +X\section{Standard Modules} +X +XThe following standard modules are defined. +XThey are available in one of the directories in the default module +Xsearch path (try printing +X{\tt sys.path} +Xto find out the default search path.) +X +X\subsection{Standard Module {\tt string}} +X +XThis module defines some constants useful for checking character +Xclasses, some exceptions, and some useful string functions. +XThe constants are: +X\begin{description} +X\funcitem{digits} +XThe string +X{\tt '0123456789'}. +X\funcitem{hexdigits} +XThe string +X{\tt '0123456789abcdefABCDEF'}. +X\funcitem{letters} +XThe concatenation of the strings +X{\tt lowercase} +Xand +X{\tt uppercase} +Xdescribed below. +X\funcitem{lowercase} +XThe string +X{\tt 'abcdefghijklmnopqrstuvwxyz'}. +X\funcitem{octdigits} +XThe string +X{\tt '01234567'}. +X\funcitem{uppercase} +XThe string +X{\tt 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'}. +X\funcitem{whitespace} +XA string containing all characters that are considered whitespace, +Xi.e., +Xspace, tab and newline. +XThis definition is used by +X{\tt split()} +Xand +X{\tt strip()}. +X\end{description} +X +XThe exceptions are: +X\begin{description} +X\excitem{atoi\_error}{non-numeric argument to string.atoi} +X%.br +XException raised by +X{\tt atoi} +Xwhen a non-numeric string argument is detected. +XThe exception argument is the offending string. +X\excitem{index\_error}{substring not found in string.index} +X%.br +XException raised by +X{\tt index} +Xwhen +X{\tt sub} +Xis not found. +XThe argument are the offending arguments to index: {\tt (s, sub)}. +X\end{description} +X +XThe functions are: +X\begin{description} +X\funcitem{atoi}{s} +XConverts a string to a number. +XThe string must consist of one or more digits, optionally preceded by a +Xsign ({\tt '+'} or {\tt '-'}). +X\funcitem{index}{s, sub} +XReturns the lowest index in +X{\tt s} +Xwhere the substring +X{\tt sub} +Xis found. +X\funcitem{lower}{s} +XConvert letters to lower case. +X\funcitem{split}{s} +XReturns a list of the whitespace-delimited words of the string +X{\tt s}. +X\funcitem{splitfields}{s, sep} +X%.br +XReturns a list containing the fields of the string +X{\tt s}, +Xusing the string +X{\tt sep} +Xas a separator. +XThe list will have one more items than the number of non-overlapping +Xoccurrences of the separator in the string. +XThus, +X{\tt string.splitfields(s, ' ')} +Xis not the same as +X{\tt string.split(s)}, +Xas the latter only returns non-empty words. +X\funcitem{strip}{s} +XRemoves leading and trailing whitespace from the string +X{\tt s}. +X\funcitem{swapcase}{s} +XConverts lower case letters to upper case and vice versa. +X\funcitem{upper}{s} +XConvert letters to upper case. +X\funcitem{ljust(s, width), rjust(s, width), center}{s, width} +X%.br +XThese functions respectively left-justify, right-justify and center a +Xstring in a field of given width. +XThey return a string that is at least +X{\tt width} +Xcharacters wide, created by padding the string +X{\tt s} +Xwith spaces until the given width on the right, left or both sides. +XThe string is never truncated. +X\end{description} +X +X\subsection{Standard Module {\tt path}} +X +XThis module implements some useful functions on POSIX pathnames. +X\begin{description} +X\funcitem{basename}{p} +XReturns the base name of pathname +X{\tt p}. +XThis is the second half of the pair returned by +X{\tt path.split(p)}. +X\funcitem{cat}{p, q} +XPerforms intelligent pathname concatenation on paths +X{\tt p} +Xand +X{\tt q}: +XIf +X{\tt q} +Xis an absolute path, the return value is +X{\tt q}. +XOtherwise, the concatenation of +X{\tt p} +Xand +X{\tt q} +Xis returned, with a slash ({\tt '/'}) inserted unless +X{\tt p} +Xis empty or ends in a slash. +X\funcitem{commonprefix}{list} +X%.br +XReturns the longest string that is a prefix of all strings in +X{\tt list}. +XIf +X{\tt list} +Xis empty, the empty string ({\tt ''}) is returned. +X\funcitem{exists}{p} +XReturns true if +X{\tt p} +Xrefers to an existing path. +X\funcitem{isdir}{p} +XReturns true if +X{\tt p} +Xrefers to an existing directory. +X\funcitem{islink}{p} +XReturns true if +X{\tt p} +Xrefers to a directory entry that is a symbolic link. +XAlways false if symbolic links are not supported. +X\funcitem{ismount}{p} +XReturns true if +X{\tt p} +Xis an absolute path that occurs in the mount table as output by the +X{\tt /etc/mount} +Xutility. +XThis output is read once when the function is used for the first +Xtime.% +X\footnote{ +XIs there a better way to check for mount points? +X} +X\funcitem{split}{p} +XReturns a pair +X{\tt (head,~tail)} +Xsuch that +X{\tt tail} +Xcontains no slashes and +X{\tt path.cat(head, tail)} +Xis equal to +X{\tt p}. +X\funcitem{walk}{p, visit, arg} +X%.br +XCalls the function +X{\tt visit} +Xwith arguments +X{\tt (arg, dirname, names)} +Xfor each directory in the directory tree rooted at +X{\tt p} +X(including +X{\tt p} +Xitself, if it is a directory). +XThe argument +X{\tt dirname} +Xspecifies the visited directory, the argument +X{\tt names} +Xlists the files in the directory (gotten from +X{\tt posix.listdir(dirname)}). +XThe +X{\tt visit} +Xfunction may modify +X{\tt names} +Xto influence the set of directories visited below +X{\tt dirname}, +Xe.g., +Xto avoid visiting certain parts of the tree. +X(The object referred to by +X{\tt names} +Xmust be modified in place, using +X{\tt del} +Xor slice assignment.) +X\end{description} +X +X\subsection{Standard Module {\tt getopt}} +X +XThis module helps scripts to parse the command line arguments in +X{\tt sys.argv}. +XIt uses the same conventions as the {\UNIX} +X{\tt getopt()} +Xfunction. +XIt defines the function +X{\tt getopt.getopt(args, options)} +Xand the exception +X{\tt getopt.error}. +X +XThe first argument to +X{\tt getopt()} +Xis the argument list passed to the script with its first element +Xchopped off (i.e., +X{\tt sys.argv[1:]}). +XThe second argument is the string of option letters that the +Xscript wants to recognize, with options that require an argument +Xfollowed by a colon (i.e., the same format that {\UNIX} +X{\tt getopt()} +Xuses). +XThe return value consists of two elements: the first is a list of +Xoption-and-value pairs; the second is the list of program arguments +Xleft after the option list was stripped (this is a trailing slice of the +Xfirst argument). +XEach option-and-value pair returned has the option as its first element, +Xprefixed with a hyphen (e.g., +X{\tt '-x'}), +Xand the option argument as its second element, or an empty string if the +Xoption has no argument. +XThe options occur in the list in the same order in which they were +Xfound, thus allowing multiple occurrences. +XExample: +X\bcode\begin{verbatim} +X>>> import getopt, string +X>>> args = string.split('-a -b -cfoo -d bar a1 a2') +X>>> args +X['-a', '-b', '-cfoo', '-d', 'bar', 'a1', 'a2'] +X>>> optlist, args = getopt.getopt(args, 'abc:d:') +X>>> optlist +X[('-a', ''), ('-b', ''), ('-c', 'foo'), ('-d', 'bar')] +X>>> args +X['a1', 'a2'] +X>>> +X\end{verbatim}\ecode +XThe exception +X{\tt getopt.error = 'getopt error'} +Xis raised when an unrecognized option is found in the argument list or +Xwhen an option requiring an argument is given none. +XThe argument to the exception is a string indicating the cause of the +Xerror. +X +X\subsection{Standard Module {\tt rand}} +X +XThis module implements a pseudo-random number generator similar to +X{\tt rand()} +Xin C. +XIt defines the following functions: +X\begin{description} +X\funcitem{rand}{} +XReturns an integer random number in the range [0 ... 32768). +X\funcitem{choice}{s} +XReturns a random element from the sequence (string, tuple or list) +X{\tt s.} +X\funcitem{srand}{seed} +XInitializes the random number generator with the given integral seed. +XWhen the module is first imported, the random number is initialized with +Xthe current time. +X\end{description} +X +X\subsection{Standard Module {\tt whrandom}} +X +XThis module implements a Wichmann-Hill pseudo-random number generator. +XIt defines the following functions: +X\begin{description} +X\funcitem{random}{} +XReturns the next random floating point number in the range [0.0 ... 1.0). +X\funcitem{seed}{x, y, z} +XInitializes the random number generator from the integers +X{\tt x}, +X{\tt y} +Xand +X{\tt z}. +XWhen the module is first imported, the random number is initialized +Xusing values derived from the current time. +X\end{description} +X +X\subsection{Standard Module {\tt stdwinevents}} +X +XThis module defines constants used by STDWIN for event types +X({\tt WE\_ACTIVATE} etc.), command codes ({\tt WC\_LEFT} etc.) +Xand selection types ({\tt WS\_PRIMARY} etc.). +XRead the file for details. +XSuggested usage is +X\bcode\begin{verbatim} +X>>> from stdwinevents import * +X>>> +X\end{verbatim}\ecode +X +X\subsection{Standard Module {\tt rect}} +X +XThis module contains useful operations on rectangles. +XA rectangle is defined as in module +X{\tt stdwin}: +Xa pair of points, where a point is a pair of integers. +XFor example, the rectangle +X\bcode\begin{verbatim} +X(10, 20), (90, 80) +X\end{verbatim}\ecode +Xis a rectangle whose left, top, right and bottom edges are 10, 20, 90 +Xand 80, respectively. +XNote that the positive vertical axis points down (as in +X{\tt stdwin}). +X +XThe module defines the following objects: +X\begin{description} +X\excitem{error}{rect.error} +X%.br +XThe exception raised by functions in this module when they detect an +Xerror. +XThe exception argument is a string describing the problem in more +Xdetail. +X\funcitem{empty} +X%.br +XThe rectangle returned when some operations return an empty result. +XThis makes it possible to quickly check whether a result is empty: +X\bcode\begin{verbatim} +X>>> import rect +X>>> r1 = (10, 20), (90, 80) +X>>> r2 = (0, 0), (10, 20) +X>>> r3 = rect.intersect(r1, r2) +X>>> if r3 is rect.empty: print 'Empty intersection' +XEmpty intersection +X>>> +X\end{verbatim}\ecode +X\funcitem{is\_empty}{r} +X%.br +XReturns true if the given rectangle is empty. +XA rectangle +X{\em (left,~top), (right,~bottom)} +Xis empty if +X{\em left~$\geq$~right} +Xor +X{\em top~$\leq$~bottom}. +X\funcitem{intersect}{list} +X%.br +XReturns the intersection of all rectangles in the list argument. +XIt may also be called with a tuple argument or with two or more +Xrectangles as arguments. +XRaises +X{\tt rect.error} +Xif the list is empty. +XReturns +X{\tt rect.empty} +Xif the intersection of the rectangles is empty. +X\funcitem{union}{list} +X%.br +XReturns the smallest rectangle that contains all non-empty rectangles in +Xthe list argument. +XIt may also be called with a tuple argument or with two or more +Xrectangles as arguments. +XReturns +X{\tt rect.empty} +Xif the list is empty or all its rectangles are empty. +X\funcitem{pointinrect}{point, rect} +X%.br +XReturns true if the point is inside the rectangle. +XBy definition, a point +X{\em (h,~v)} +Xis inside a rectangle +X{\em (left,~top),} +X{\em (right,~bottom)} +Xif +X{\em left~$\leq$~h~$<$~right} +Xand +X{\em top~$\leq$~v~$<$~bottom}. +X\funcitem{inset(rect, }{dh, dv)} +X%.br +XReturns a rectangle that lies inside the +X{\tt rect} +Xargument by +X{\tt dh} +Xpixels horizontally +Xand +X{\tt dv} +Xpixels +Xvertically. +XIf +X{\tt dh} +Xor +X{\tt dv} +Xis negative, the result lies outside +X{\tt rect}. +X\funcitem{rect2geom}{rect} +X%.br +XConverts a rectangle to geometry representation: +X{\em (left,~top),} +X{\em (width,~height)}. +X\funcitem{geom2rect}{geom} +X%.br +XConverts a rectangle given in geometry representation back to the +Xstandard rectangle representation +X{\em (left,~top),} +X{\em (right,~bottom)}. +X\end{description} +X +X\subsection{Standard Modules {\tt GL} and {\tt DEVICE}} +X +XThese modules define the constants used by the Silicon Graphics +X{\em Graphics Library} +Xthat C programmers find in the header files +X{\tt <gl/gl.h>} +Xand +X{\tt <gl/device.h>}. +XRead the module files for details. +X +X\subsection{Standard Module {\tt panel}} +X +XThis module should be used instead of the built-in module +X{\tt pnl} +Xto interface with the +X{\em Panel Library}. +X +XThe module is too large to document here in its entirety. +XOne interesting function: +X\begin{description} +X\funcitem{defpanellist}{filename} +X%.br +XParses a panel description file containing S-expressions written by the +X{\em Panel Editor} +Xthat accompanies the Panel Library and creates the described panels. +XIt returns a list of panel objects. +X\end{description} +X +X{\bf Warning:} +Xthe {\Python} interpreter will dump core if you don't create a GL window +Xbefore calling +X{\tt panel.mkpanel()} +Xor +X{\tt panel.defpanellist()}. +X +X\subsection{Standard Module {\tt panelparser}} +X +XThis module defines a self-contained parser for S-expressions as output +Xby the Panel Editor (which is written in Scheme so it can't help writing +XS-expressions). +XThe relevant function is +X{\tt panelparser.parse\_file(file)} +Xwhich has a file object (not a filename!) as argument and returns a list +Xof parsed S-expressions. +XEach S-expression is converted into a {\Python} list, with atoms converted +Xto {\Python} strings and sub-expressions (recursively) to {\Python} lists. +XFor more details, read the module file. +X +X\section{P.M.} +X +X\begin{verse} +X +Xcommands +X +Xcmp? +X +X*cache? +X +Xlocaltime? +X +Xcalendar? +X +X\_\_dict? +X +Xmac? +X +X\end{verse} +EOF +fi +if test -s 'src/audiomodule.c' +then echo '*** I will not over-write existing file src/audiomodule.c' +else +echo 'x - src/audiomodule.c' +sed 's/^X//' > 'src/audiomodule.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Silicon Graphics audio module implementation */ +X/* For SGI Personal IRIS 4D/20 under IRIX 3.3; <sys/audio.h> mentions "IP6" */ +X/* Note: The set-in-gain ioctl exists but is non-functional */ +X +X#include <errno.h> +X#include <sys/audio.h> +X#include "asa.h" +X +X#include "allobjects.h" +X#include "modsupport.h" +X +Xstatic int audio_fd = -1; +X +Xstatic int +Xinit() +X{ +X if (audio_fd >= 0) +X return 1; +X if ((audio_fd = asa_init()) >= 0) +X return 1; +X err_setstr(RuntimeError, "can't initialize async audio"); +X return 0; +X} +X +X +X/* POSIX methods */ +X +Xstatic object * +Xaudio_get_ioctl(self, args, code) +X object *self; +X object *args; +X long code; +X{ +X long x; +X if (!getnoarg(args)) +X return NULL; +X if (!init()) +X return NULL; +X if ((x = ioctl(audio_fd, code, (char *) NULL)) < 0) { +X return NULL; +X } +X return newintobject(x); +X} +X +Xstatic object * +Xaudio_set_ioctl(self, args, code) +X object *self; +X object *args; +X long code; +X{ +X long x; +X if (!getlongarg(args, &x)) +X return NULL; +X if (!init()) +X return NULL; +X if (ioctl(audio_fd, code, (char *) x) != 0) +X return NULL; +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xaudio_getingain(self, args) +X object *self; +X object *args; +X{ +X return audio_get_ioctl(self, args, AUDIOCGETINGAIN); +X} +X +Xstatic object * +Xaudio_getoutgain(self, args) +X object *self; +X object *args; +X{ +X return audio_get_ioctl(self, args, AUDIOCGETOUTGAIN); +X} +X +Xstatic object * +Xaudio_setingain(self, args) +X object *self; +X object *args; +X{ +X return audio_set_ioctl(self, args, AUDIOCSETINGAIN); +X} +X +Xstatic object * +Xaudio_setoutgain(self, args) +X object *self; +X object *args; +X{ +X return audio_set_ioctl(self, args, AUDIOCSETOUTGAIN); +X} +X +Xstatic object * +Xaudio_setrate(self, args) +X object *self; +X object *args; +X{ +X return audio_set_ioctl(self, args, AUDIOCSETRATE); +X} +X +Xstatic object * +Xaudio_setduration(self, args) +X object *self; +X object *args; +X{ +X return audio_set_ioctl(self, args, AUDIOCDURATION); +X} +X +X/* Compute average bias, and remove it */ +X +Xstatic void +Xunbias(buf, len) +X char *buf; +X int len; +X{ +X register int i; +X register int c; +X register long bias; +X if (len == 0) +X return; +X bias = 0; +X for (i = 0; i < len; i++) { +X c = buf[i]; +X if (c > 127) +X c -= 256; +X bias += c; +X } +X bias = (bias + len/2) / len; /* Rounded average */ +X if (bias != 0) { +X for (i = 0; i < len; i++) { +X buf[i] -= bias; +X } +X } +X} +X +Xstatic object * +Xaudio_read(self, args) +X object *self; +X object *args; +X{ +X int c, i, n; +X object *v; +X char *s; +X if (!getintarg(args, &n)) +X return NULL; +X if (n <= 0) { +X err_setstr(RuntimeError, "audio.read: arg <= 0"); +X return NULL; +X } +X if (!init()) +X return NULL; +X v = newsizedstringobject((char *)NULL, n); +X if (v == NULL) +X return err_nomem(); +X s = getstringvalue(v); +X n = read(audio_fd, s, n); +X if (intrcheck()) { +X DECREF(v); +X err_set(KeyboardInterrupt); +X return NULL; +X } +X /* Check for errors */ +X if (n < 0) { +X DECREF(v); +X return NULL; +X } +X /* But EOF is reported as an empty string */ +X +X unbias(s, n); +X resizestring(&v, n); +X return v; +X} +X +Xstatic object * +Xaudio_write(self, args) +X object *self; +X object *args; +X{ +X int n, n2; +X object *v; +X if (!getstrarg(args, &v)) +X return NULL; +X if (!init()) +X return NULL; +X errno = 0; +X n2 = write(audio_fd, getstringvalue(v), n = getstringsize(v)); +X if (intrcheck()) { +X err_set(KeyboardInterrupt); +X return NULL; +X } +X /* Check for other errors */ +X if (n2 != n) { +X if (errno == 0) +X errno = EIO; +X return NULL; +X } +X INCREF(None); +X return None; +X} +X +X/* audio.amplify(sample, f1, f2). +X Amplify a sample by a factor changing from f1/256 to (almost) f2/256. +X Negative factors are allowed. Sound values that are to large +X to fit in a byte are clipped. */ +X +Xstatic object * +Xaudio_amplify(self, args) +X object *self; +X object *args; +X{ +X object *v; +X char *s, *t; +X int f1, f2; +X int i, n; +X int c; +X if (!getstrintintarg(args, &v, &f1, &f2)) +X return NULL; +X n = getstringsize(v); +X s = getstringvalue(v); +X v = newsizedstringobject((char *)NULL, n); +X if (v == NULL) +X return err_nomem(); +X t = getstringvalue(v); +X for (i = 0; i < n; i++) { +X c = s[i]; +X if (c > 127) c -= 256; /* If chars are unsigned */ +X c = c * ( f1*(n-i) + f2*i ) / ( n*256 ); +X if (c > 127) c = 127; +X else if (c < -128) c = -128; +X t[i] = c; +X } +X return v; +X} +X +X/* audio.reverse(s): return a sample backwards */ +X +Xstatic object * +Xaudio_reverse(self, args) +X object *self; +X object *args; +X{ +X object *v; +X char *s, *t; +X int i, n; +X if (!getstrarg(args, &v)) +X return NULL; +X n = getstringsize(v); +X s = getstringvalue(v); +X v = newsizedstringobject((char *)NULL, n); +X if (v == NULL) +X return err_nomem(); +X t = getstringvalue(v); +X for (i = 0; i < n; i++) { +X t[n-1-i] = s[i]; +X } +X return v; +X} +X +X/* audio.add(a, b): add two samples. +X Bytes that exceed the range are clipped. +X If one is shorter, the rest of the longer sample is returned unchanged. */ +X +Xstatic object * +Xaudio_add(self, args) +X object *self; +X object *args; +X{ +X object *a, *b, *v; +X char *sa, *sb, *t; +X int i, n, na, nb, c, ca, cb; +X if (!getstrstrarg(args, &a, &b)) +X return NULL; +X na = getstringsize(a); +X sa = getstringvalue(a); +X nb = getstringsize(b); +X sb = getstringvalue(b); +X n = (na > nb) ? na : nb; +X v = newsizedstringobject((char *)NULL, n); +X if (v == NULL) +X return err_nomem(); +X t = getstringvalue(v); +X for (i = 0; i < n; i++) { +X c = 0; +X if (i < na) { +X ca = sa[i]; +X if (ca > 127) ca = ca - 256; +X c = c + ca; +X } +X if (i < nb) { +X cb = sb[i]; +X if (cb > 127) cb = cb - 256; +X c = c + cb; +X } +X if (c > 127) c = 127; +X else if (c < -128) c = -128; +X t[i] = c; +X } +X return v; +X} +X +X/* audio.chr2num(s) returns a list containing the numeric values +X of the samples. */ +X +Xstatic object * +Xaudio_chr2num(self, args) +X object *self; +X object *args; +X{ +X object *v, *w; +X char *s; +X int c, i, n; +X static object *ints[256]; +X +X /* To avoid filling memory with all those int objects, we create +X integer objects for all the desired values and reference these. */ +X if (ints[255] == NULL) { +X for (i = 0; i < 256; i++) { +X if (ints[i] != NULL) +X continue; +X c = i; +X if (c > 127) c -= 256; +X ints[i] = newintobject((long)c); +X if (ints[i] == NULL) +X return NULL; +X } +X } +X +X if (!getstrarg(args, &v)) +X return NULL; +X n = getstringsize(v); +X s = getstringvalue(v); +X v = newlistobject(n); +X if (v == NULL) +X return err_nomem(); +X for (i = 0; i < n; i++) { +X c = s[i] & 0xff; +X w = ints[c]; +X INCREF(w); +X if (setlistitem(v, i, w) != 0) { +X DECREF(v); +X return NULL; +X } +X } +X return v; +X} +X +X/* audio.num2chr is the inverse of audio.chr2num. +X Excess values are clipped. */ +X +Xstatic object * +Xaudio_num2chr(self, args) +X object *self; +X object *args; +X{ +X object *v, *w; +X char *s; +X int c, i, n; +X if (!is_listobject(args)) { +X err_badarg(); +X return NULL; +X } +X n = getlistsize(args); +X v = newsizedstringobject((char *)NULL, n); +X if (v == NULL) +X return NULL; +X s = getstringvalue(v); +X for (i = 0; i < n; i++) { +X w = getlistitem(args, i); +X if (!is_intobject(w)) { +X DECREF(v); +X err_badarg(); +X return NULL; +X } +X s[i] = getintvalue(w); +X } +X return v; +X} +X +Xstatic object *stdaudio_buffer = NULL; +X +Xstatic object * +Xaudio_start_recording(self, args) +X object *self; +X object *args; +X{ +X int n; +X object *v; +X char *s; +X if (!getintarg(args, &n)) +X return NULL; +X if (stdaudio_buffer != NULL) { +X err_setstr(RuntimeError, "audio.start_recording: device busy"); +X return NULL; +X } +X if (n <= 0) { +X err_setstr(TypeError, "audio.start_recording: arg <= 0"); +X return NULL; +X } +X if (!init()) +X return NULL; +X v = newsizedstringobject((char *)NULL, n); +X if (v == NULL) +X return err_nomem(); +X s = getstringvalue(v); +X asa_start_read(s, n); +X stdaudio_buffer = v; +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xaudio_poll(self, args) +X object *self; +X object *args; +X{ +X int n; +X if (!getnoarg(args)) +X return NULL; +X if (stdaudio_buffer == NULL) { +X err_setstr(RuntimeError, "audio.poll: not busy"); +X return NULL; +X } +X if (!init()) +X return NULL; +X if ((n = asa_poll()) < 0) +X return NULL; +X return newintobject(n); +X} +X +Xstatic object * +Xaudio_wait_recording(self, args) +X object *self; +X object *args; +X{ +X object *v; +X int n; +X if (!getnoarg(args)) +X return NULL; +X if (stdaudio_buffer == NULL) { +X err_setstr(RuntimeError, "audio.wait_recording: not busy"); +X return NULL; +X } +X if (!init()) +X return NULL; +X if ((n = asa_wait()) < 0) +X return NULL; +X v = stdaudio_buffer; +X stdaudio_buffer = NULL; +X unbias(getstringvalue(v), n); +X resizestring(&v, n); +X return v; +X} +X +Xstatic object * +Xaudio_stop_recording(self, args) +X object *self; +X object *args; +X{ +X int n; +X object *v; +X char *s; +X if (!getnoarg(args)) +X return NULL; +X if (stdaudio_buffer == NULL) { +X err_setstr(RuntimeError, "audio.stop_recording: not busy"); +X return NULL; +X } +X if ((n = asa_cancel()) < 0) +X return NULL; +X v = stdaudio_buffer; +X stdaudio_buffer = NULL; +X s = getstringvalue(v); +X unbias(s, n); +X resizestring(&v, n); +X return v; +X} +X +Xstatic object * +Xaudio_start_playing(self, args) +X object *self; +X object *args; +X{ +X object *v; +X if (!getstrarg(args, &v)) +X return NULL; +X if (stdaudio_buffer != NULL) { +X err_setstr(RuntimeError, "audio.start_recording: device rbusy"); +X return NULL; +X } +X asa_start_write(getstringvalue(v), (int)getstringsize(v)); +X INCREF(v); +X stdaudio_buffer = v; +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xaudio_wait_playing(self, args) +X object *self; +X object *args; +X{ +X int n; +X if (!getnoarg(args)) +X return NULL; +X if (stdaudio_buffer == NULL) { +X err_setstr(RuntimeError, "audio.wait_playing: not busy"); +X return NULL; +X } +X if ((n = asa_wait()) < 0) +X return NULL; +X DECREF(stdaudio_buffer); +X stdaudio_buffer = NULL; +X /* XXX return newintobject((long)n); ??? */ +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xaudio_stop_playing(self, args) +X object *self; +X object *args; +X{ +X int n; +X if (!getnoarg(args)) +X return NULL; +X if (stdaudio_buffer == NULL) { +X err_setstr(RuntimeError, "audio.stop_playing: not busy"); +X return NULL; +X } +X if ((n = asa_cancel()) < 0) +X return NULL; +X DECREF(stdaudio_buffer); +X stdaudio_buffer = NULL; +X return newintobject((long)n); +X} +X +Xstatic object * +Xaudio_audio_done(self, args) +X object *self; +X object *args; +X{ +X if (!getnoarg(args)) +X return NULL; +X asa_done(); +X if (stdaudio_buffer != NULL) +X DECREF(stdaudio_buffer); +X stdaudio_buffer = NULL; +X audio_fd = -1; +X INCREF(None); +X return None; +X} +X +X +Xstatic struct methodlist audio_methods[] = { +X {"getingain", audio_getingain}, +X {"getoutgain", audio_getoutgain}, +X {"setingain", audio_setingain}, +X {"setoutgain", audio_setoutgain}, +X {"setrate", audio_setrate}, +X {"setduration", audio_setduration}, +X {"read", audio_read}, +X {"write", audio_write}, +X {"amplify", audio_amplify}, +X {"reverse", audio_reverse}, +X {"add", audio_add}, +X {"chr2num", audio_chr2num}, +X {"num2chr", audio_num2chr}, +X +X /* "asa" interface: */ +X +X {"start_recording", audio_start_recording}, +X {"poll_recording", audio_poll}, +X {"wait_recording", audio_wait_recording}, +X {"stop_recording", audio_stop_recording}, +X +X {"start_playing", audio_start_playing}, +X {"poll_playing", audio_poll}, +X {"wait_playing", audio_wait_playing}, +X {"stop_playing", audio_stop_playing}, +X +X {"done", audio_audio_done}, +X +X {NULL, NULL} /* Sentinel */ +X}; +X +Xvoid +Xinitaudio() +X{ +X initmodule("audio", audio_methods); +X} +EOF +fi +if test -s 'src/dictobject.c' +then echo '*** I will not over-write existing file src/dictobject.c' +else +echo 'x - src/dictobject.c' +sed 's/^X//' > 'src/dictobject.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Dictionary object implementation; using a hash table */ +X +X/* +XXXX Note -- although this may look professional, I didn't think very hard +Xabout the problem and it is possible that obvious improvements exist. +XA similar module that I saw by Chris Torek: +X- uses chaining instead of hashed linear probing +X- remembers the hash value with the entry to speed up table resizing +X- sets the table size to a power of 2 +X- uses a different hash function: +X h = 0; p = str; while (*p) h = (h<<5) - h + *p++; +X*/ +X +X#include "allobjects.h" +X +X +X/* +XTable of primes suitable as keys, in ascending order. +XThe first line are the largest primes less than some powers of two, +Xthe second line is the largest prime less than 6000, +Xand the third line is a selection from Knuth, Vol. 3, Sec. 6.1, Table 1. +XThe final value is a sentinel and should cause the memory allocation +Xof that many entries to fail (if none of the earlier values cause such +Xfailure already). +X*/ +Xstatic unsigned int primes[] = { +X 3, 7, 13, 31, 61, 127, 251, 509, 1021, 2017, 4093, +X 5987, +X 9551, 15683, 19609, 31397, +X 0xffffffff /* All bits set -- truncation OK */ +X}; +X +X/* String used as dummy key to fill deleted entries */ +Xstatic stringobject *dummy; /* Initialized by first call to newdictobject() */ +X +X/* +XInvariant for entries: when in use, de_value is not NULL and de_key is +Xnot NULL and not dummy; when not in use, de_value is NULL and de_key +Xis either NULL or dummy. A dummy key value cannot be replaced by NULL, +Xsince otherwise other keys may be lost. +X*/ +Xtypedef struct { +X stringobject *de_key; +X object *de_value; +X} dictentry; +X +X/* +XTo ensure the lookup algorithm terminates, the table size must be a +Xprime number and there must be at least one NULL key in the table. +XThe value di_fill is the number of non-NULL keys; di_used is the number +Xof non-NULL, non-dummy keys. +XTo avoid slowing down lookups on a near-full table, we resize the table +Xwhen it is more than half filled. +X*/ +Xtypedef struct { +X OB_HEAD +X int di_fill; +X int di_used; +X int di_size; +X dictentry *di_table; +X} dictobject; +X +Xobject * +Xnewdictobject() +X{ +X register dictobject *dp; +X if (dummy == NULL) { /* Auto-initialize dummy */ +X dummy = (stringobject *) newstringobject(""); +X if (dummy == NULL) +X return NULL; +X } +X dp = NEWOBJ(dictobject, &Dicttype); +X if (dp == NULL) +X return NULL; +X dp->di_size = primes[0]; +X dp->di_table = (dictentry *) calloc(sizeof(dictentry), dp->di_size); +X if (dp->di_table == NULL) { +X DEL(dp); +X return err_nomem(); +X } +X dp->di_fill = 0; +X dp->di_used = 0; +X return (object *)dp; +X} +X +X/* +XThe basic lookup function used by all operations. +XThis is essentially Algorithm D from Knuth Vol. 3, Sec. 6.4. +XOpen addressing is preferred over chaining since the link overhead for +Xchaining would be substantial (100% with typical malloc overhead). +X +XFirst a 32-bit hash value, 'sum', is computed from the key string. +XThe first character is added an extra time shifted by 8 to avoid hashing +Xsingle-character keys (often heavily used variables) too close together. +XAll arithmetic on sum should ignore overflow. +X +XThe initial probe index is then computed as sum mod the table size. +XSubsequent probe indices are incr apart (mod table size), where incr +Xis also derived from sum, with the additional requirement that it is +Xrelative prime to the table size (i.e., 1 <= incr < size, since the size +Xis a prime number). My choice for incr is somewhat arbitrary. +X*/ +Xstatic dictentry *lookdict PROTO((dictobject *, char *)); +Xstatic dictentry * +Xlookdict(dp, key) +X register dictobject *dp; +X char *key; +X{ +X register int i, incr; +X register dictentry *freeslot = NULL; +X register unsigned char *p = (unsigned char *) key; +X register unsigned long sum = *p << 7; +X while (*p != '\0') +X sum = sum + sum + *p++; +X i = sum % dp->di_size; +X do { +X sum = sum + sum + 1; +X incr = sum % dp->di_size; +X } while (incr == 0); +X for (;;) { +X register dictentry *ep = &dp->di_table[i]; +X if (ep->de_key == NULL) { +X if (freeslot != NULL) +X return freeslot; +X else +X return ep; +X } +X if (ep->de_key == dummy) { +X if (freeslot != NULL) +X freeslot = ep; +X } +X else if (GETSTRINGVALUE(ep->de_key)[0] == key[0]) { +X if (strcmp(GETSTRINGVALUE(ep->de_key), key) == 0) { +X return ep; +X } +X } +X i = (i + incr) % dp->di_size; +X } +X} +X +X/* +XInternal routine to insert a new item into the table. +XUsed both by the internal resize routine and by the public insert routine. +XEats a reference to key and one to value. +X*/ +Xstatic void insertdict PROTO((dictobject *, stringobject *, object *)); +Xstatic void +Xinsertdict(dp, key, value) +X register dictobject *dp; +X stringobject *key; +X object *value; +X{ +X register dictentry *ep; +X ep = lookdict(dp, GETSTRINGVALUE(key)); +X if (ep->de_value != NULL) { +X DECREF(ep->de_value); +X DECREF(key); +X } +X else { +X if (ep->de_key == NULL) +X dp->di_fill++; +X else +X DECREF(ep->de_key); +X ep->de_key = key; +X dp->di_used++; +X } +X ep->de_value = value; +X} +X +X/* +XRestructure the table by allocating a new table and reinserting all +Xitems again. When entries have been deleted, the new table may +Xactually be smaller than the old one. +X*/ +Xstatic int dictresize PROTO((dictobject *)); +Xstatic int +Xdictresize(dp) +X dictobject *dp; +X{ +X register int oldsize = dp->di_size; +X register int newsize; +X register dictentry *oldtable = dp->di_table; +X register dictentry *newtable; +X register dictentry *ep; +X register int i; +X newsize = dp->di_size; +X for (i = 0; ; i++) { +X if (primes[i] > dp->di_used*2) { +X newsize = primes[i]; +X break; +X } +X } +X newtable = (dictentry *) calloc(sizeof(dictentry), newsize); +X if (newtable == NULL) { +X err_nomem(); +X return -1; +X } +X dp->di_size = newsize; +X dp->di_table = newtable; +X dp->di_fill = 0; +X dp->di_used = 0; +X for (i = 0, ep = oldtable; i < oldsize; i++, ep++) { +X if (ep->de_value != NULL) +X insertdict(dp, ep->de_key, ep->de_value); +X else if (ep->de_key != NULL) +X DECREF(ep->de_key); +X } +X DEL(oldtable); +X return 0; +X} +X +Xobject * +Xdictlookup(op, key) +X object *op; +X char *key; +X{ +X if (!is_dictobject(op)) +X fatal("dictlookup on non-dictionary"); +X return lookdict((dictobject *)op, key) -> de_value; +X} +X +X#ifdef NOT_USED +Xstatic object * +Xdict2lookup(op, key) +X register object *op; +X register object *key; +X{ +X register object *res; +X if (!is_dictobject(op)) { +X err_badcall(); +X return NULL; +X } +X if (!is_stringobject(key)) { +X err_badarg(); +X return NULL; +X } +X res = lookdict((dictobject *)op, ((stringobject *)key)->ob_sval) +X -> de_value; +X if (res == NULL) +X err_setstr(KeyError, "key not in dictionary"); +X return res; +X} +X#endif +X +Xstatic int +Xdict2insert(op, key, value) +X register object *op; +X object *key; +X object *value; +X{ +X register dictobject *dp; +X register stringobject *keyobj; +X if (!is_dictobject(op)) { +X err_badcall(); +X return -1; +X } +X dp = (dictobject *)op; +X if (!is_stringobject(key)) { +X err_badarg(); +X return -1; +X } +X keyobj = (stringobject *)key; +X /* if fill >= 2/3 size, resize */ +X if (dp->di_fill*3 >= dp->di_size*2) { +X if (dictresize(dp) != 0) { +X if (dp->di_fill+1 > dp->di_size) +X return -1; +X } +X } +X INCREF(keyobj); +X INCREF(value); +X insertdict(dp, keyobj, value); +X return 0; +X} +X +Xint +Xdictinsert(op, key, value) +X object *op; +X char *key; +X object *value; +X{ +X register object *keyobj; +X register int err; +X keyobj = newstringobject(key); +X if (keyobj == NULL) { +X err_nomem(); +X return -1; +X } +X err = dict2insert(op, keyobj, value); +X DECREF(keyobj); +X return err; +X} +X +Xint +Xdictremove(op, key) +X object *op; +X char *key; +X{ +X register dictobject *dp; +X register dictentry *ep; +X if (!is_dictobject(op)) { +X err_badcall(); +X return -1; +X } +X dp = (dictobject *)op; +X ep = lookdict(dp, key); +X if (ep->de_value == NULL) { +X err_setstr(KeyError, "key not in dictionary"); +X return -1; +X } +X DECREF(ep->de_key); +X INCREF(dummy); +X ep->de_key = dummy; +X DECREF(ep->de_value); +X ep->de_value = NULL; +X dp->di_used--; +X return 0; +X} +X +Xstatic int +Xdict2remove(op, key) +X object *op; +X register object *key; +X{ +X if (!is_stringobject(key)) { +X err_badarg(); +X return -1; +X } +X return dictremove(op, GETSTRINGVALUE((stringobject *)key)); +X} +X +Xint +Xgetdictsize(op) +X register object *op; +X{ +X if (!is_dictobject(op)) { +X err_badcall(); +X return -1; +X } +X return ((dictobject *)op) -> di_size; +X} +X +Xstatic object * +Xgetdict2key(op, i) +X object *op; +X register int i; +X{ +X /* XXX This can't return errors since its callers assume +X that NULL means there was no key at that point */ +X register dictobject *dp; +X if (!is_dictobject(op)) { +X /* err_badcall(); */ +X return NULL; +X } +X dp = (dictobject *)op; +X if (i < 0 || i >= dp->di_size) { +X /* err_badarg(); */ +X return NULL; +X } +X if (dp->di_table[i].de_value == NULL) { +X /* Not an error! */ +X return NULL; +X } +X return (object *) dp->di_table[i].de_key; +X} +X +Xchar * +Xgetdictkey(op, i) +X object *op; +X int i; +X{ +X register object *keyobj = getdict2key(op, i); +X if (keyobj == NULL) +X return NULL; +X return GETSTRINGVALUE((stringobject *)keyobj); +X} +X +X/* Methods */ +X +Xstatic void +Xdict_dealloc(dp) +X register dictobject *dp; +X{ +X register int i; +X register dictentry *ep; +X for (i = 0, ep = dp->di_table; i < dp->di_size; i++, ep++) { +X if (ep->de_key != NULL) +X DECREF(ep->de_key); +X if (ep->de_value != NULL) +X DECREF(ep->de_value); +X } +X if (dp->di_table != NULL) +X DEL(dp->di_table); +X DEL(dp); +X} +X +Xstatic void +Xdict_print(dp, fp, flags) +X register dictobject *dp; +X register FILE *fp; +X register int flags; +X{ +X register int i; +X register int any; +X register dictentry *ep; +X fprintf(fp, "{"); +X any = 0; +X for (i = 0, ep = dp->di_table; i < dp->di_size && !StopPrint; +X i++, ep++) { +X if (ep->de_value != NULL) { +X if (any++ > 0) +X fprintf(fp, "; "); +X printobject((object *)ep->de_key, fp, flags); +X fprintf(fp, ": "); +X printobject(ep->de_value, fp, flags); +X } +X } +X fprintf(fp, "}"); +X} +X +Xstatic void +Xjs(pv, w) +X object **pv; +X object *w; +X{ +X joinstring(pv, w); +X if (w != NULL) +X DECREF(w); +X} +X +Xstatic object * +Xdict_repr(dp) +X dictobject *dp; +X{ +X auto object *v; +X register object *w; +X object *semi, *colon; +X register int i; +X register int any; +X register dictentry *ep; +X v = newstringobject("{"); +X semi = newstringobject("; "); +X colon = newstringobject(": "); +X any = 0; +X for (i = 0, ep = dp->di_table; i < dp->di_size && !StopPrint; +X i++, ep++) { +X if (ep->de_value != NULL) { +X if (any++) +X joinstring(&v, semi); +X js(&v, w = reprobject((object *)ep->de_key)); +X joinstring(&v, colon); +X js(&v, w = reprobject(ep->de_value)); +X } +X } +X js(&v, w = newstringobject("}")); +X if (semi != NULL) +X DECREF(semi); +X if (colon != NULL) +X DECREF(colon); +X return v; +X} +X +Xstatic int +Xdict_length(dp) +X dictobject *dp; +X{ +X return dp->di_used; +X} +X +Xstatic object * +Xdict_subscript(dp, v) +X dictobject *dp; +X register object *v; +X{ +X if (!is_stringobject(v)) { +X err_badarg(); +X return NULL; +X } +X v = lookdict(dp, GETSTRINGVALUE((stringobject *)v)) -> de_value; +X if (v == NULL) +X err_setstr(KeyError, "key not in dictionary"); +X else +X INCREF(v); +X return v; +X} +X +Xstatic int +Xdict_ass_sub(dp, v, w) +X dictobject *dp; +X object *v, *w; +X{ +X if (w == NULL) +X return dict2remove((object *)dp, v); +X else +X return dict2insert((object *)dp, v, w); +X} +X +Xstatic mapping_methods dict_as_mapping = { +X dict_length, /*mp_length*/ +X dict_subscript, /*mp_subscript*/ +X dict_ass_sub, /*mp_ass_subscript*/ +X}; +X +Xstatic object * +Xdict_keys(dp, args) +X register dictobject *dp; +X object *args; +X{ +X register object *v; +X register int i, j; +X if (!getnoarg(args)) +X return NULL; +X v = newlistobject(dp->di_used); +X if (v == NULL) +X return NULL; +X for (i = 0, j = 0; i < dp->di_size; i++) { +X if (dp->di_table[i].de_value != NULL) { +X stringobject *key = dp->di_table[i].de_key; +X INCREF(key); +X setlistitem(v, j, (object *)key); +X j++; +X } +X } +X return v; +X} +X +Xobject * +Xgetdictkeys(dp) +X object *dp; +X{ +X if (dp == NULL || !is_dictobject(dp)) { +X err_badcall(); +X return NULL; +X } +X return dict_keys((dictobject *)dp, (object *)NULL); +X} +X +Xstatic object * +Xdict_has_key(dp, args) +X register dictobject *dp; +X object *args; +X{ +X object *key; +X register long ok; +X if (!getstrarg(args, &key)) +X return NULL; +X ok = lookdict(dp, GETSTRINGVALUE((stringobject *)key))->de_value +X != NULL; +X return newintobject(ok); +X} +X +Xstatic struct methodlist dict_methods[] = { +X {"keys", dict_keys}, +X {"has_key", dict_has_key}, +X {NULL, NULL} /* sentinel */ +X}; +X +Xstatic object * +Xdict_getattr(dp, name) +X dictobject *dp; +X char *name; +X{ +X return findmethod(dict_methods, (object *)dp, name); +X} +X +Xtypeobject Dicttype = { +X OB_HEAD_INIT(&Typetype) +X 0, +X "dictionary", +X sizeof(dictobject), +X 0, +X dict_dealloc, /*tp_dealloc*/ +X dict_print, /*tp_print*/ +X dict_getattr, /*tp_getattr*/ +X 0, /*tp_setattr*/ +X 0, /*tp_compare*/ +X dict_repr, /*tp_repr*/ +X 0, /*tp_as_number*/ +X 0, /*tp_as_sequence*/ +X &dict_as_mapping, /*tp_as_mapping*/ +X}; +EOF +fi +if test -s 'src/pgen.c' +then echo '*** I will not over-write existing file src/pgen.c' +else +echo 'x - src/pgen.c' +sed 's/^X//' > 'src/pgen.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Parser generator */ +X/* XXX This file is not yet fully PROTOized */ +X +X/* For a description, see the comments at end of this file */ +X +X#include "pgenheaders.h" +X#include "assert.h" +X#include "token.h" +X#include "node.h" +X#include "grammar.h" +X#include "metagrammar.h" +X#include "pgen.h" +X +Xextern int debugging; +X +X +X/* PART ONE -- CONSTRUCT NFA -- Cf. Algorithm 3.2 from [Aho&Ullman 77] */ +X +Xtypedef struct _nfaarc { +X int ar_label; +X int ar_arrow; +X} nfaarc; +X +Xtypedef struct _nfastate { +X int st_narcs; +X nfaarc *st_arc; +X} nfastate; +X +Xtypedef struct _nfa { +X int nf_type; +X char *nf_name; +X int nf_nstates; +X nfastate *nf_state; +X int nf_start, nf_finish; +X} nfa; +X +Xstatic int +Xaddnfastate(nf) +X nfa *nf; +X{ +X nfastate *st; +X +X RESIZE(nf->nf_state, nfastate, nf->nf_nstates + 1); +X if (nf->nf_state == NULL) +X fatal("out of mem"); +X st = &nf->nf_state[nf->nf_nstates++]; +X st->st_narcs = 0; +X st->st_arc = NULL; +X return st - nf->nf_state; +X} +X +Xstatic void +Xaddnfaarc(nf, from, to, lbl) +X nfa *nf; +X int from, to, lbl; +X{ +X nfastate *st; +X nfaarc *ar; +X +X st = &nf->nf_state[from]; +X RESIZE(st->st_arc, nfaarc, st->st_narcs + 1); +X if (st->st_arc == NULL) +X fatal("out of mem"); +X ar = &st->st_arc[st->st_narcs++]; +X ar->ar_label = lbl; +X ar->ar_arrow = to; +X} +X +Xstatic nfa * +Xnewnfa(name) +X char *name; +X{ +X nfa *nf; +X static type = NT_OFFSET; /* All types will be disjunct */ +X +X nf = NEW(nfa, 1); +X if (nf == NULL) +X fatal("no mem for new nfa"); +X nf->nf_type = type++; +X nf->nf_name = name; /* XXX strdup(name) ??? */ +X nf->nf_nstates = 0; +X nf->nf_state = NULL; +X nf->nf_start = nf->nf_finish = -1; +X return nf; +X} +X +Xtypedef struct _nfagrammar { +X int gr_nnfas; +X nfa **gr_nfa; +X labellist gr_ll; +X} nfagrammar; +X +Xstatic nfagrammar * +Xnewnfagrammar() +X{ +X nfagrammar *gr; +X +X gr = NEW(nfagrammar, 1); +X if (gr == NULL) +X fatal("no mem for new nfa grammar"); +X gr->gr_nnfas = 0; +X gr->gr_nfa = NULL; +X gr->gr_ll.ll_nlabels = 0; +X gr->gr_ll.ll_label = NULL; +X addlabel(&gr->gr_ll, ENDMARKER, "EMPTY"); +X return gr; +X} +X +Xstatic nfa * +Xaddnfa(gr, name) +X nfagrammar *gr; +X char *name; +X{ +X nfa *nf; +X +X nf = newnfa(name); +X RESIZE(gr->gr_nfa, nfa *, gr->gr_nnfas + 1); +X if (gr->gr_nfa == NULL) +X fatal("out of mem"); +X gr->gr_nfa[gr->gr_nnfas++] = nf; +X addlabel(&gr->gr_ll, NAME, nf->nf_name); +X return nf; +X} +X +X#ifdef DEBUG +X +Xstatic char REQNFMT[] = "metacompile: less than %d children\n"; +X +X#define REQN(i, count) \ +X if (i < count) { \ +X fprintf(stderr, REQNFMT, count); \ +X abort(); \ +X } else +X +X#else +X#define REQN(i, count) /* empty */ +X#endif +X +Xstatic nfagrammar * +Xmetacompile(n) +X node *n; +X{ +X nfagrammar *gr; +X int i; +X +X printf("Compiling (meta-) parse tree into NFA grammar\n"); +X gr = newnfagrammar(); +X REQ(n, MSTART); +X i = n->n_nchildren - 1; /* Last child is ENDMARKER */ +X n = n->n_child; +X for (; --i >= 0; n++) { +X if (n->n_type != NEWLINE) +X compile_rule(gr, n); +X } +X return gr; +X} +X +Xstatic +Xcompile_rule(gr, n) +X nfagrammar *gr; +X node *n; +X{ +X nfa *nf; +X +X REQ(n, RULE); +X REQN(n->n_nchildren, 4); +X n = n->n_child; +X REQ(n, NAME); +X nf = addnfa(gr, n->n_str); +X n++; +X REQ(n, COLON); +X n++; +X REQ(n, RHS); +X compile_rhs(&gr->gr_ll, nf, n, &nf->nf_start, &nf->nf_finish); +X n++; +X REQ(n, NEWLINE); +X} +X +Xstatic +Xcompile_rhs(ll, nf, n, pa, pb) +X labellist *ll; +X nfa *nf; +X node *n; +X int *pa, *pb; +X{ +X int i; +X int a, b; +X +X REQ(n, RHS); +X i = n->n_nchildren; +X REQN(i, 1); +X n = n->n_child; +X REQ(n, ALT); +X compile_alt(ll, nf, n, pa, pb); +X if (--i <= 0) +X return; +X n++; +X a = *pa; +X b = *pb; +X *pa = addnfastate(nf); +X *pb = addnfastate(nf); +X addnfaarc(nf, *pa, a, EMPTY); +X addnfaarc(nf, b, *pb, EMPTY); +X for (; --i >= 0; n++) { +X REQ(n, VBAR); +X REQN(i, 1); +X --i; +X n++; +X REQ(n, ALT); +X compile_alt(ll, nf, n, &a, &b); +X addnfaarc(nf, *pa, a, EMPTY); +X addnfaarc(nf, b, *pb, EMPTY); +X } +X} +X +Xstatic +Xcompile_alt(ll, nf, n, pa, pb) +X labellist *ll; +X nfa *nf; +X node *n; +X int *pa, *pb; +X{ +X int i; +X int a, b; +X +X REQ(n, ALT); +X i = n->n_nchildren; +X REQN(i, 1); +X n = n->n_child; +X REQ(n, ITEM); +X compile_item(ll, nf, n, pa, pb); +X --i; +X n++; +X for (; --i >= 0; n++) { +X if (n->n_type == COMMA) { /* XXX Temporary */ +X REQN(i, 1); +X --i; +X n++; +X } +X REQ(n, ITEM); +X compile_item(ll, nf, n, &a, &b); +X addnfaarc(nf, *pb, a, EMPTY); +X *pb = b; +X } +X} +X +Xstatic +Xcompile_item(ll, nf, n, pa, pb) +X labellist *ll; +X nfa *nf; +X node *n; +X int *pa, *pb; +X{ +X int i; +X int a, b; +X +X REQ(n, ITEM); +X i = n->n_nchildren; +X REQN(i, 1); +X n = n->n_child; +X if (n->n_type == LSQB) { +X REQN(i, 3); +X n++; +X REQ(n, RHS); +X *pa = addnfastate(nf); +X *pb = addnfastate(nf); +X addnfaarc(nf, *pa, *pb, EMPTY); +X compile_rhs(ll, nf, n, &a, &b); +X addnfaarc(nf, *pa, a, EMPTY); +X addnfaarc(nf, b, *pb, EMPTY); +X REQN(i, 1); +X n++; +X REQ(n, RSQB); +X } +X else { +X compile_atom(ll, nf, n, pa, pb); +X if (--i <= 0) +X return; +X n++; +X addnfaarc(nf, *pb, *pa, EMPTY); +X if (n->n_type == STAR) +X *pb = *pa; +X else +X REQ(n, PLUS); +X } +X} +X +Xstatic +Xcompile_atom(ll, nf, n, pa, pb) +X labellist *ll; +X nfa *nf; +X node *n; +X int *pa, *pb; +X{ +X int i; +X +X REQ(n, ATOM); +X i = n->n_nchildren; +X REQN(i, 1); +X n = n->n_child; +X if (n->n_type == LPAR) { +X REQN(i, 3); +X n++; +X REQ(n, RHS); +X compile_rhs(ll, nf, n, pa, pb); +X n++; +X REQ(n, RPAR); +X } +X else if (n->n_type == NAME || n->n_type == STRING) { +X *pa = addnfastate(nf); +X *pb = addnfastate(nf); +X addnfaarc(nf, *pa, *pb, addlabel(ll, n->n_type, n->n_str)); +X } +X else +X REQ(n, NAME); +X} +X +Xstatic void +Xdumpstate(ll, nf, istate) +X labellist *ll; +X nfa *nf; +X int istate; +X{ +X nfastate *st; +X int i; +X nfaarc *ar; +X +X printf("%c%2d%c", +X istate == nf->nf_start ? '*' : ' ', +X istate, +X istate == nf->nf_finish ? '.' : ' '); +X st = &nf->nf_state[istate]; +X ar = st->st_arc; +X for (i = 0; i < st->st_narcs; i++) { +X if (i > 0) +X printf("\n "); +X printf("-> %2d %s", ar->ar_arrow, +X labelrepr(&ll->ll_label[ar->ar_label])); +X ar++; +X } +X printf("\n"); +X} +X +Xstatic void +Xdumpnfa(ll, nf) +X labellist *ll; +X nfa *nf; +X{ +X int i; +X +X printf("NFA '%s' has %d states; start %d, finish %d\n", +X nf->nf_name, nf->nf_nstates, nf->nf_start, nf->nf_finish); +X for (i = 0; i < nf->nf_nstates; i++) +X dumpstate(ll, nf, i); +X} +X +X +X/* PART TWO -- CONSTRUCT DFA -- Algorithm 3.1 from [Aho&Ullman 77] */ +X +Xstatic int +Xaddclosure(ss, nf, istate) +X bitset ss; +X nfa *nf; +X int istate; +X{ +X if (addbit(ss, istate)) { +X nfastate *st = &nf->nf_state[istate]; +X nfaarc *ar = st->st_arc; +X int i; +X +X for (i = st->st_narcs; --i >= 0; ) { +X if (ar->ar_label == EMPTY) +X addclosure(ss, nf, ar->ar_arrow); +X ar++; +X } +X } +X} +X +Xtypedef struct _ss_arc { +X bitset sa_bitset; +X int sa_arrow; +X int sa_label; +X} ss_arc; +X +Xtypedef struct _ss_state { +X bitset ss_ss; +X int ss_narcs; +X ss_arc *ss_arc; +X int ss_deleted; +X int ss_finish; +X int ss_rename; +X} ss_state; +X +Xtypedef struct _ss_dfa { +X int sd_nstates; +X ss_state *sd_state; +X} ss_dfa; +X +Xstatic +Xmakedfa(gr, nf, d) +X nfagrammar *gr; +X nfa *nf; +X dfa *d; +X{ +X int nbits = nf->nf_nstates; +X bitset ss; +X int xx_nstates; +X ss_state *xx_state, *yy; +X ss_arc *zz; +X int istate, jstate, iarc, jarc, ibit; +X nfastate *st; +X nfaarc *ar; +X +X ss = newbitset(nbits); +X addclosure(ss, nf, nf->nf_start); +X xx_state = NEW(ss_state, 1); +X if (xx_state == NULL) +X fatal("no mem for xx_state in makedfa"); +X xx_nstates = 1; +X yy = &xx_state[0]; +X yy->ss_ss = ss; +X yy->ss_narcs = 0; +X yy->ss_arc = NULL; +X yy->ss_deleted = 0; +X yy->ss_finish = testbit(ss, nf->nf_finish); +X if (yy->ss_finish) +X printf("Error: nonterminal '%s' may produce empty.\n", +X nf->nf_name); +X +X /* This algorithm is from a book written before +X the invention of structured programming... */ +X +X /* For each unmarked state... */ +X for (istate = 0; istate < xx_nstates; ++istate) { +X yy = &xx_state[istate]; +X ss = yy->ss_ss; +X /* For all its states... */ +X for (ibit = 0; ibit < nf->nf_nstates; ++ibit) { +X if (!testbit(ss, ibit)) +X continue; +X st = &nf->nf_state[ibit]; +X /* For all non-empty arcs from this state... */ +X for (iarc = 0; iarc < st->st_narcs; iarc++) { +X ar = &st->st_arc[iarc]; +X if (ar->ar_label == EMPTY) +X continue; +X /* Look up in list of arcs from this state */ +X for (jarc = 0; jarc < yy->ss_narcs; ++jarc) { +X zz = &yy->ss_arc[jarc]; +X if (ar->ar_label == zz->sa_label) +X goto found; +X } +X /* Add new arc for this state */ +X RESIZE(yy->ss_arc, ss_arc, yy->ss_narcs + 1); +X if (yy->ss_arc == NULL) +X fatal("out of mem"); +X zz = &yy->ss_arc[yy->ss_narcs++]; +X zz->sa_label = ar->ar_label; +X zz->sa_bitset = newbitset(nbits); +X zz->sa_arrow = -1; +X found: ; +X /* Add destination */ +X addclosure(zz->sa_bitset, nf, ar->ar_arrow); +X } +X } +X /* Now look up all the arrow states */ +X for (jarc = 0; jarc < xx_state[istate].ss_narcs; jarc++) { +X zz = &xx_state[istate].ss_arc[jarc]; +X for (jstate = 0; jstate < xx_nstates; jstate++) { +X if (samebitset(zz->sa_bitset, +X xx_state[jstate].ss_ss, nbits)) { +X zz->sa_arrow = jstate; +X goto done; +X } +X } +X RESIZE(xx_state, ss_state, xx_nstates + 1); +X if (xx_state == NULL) +X fatal("out of mem"); +X zz->sa_arrow = xx_nstates; +X yy = &xx_state[xx_nstates++]; +X yy->ss_ss = zz->sa_bitset; +X yy->ss_narcs = 0; +X yy->ss_arc = NULL; +X yy->ss_deleted = 0; +X yy->ss_finish = testbit(yy->ss_ss, nf->nf_finish); +X done: ; +X } +X } +X +X if (debugging) +X printssdfa(xx_nstates, xx_state, nbits, &gr->gr_ll, +X "before minimizing"); +X +X simplify(xx_nstates, xx_state); +X +X if (debugging) +X printssdfa(xx_nstates, xx_state, nbits, &gr->gr_ll, +X "after minimizing"); +X +X convert(d, xx_nstates, xx_state); +X +X /* XXX cleanup */ +X} +X +Xstatic +Xprintssdfa(xx_nstates, xx_state, nbits, ll, msg) +X int xx_nstates; +X ss_state *xx_state; +X int nbits; +X labellist *ll; +X char *msg; +X{ +X int i, ibit, iarc; +X ss_state *yy; +X ss_arc *zz; +X +X printf("Subset DFA %s\n", msg); +X for (i = 0; i < xx_nstates; i++) { +X yy = &xx_state[i]; +X if (yy->ss_deleted) +X continue; +X printf(" Subset %d", i); +X if (yy->ss_finish) +X printf(" (finish)"); +X printf(" { "); +X for (ibit = 0; ibit < nbits; ibit++) { +X if (testbit(yy->ss_ss, ibit)) +X printf("%d ", ibit); +X } +X printf("}\n"); +X for (iarc = 0; iarc < yy->ss_narcs; iarc++) { +X zz = &yy->ss_arc[iarc]; +X printf(" Arc to state %d, label %s\n", +X zz->sa_arrow, +X labelrepr(&ll->ll_label[zz->sa_label])); +X } +X } +X} +X +X +X/* PART THREE -- SIMPLIFY DFA */ +X +X/* Simplify the DFA by repeatedly eliminating states that are +X equivalent to another oner. This is NOT Algorithm 3.3 from +X [Aho&Ullman 77]. It does not always finds the minimal DFA, +X but it does usually make a much smaller one... (For an example +X of sub-optimal behaviour, try S: x a b+ | y a b+.) +X*/ +X +Xstatic int +Xsamestate(s1, s2) +X ss_state *s1, *s2; +X{ +X int i; +X +X if (s1->ss_narcs != s2->ss_narcs || s1->ss_finish != s2->ss_finish) +X return 0; +X for (i = 0; i < s1->ss_narcs; i++) { +X if (s1->ss_arc[i].sa_arrow != s2->ss_arc[i].sa_arrow || +X s1->ss_arc[i].sa_label != s2->ss_arc[i].sa_label) +X return 0; +X } +X return 1; +X} +X +Xstatic void +Xrenamestates(xx_nstates, xx_state, from, to) +X int xx_nstates; +X ss_state *xx_state; +X int from, to; +X{ +X int i, j; +X +X if (debugging) +X printf("Rename state %d to %d.\n", from, to); +X for (i = 0; i < xx_nstates; i++) { +X if (xx_state[i].ss_deleted) +X continue; +X for (j = 0; j < xx_state[i].ss_narcs; j++) { +X if (xx_state[i].ss_arc[j].sa_arrow == from) +X xx_state[i].ss_arc[j].sa_arrow = to; +X } +X } +X} +X +Xstatic +Xsimplify(xx_nstates, xx_state) +X int xx_nstates; +X ss_state *xx_state; +X{ +X int changes; +X int i, j, k; +X +X do { +X changes = 0; +X for (i = 1; i < xx_nstates; i++) { +X if (xx_state[i].ss_deleted) +X continue; +X for (j = 0; j < i; j++) { +X if (xx_state[j].ss_deleted) +X continue; +X if (samestate(&xx_state[i], &xx_state[j])) { +X xx_state[i].ss_deleted++; +X renamestates(xx_nstates, xx_state, i, j); +X changes++; +X break; +X } +X } +X } +X } while (changes); +X} +X +X +X/* PART FOUR -- GENERATE PARSING TABLES */ +X +X/* Convert the DFA into a grammar that can be used by our parser */ +X +Xstatic +Xconvert(d, xx_nstates, xx_state) +X dfa *d; +X int xx_nstates; +X ss_state *xx_state; +X{ +X int i, j; +X ss_state *yy; +X ss_arc *zz; +X +X for (i = 0; i < xx_nstates; i++) { +X yy = &xx_state[i]; +X if (yy->ss_deleted) +X continue; +X yy->ss_rename = addstate(d); +X } +X +X for (i = 0; i < xx_nstates; i++) { +X yy = &xx_state[i]; +X if (yy->ss_deleted) +X continue; +X for (j = 0; j < yy->ss_narcs; j++) { +X zz = &yy->ss_arc[j]; +X addarc(d, yy->ss_rename, +X xx_state[zz->sa_arrow].ss_rename, +X zz->sa_label); +X } +X if (yy->ss_finish) +X addarc(d, yy->ss_rename, yy->ss_rename, 0); +X } +X +X d->d_initial = 0; +X} +X +X +X/* PART FIVE -- GLUE IT ALL TOGETHER */ +X +Xstatic grammar * +Xmaketables(gr) +X nfagrammar *gr; +X{ +X int i; +X nfa *nf; +X dfa *d; +X grammar *g; +X +X if (gr->gr_nnfas == 0) +X return NULL; +X g = newgrammar(gr->gr_nfa[0]->nf_type); +X /* XXX first rule must be start rule */ +X g->g_ll = gr->gr_ll; +X +X for (i = 0; i < gr->gr_nnfas; i++) { +X nf = gr->gr_nfa[i]; +X if (debugging) { +X printf("Dump of NFA for '%s' ...\n", nf->nf_name); +X dumpnfa(&gr->gr_ll, nf); +X } +X printf("Making DFA for '%s' ...\n", nf->nf_name); +X d = adddfa(g, nf->nf_type, nf->nf_name); +X makedfa(gr, gr->gr_nfa[i], d); +X } +X +X return g; +X} +X +Xgrammar * +Xpgen(n) +X node *n; +X{ +X nfagrammar *gr; +X grammar *g; +X +X gr = metacompile(n); +X g = maketables(gr); +X translatelabels(g); +X addfirstsets(g); +X return g; +X} +X +X +X/* +X +XDescription +X----------- +X +XInput is a grammar in extended BNF (using * for repetition, + for +Xat-least-once repetition, [] for optional parts, | for alternatives and +X() for grouping). This has already been parsed and turned into a parse +Xtree. +X +XEach rule is considered as a regular expression in its own right. +XIt is turned into a Non-deterministic Finite Automaton (NFA), which +Xis then turned into a Deterministic Finite Automaton (DFA), which is then +Xoptimized to reduce the number of states. See [Aho&Ullman 77] chapter 3, +Xor similar compiler books (this technique is more often used for lexical +Xanalyzers). +X +XThe DFA's are used by the parser as parsing tables in a special way +Xthat's probably unique. Before they are usable, the FIRST sets of all +Xnon-terminals are computed. +X +XReference +X--------- +X +X[Aho&Ullman 77] +X Aho&Ullman, Principles of Compiler Design, Addison-Wesley 1977 +X (first edition) +X +X*/ +EOF +fi +if test -s 'src/regexpmodule.c' +then echo '*** I will not over-write existing file src/regexpmodule.c' +else +echo 'x - src/regexpmodule.c' +sed 's/^X//' > 'src/regexpmodule.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Regular expression objects */ +X/* This needs V8 or Henry Spencer's regexp! */ +X +X#include "allobjects.h" +X#include "modsupport.h" +X +X#include "regexp.h" +X +Xstatic object *RegexpError; /* Exception */ +X +Xtypedef struct { +X OB_HEAD +X object *re_string; /* The string (for printing) */ +X regexp *re_prog; /* The compiled regular expression */ +X} regexpobject; +X +Xextern typeobject Regexptype; /* Really static, forward */ +X +Xstatic regexpobject * +Xnewregexpobject(string, prog) +X object *string; +X regexp *prog; +X{ +X regexpobject *re; +X re = NEWOBJ(regexpobject, &Regexptype); +X if (re != NULL) { +X XINCREF(string); +X re->re_string = string; +X re->re_prog = prog; +X } +X return re; +X} +X +X/* Regexp methods */ +X +Xstatic void +Xregexp_dealloc(re) +X regexpobject *re; +X{ +X XDECREF(re->re_string); +X XDEL(re->re_prog); +X DEL(re); +X} +X +Xstatic object * +Xmakeresult(prog, buffer) +X regexp *prog; +X char *buffer; +X{ +X int n; +X object *v; +X /* Count substrings found, including \0, the main one */ +X for (n = 0; n < 10 && prog->startp[n] != NULL; n++) +X ; +X v = newtupleobject(n); +X if (v != NULL) { +X int i; +X for (i = 0; i < n; i++) { +X object *w, *u; +X long start, end; +X start = prog->startp[i] - buffer; +X end = prog->endp[i] - buffer; +X if ( (w = newtupleobject(2)) == NULL || +X (u = newintobject(start)) == NULL || +X settupleitem(w, 0, u) != 0 || +X (u = newintobject(end)) == NULL || +X settupleitem(w, 1, u) != 0) { +X XDECREF(w); +X DECREF(v); +X return NULL; +X } +X settupleitem(v, i, w); +X } +X } +X return v; +X} +X +Xstatic object * +Xregexp_exec(re, args) +X regexpobject *re; +X object *args; +X{ +X object *v; +X char *buffer; +X int offset; +X if (args != NULL && is_stringobject(args)) { +X v = args; +X offset = 0; +X } +X else if (!getstrintarg(args, &v, &offset)) +X return NULL; +X buffer = getstringvalue(v); +X#ifndef MULTILINE +X#define reglexec(prog, str, offset) regexec((prog), (str)+(offset)) +X#endif +X if (!reglexec(re->re_prog, buffer, offset)) +X return newtupleobject(0); +X return makeresult(re->re_prog, buffer); +X} +X +Xstatic struct methodlist regexp_methods[] = { +X "exec", regexp_exec, +X {NULL, NULL} /* sentinel */ +X}; +X +Xstatic object * +Xregexp_getattr(re, name) +X regexpobject *re; +X char *name; +X{ +X return findmethod(regexp_methods, (object *)re, name); +X} +X +Xstatic typeobject Regexptype = { +X OB_HEAD_INIT(&Typetype) +X 0, /*ob_size*/ +X "regexp", /*tp_name*/ +X sizeof(regexpobject), /*tp_size*/ +X 0, /*tp_itemsize*/ +X /* methods */ +X regexp_dealloc, /*tp_dealloc*/ +X 0, /*tp_print*/ +X regexp_getattr, /*tp_getattr*/ +X 0, /*tp_setattr*/ +X 0, /*tp_compare*/ +X 0, /*tp_repr*/ +X}; +X +Xvoid +Xregerror(str) +X char *str; +X{ +X err_setstr(RegexpError, str); +X} +X +Xstatic object * +Xregexp_compile(self, args) +X object *self; +X object *args; +X{ +X object *string; +X regexp *prog; +X if (!getstrarg(args, &string)) +X return NULL; +X prog = regcomp(getstringvalue(string)); +X if (prog == NULL) +X return NULL; /* regerror() has called err_seterr() */ +X return (object *)newregexpobject(string, prog); +X} +X +Xstatic struct methodlist regexp_global_methods[] = { +X {"compile", regexp_compile}, +X {NULL, NULL} /* sentinel */ +X}; +X +Xinitregexp() +X{ +X object *m, *d; +X +X m = initmodule("regexp", regexp_global_methods); +X d = getmoduledict(m); +X +X /* Initialize regexp.error exception */ +X RegexpError = newstringobject("regexp.error"); +X if (RegexpError == NULL || dictinsert(d, "error", RegexpError) != 0) +X fatal("can't define regexp.error"); +X} +EOF +fi +echo 'Part 09 out of 21 of pack.out complete.' +exit 0 diff --git a/shar/python-0.9.1-10-21.shar b/shar/python-0.9.1-10-21.shar new file mode 100644 index 0000000..962819a --- /dev/null +++ b/shar/python-0.9.1-10-21.shar @@ -0,0 +1,2508 @@ +: This is a shell archive. +: Extract with 'sh this_file'. +: +: Extract part 01 first since it makes all directories +echo 'Start of pack.out, part 10 out of 21:' +if test -s 'demo/sgi/gl_panel/flying/light.py' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/flying/light.py' +else +echo 'x - demo/sgi/gl_panel/flying/light.py' +sed 's/^X//' > 'demo/sgi/gl_panel/flying/light.py' << 'EOF' +Xfrom GL import * +Xfrom gl import * +X +X# identity matrix +Xidmat=[1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0] +X +X# the different materials. +Xm1=[SPECULAR,0.8,0.0,0.0,DIFFUSE,0.4,0.0,0.0,SHININESS,40.0,LMNULL] +Xm2=[SPECULAR,1.0,0.4,0.0,DIFFUSE,1.0,0.4,0.0,SHININESS,80.0,LMNULL] +Xm3=[SPECULAR,0.0,0.0,0.6,DIFFUSE,0.0,0.0,0.8,SHININESS,60.0,LMNULL] +Xm4=[SPECULAR,0.0,1.0,0.0,DIFFUSE,0.0,0.6,0.0,SHININESS,120.0,LMNULL] +Xm5=[SPECULAR,1.0,1.0,0.0,DIFFUSE,0.6,0.6,0.0,SHININESS,100.0,LMNULL] +Xm6=[SPECULAR,1.0,0.0,1.0,DIFFUSE,0.6,0.0,0.6,SHININESS,120.0,LMNULL] +Xm7=[SPECULAR,0.9,0.9,0.9,DIFFUSE,0.6,0.6,0.6,SHININESS,120.0,LMNULL] +Xm8=[SPECULAR,0.4,0.7,0.4,DIFFUSE,0.5,1.0,0.5,SHININESS,50.0,LMNULL] +Xm9=[SPECULAR,0.2,0.0,0.1,DIFFUSE,0.8,0.0,0.3,SHININESS,10.0,LMNULL] +X +X#the lightsources. +Xlight1 = [LCOLOR,1.0,1.0,1.0,POSITION,10.0,10.0,5.0,0.0,LMNULL] +Xlight2 = [LCOLOR,1.0,1.0,1.0,POSITION,-10.0,10.0,5.0,0.0,LMNULL] +X +X# the lightmodel. +Xmodel = [AMBIENT,0.4,0.4,0.4,LMNULL] +X +Xdef bindlight (bool) : +X # Initializes all settings for a window. +X if bool <> 0 : +X mmode(MVIEWING) +X perspective (900, 1.0, 1.0, 35.0) +X loadmatrix(idmat) +X # define materials and lights +X lmdef(DEFMATERIAL, 1, m1) +X lmdef(DEFMATERIAL, 2, m2) +X lmdef(DEFMATERIAL, 3, m3) +X lmdef(DEFMATERIAL, 4, m4) +X lmdef(DEFMATERIAL, 5, m5) +X lmdef(DEFMATERIAL, 6, m6) +X lmdef(DEFMATERIAL, 7, m7) +X lmdef(DEFMATERIAL, 8, m8) +X lmdef(DEFMATERIAL, 9, m9) +X lmdef(DEFLIGHT, 1, light1) +X lmdef(DEFLIGHT, 2, light2) +X lmdef(DEFLMODEL, 1, model) +X lmbind(LIGHT0,1) +X lmbind(LIGHT1,2) +X lmbind(LMODEL,1) +EOF +fi +if test -s 'demo/stdwin/wdiff.py' +then echo '*** I will not over-write existing file demo/stdwin/wdiff.py' +else +echo 'x - demo/stdwin/wdiff.py' +sed 's/^X//' > 'demo/stdwin/wdiff.py' << 'EOF' +X#! /ufs/guido/bin/sgi/python +X +X# A window-oriented recursive diff utility. +X# NB: This uses undocumented window classing modules. +X +X# TO DO: +X# - faster update after moving/copying one file +X# - diff flags (-b, etc.) should be global or maintained per window +X# - use a few fixed windows instead of creating new ones all the time +X# - ways to specify patterns to skip +X# (best by pointing at a file and clicking a special menu entry!) +X# - add rcsdiff menu commands +X# - add a way to view status of selected files without opening them +X# - add a way to diff two files with different names +X# - add a way to rename files +X# - keep backups of overwritten/deleted files +X# - a way to mark specified files as uninteresting for dircmp +X +Ximport sys +Ximport posix +Ximport path +Ximport rand +Ximport commands +Ximport dircache +Ximport statcache +Ximport cmp +Ximport cmpcache +Ximport stdwin +Ximport gwin +Ximport textwin +Ximport filewin +Ximport tablewin +Ximport anywin +X +Xmkarg = commands.mkarg +Xmk2arg = commands.mk2arg +X +X# List of names to ignore in dircmp() +X# (Should be done with function, so we can specify patterns as well) +X# +Xskiplist = ['RCS', '.Amake', 'tags', '.', '..'] +X +X +Xdef anydiff(a, b, flags): # Display differences between any two objects +X print 'diff', flags, a, b +X if path.isdir(a) and path.isdir(b): +X w = dirdiff(a, b, flags) +X else: +X w = filediff(a, b, flags) +X addstatmenu(w, [a, b]) +X w.original_close = w.close +X w.close = close_dirwin +X return w +X +Xdef close_dirwin(w): +X close_subwindows(w, (), 0) +X w.original_close(w) +X +Xdef filediff(a, b, flags): # Display differences between two text files +X diffcmd = 'diff' +X if flags: diffcmd = diffcmd + mkarg(flags) +X diffcmd = diffcmd + mkarg(a) + mkarg(b) +X difftext = commands.getoutput(diffcmd) +X return textwin.open_readonly(mktitle(a, b), difftext) +X +Xdef dirdiff(a, b, flags): # Display differences between two directories +X data = diffdata(a, b, flags) +X w = tablewin.open(mktitle(a, b), data) +X w.flags = flags +X w.a = a +X w.b = b +X addviewmenu(w) +X addactionmenu(w) +X return w +X +Xdef diffdata(a, b, flags): # Compute directory differences. +X # +X a_only = [('A only:', header_action), ('', header_action)] +X b_only = [('B only:', header_action), ('', header_action)] +X ab_diff = [('A <> B:', header_action), ('', header_action)] +X ab_same = [('A == B:', header_action), ('', header_action)] +X data = [a_only, b_only, ab_diff, ab_same] +X # +X a_list = dircache.listdir(a)[:] +X b_list = dircache.listdir(b)[:] +X dircache.annotate(a, a_list) +X dircache.annotate(b, b_list) +X a_list.sort() +X b_list.sort() +X # +X for x in a_list: +X if x in ['./', '../']: +X pass +X elif x not in b_list: +X a_only.append(x, a_only_action) +X else: +X ax = path.cat(a, x) +X bx = path.cat(b, x) +X if path.isdir(ax) and path.isdir(bx): +X if flags = '-r': +X same = dircmp(ax, bx) +X else: +X same = 0 +X else: +X try: +X same = cmp.cmp(ax, bx) +X except posix.error: +X same = 0 +X if same: +X ab_same.append(x, ab_same_action) +X else: +X ab_diff.append(x, ab_diff_action) +X # +X for x in b_list: +X if x in ['./', '../']: +X pass +X elif x not in a_list: +X b_only.append(x, b_only_action) +X # +X return data +X +X# Re-read the directory. +X# Attempt to find the selected item back. +X +Xdef update(w): +X setbusy(w) +X icol, irow = w.selection +X if 0 <= icol < len(w.data) and 2 <= irow < len(w.data[icol]): +X selname = w.data[icol][irow][0] +X else: +X selname = '' +X statcache.forget_dir(w.a) +X statcache.forget_dir(w.b) +X tablewin.select(w, (-1, -1)) +X tablewin.update(w, diffdata(w.a, w.b, w.flags)) +X if selname: +X for icol in range(len(w.data)): +X for irow in range(2, len(w.data[icol])): +X if w.data[icol][irow][0] = selname: +X tablewin.select(w, (icol, irow)) +X break +X +X# Action functions for table items in directory diff windows +X +Xdef header_action(w, string, (icol, irow), (pos, clicks, button, mask)): +X tablewin.select(w, (-1, -1)) +X +Xdef a_only_action(w, string, (icol, irow), (pos, clicks, button, mask)): +X tablewin.select(w, (icol, irow)) +X if clicks = 2: +X w2 = anyopen(path.cat(w.a, string)) +X if w2: +X w2.parent = w +X +Xdef b_only_action(w, string, (icol, irow), (pos, clicks, button, mask)): +X tablewin.select(w, (icol, irow)) +X if clicks = 2: +X w2 = anyopen(path.cat(w.b, string)) +X if w2: +X w2.parent = w +X +Xdef ab_diff_action(w, string, (icol, irow), (pos, clicks, button, mask)): +X tablewin.select(w, (icol, irow)) +X if clicks = 2: +X w2 = anydiff(path.cat(w.a, string), path.cat(w.b, string), '') +X w2.parent = w +X +Xdef ab_same_action(w, string, sel, detail): +X ax = path.cat(w.a, string) +X if path.isdir(ax): +X ab_diff_action(w, string, sel, detail) +X else: +X a_only_action(w, string, sel, detail) +X +Xdef anyopen(name): # Open any kind of document, ignore errors +X try: +X w = anywin.open(name) +X except (RuntimeError, posix.error): +X stdwin.message('Can\'t open ' + name) +X return 0 +X addstatmenu(w, [name]) +X return w +X +Xdef dircmp(a, b): # Compare whether two directories are the same +X # To make this as fast as possible, it uses the statcache +X print ' dircmp', a, b +X a_list = dircache.listdir(a) +X b_list = dircache.listdir(b) +X for x in a_list: +X if x in skiplist: +X pass +X elif x not in b_list: +X return 0 +X else: +X ax = path.cat(a, x) +X bx = path.cat(b, x) +X if statcache.isdir(ax) and statcache.isdir(bx): +X if not dircmp(ax, bx): return 0 +X else: +X try: +X if not cmpcache.cmp(ax, bx): return 0 +X except posix.error: +X return 0 +X for x in b_list: +X if x in skiplist: +X pass +X elif x not in a_list: +X return 0 +X return 1 +X +X +X# View menu (for dir diff windows only) +X +Xdef addviewmenu(w): +X w.viewmenu = m = w.menucreate('View') +X m.action = [] +X add(m, 'diff -r A B', diffr_ab) +X add(m, 'diff A B', diff_ab) +X add(m, 'diff -b A B', diffb_ab) +X add(m, 'diff -c A B', diffc_ab) +X add(m, 'gdiff A B', gdiff_ab) +X add(m, ('Open A ', 'A'), open_a) +X add(m, ('Open B ', 'B'), open_b) +X add(m, 'Rescan', rescan) +X add(m, 'Rescan -r', rescan_r) +X +X# Action menu (for dir diff windows only) +X +Xdef addactionmenu(w): +X w.actionmenu = m = w.menucreate('Action') +X m.action = [] +X add(m, 'cp A B', cp_ab) +X add(m, 'rm B', rm_b) +X add(m, '', nop) +X add(m, 'cp B A', cp_ba) +X add(m, 'rm A', rm_a) +X +X# Main menu (global): +X +Xdef mainmenu(): +X m = stdwin.menucreate('Wdiff') +X m.action = [] +X add(m, ('Quit wdiff', 'Q'), quit_wdiff) +X add(m, 'Close subwindows', close_subwindows) +X return m +X +Xdef add(m, text, action): +X m.additem(text) +X m.action.append(action) +X +Xdef quit_wdiff(w, m, item): +X if askyesno('Really quit wdiff altogether?', 1): +X sys.exit(0) +X +Xdef close_subwindows(w, m, item): +X while 1: +X for w2 in gwin.windows: +X if w2.parent = w: +X close_subwindows(w2, m, item) +X w2.close(w2) +X break # inner loop, continue outer loop +X else: +X break # outer loop +X +Xdef diffr_ab(w, m, item): +X dodiff(w, '-r') +X +Xdef diff_ab(w, m, item): +X dodiff(w, '') +X +Xdef diffb_ab(w, m, item): +X dodiff(w, '-b') +X +Xdef diffc_ab(w, m, item): +X dodiff(w, '-c') +X +Xdef gdiff_ab(w, m, item): # Call SGI's gdiff utility +X x = getselection(w) +X if x: +X a, b = path.cat(w.a, x), path.cat(w.b, x) +X if path.isdir(a) or path.isdir(b): +X stdwin.fleep() # This is for files only +X else: +X diffcmd = 'gdiff' +X diffcmd = diffcmd + mkarg(a) + mkarg(b) + ' &' +X print diffcmd +X sts = posix.system(diffcmd) +X if sts: print 'Exit status', sts +X +Xdef dodiff(w, flags): +X x = getselection(w) +X if x: +X w2 = anydiff(path.cat(w.a, x), path.cat(w.b, x), flags) +X w2.parent = w +X +Xdef open_a(w, m, item): +X x = getselection(w) +X if x: +X w2 = anyopen(path.cat(w.a, x)) +X if w2: +X w2.parent = w +X +Xdef open_b(w, m, item): +X x = getselection(w) +X if x: +X w2 = anyopen(path.cat(w.b, x)) +X if w2: +X w2.parent = w +X +Xdef rescan(w, m, item): +X w.flags = '' +X update(w) +X +Xdef rescan_r(w, m, item): +X w.flags = '-r' +X update(w) +X +Xdef rm_a(w, m, item): +X x = getselection(w) +X if x: +X if x[-1:] = '/': x = x[:-1] +X x = path.cat(w.a, x) +X if path.isdir(x): +X if askyesno('Recursively remove A directory ' + x, 1): +X runcmd('rm -rf' + mkarg(x)) +X else: +X runcmd('rm -f' + mkarg(x)) +X update(w) +X +Xdef rm_b(w, m, item): +X x = getselection(w) +X if x: +X if x[-1:] = '/': x = x[:-1] +X x = path.cat(w.b, x) +X if path.isdir(x): +X if askyesno('Recursively remove B directory ' + x, 1): +X runcmd('rm -rf' + mkarg(x)) +X else: +X runcmd('rm -f' + mkarg(x)) +X update(w) +X +Xdef cp_ab(w, m, item): +X x = getselection(w) +X if x: +X if x[-1:] = '/': x = x[:-1] +X ax = path.cat(w.a, x) +X bx = path.cat(w.b, x) +X if path.isdir(ax): +X if path.exists(bx): +X m = 'Can\'t copy directory to existing target' +X stdwin.message(m) +X return +X runcmd('cp -r' + mkarg(ax) + mkarg(w.b)) +X else: +X runcmd('cp' + mkarg(ax) + mk2arg(w.b, x)) +X update(w) +X +Xdef cp_ba(w, m, item): +X x = getselection(w) +X if x: +X if x[-1:] = '/': x = x[:-1] +X ax = path.cat(w.a, x) +X bx = path.cat(w.b, x) +X if path.isdir(bx): +X if path.exists(ax): +X m = 'Can\'t copy directory to existing target' +X stdwin.message(m) +X return +X runcmd('cp -r' + mkarg(bx) + mkarg(w.a)) +X else: +X runcmd('cp' + mk2arg(w.b, x) + mkarg(ax)) +X update(w) +X +Xdef nop(args): +X pass +X +Xdef getselection(w): +X icol, irow = w.selection +X if 0 <= icol < len(w.data): +X if 0 <= irow < len(w.data[icol]): +X return w.data[icol][irow][0] +X stdwin.message('no selection') +X return '' +X +Xdef runcmd(cmd): +X print cmd +X sts, output = commands.getstatusoutput(cmd) +X if sts or output: +X if not output: +X output = 'Exit status ' + `sts` +X stdwin.message(output) +X +X +X# Status menu (for all kinds of windows) +X +Xdef addstatmenu(w, files): +X w.statmenu = m = w.menucreate('Stat') +X m.files = files +X m.action = [] +X for file in files: +X m.additem(commands.getstatus(file)) +X m.action.append(stataction) +X +Xdef stataction(w, m, item): # Menu item action for stat menu +X file = m.files[item] +X try: +X m.setitem(item, commands.getstatus(file)) +X except posix.error: +X stdwin.message('Can\'t get status for ' + file) +X +X +X# Compute a suitable window title from two paths +X +Xdef mktitle(a, b): +X if a = b: return a +X i = 1 +X while a[-i:] = b[-i:]: i = i+1 +X i = i-1 +X if not i: +X return a + ' ' + b +X else: +X return '{' + a[:-i] + ',' + b[:-i] + '}' + a[-i:] +X +X +X# Ask a confirmation question +X +Xdef askyesno(prompt, default): +X try: +X return stdwin.askync(prompt, default) +X except KeyboardInterrupt: +X return 0 +X +X +X# Display a message "busy" in a window, and mark it for updating +X +Xdef setbusy(w): +X left, top = w.getorigin() +X width, height = w.getwinsize() +X right, bottom = left + width, top + height +X d = w.begindrawing() +X d.erase((0, 0), (10000, 10000)) +X text = 'Busy...' +X textwidth = d.textwidth(text) +X textheight = d.lineheight() +X h, v = left + (width-textwidth)/2, top + (height-textheight)/2 +X d.text((h, v), text) +X del d +X w.change((0, 0), (10000, 10000)) +X +X +X# Main function +X +Xdef main(): +X print 'wdiff: warning: this version does NOT yet make backups' +X argv = sys.argv +X flags = '' +X if len(argv) >= 2 and argv[1][:1] = '-': +X flags = argv[1] +X del argv[1] +X m = mainmenu() # Create menu earlier than windows +X if len(argv) = 2: # 1 argument +X w = anyopen(argv[1]) +X if not w: return +X elif len(argv) = 3: # 2 arguments +X w = anydiff(argv[1], argv[2], flags) +X w.parent = () +X else: +X sys.stdout = sys.stderr +X print 'usage:', argv[0], '[diff-flags] dir-1 [dir-2]' +X sys.exit(2) +X del w # It's preserved in gwin.windows +X while 1: +X try: +X gwin.mainloop() +X break +X except KeyboardInterrupt: +X pass # Just continue... +X +X# Start the main function (this is a script) +Xmain() +EOF +chmod +x 'demo/stdwin/wdiff.py' +fi +if test -s 'lib/Tcl.py' +then echo '*** I will not over-write existing file lib/Tcl.py' +else +echo 'x - lib/Tcl.py' +sed 's/^X//' > 'lib/Tcl.py' << 'EOF' +X# An emulator for John Ousterhout's 'Tcl' language in Python (wow!). +X# Currently only the most basic commands are implemented. +X# +X# Design choices: +X# +X# - Names used for functions are not exactly those used by C Tcl. +X# In Python, names without 'Tcl_' prefix are acceptable because +X# names are less global than in C (and often they are prefixed +X# with a module name anyway). Parameter conventions also differ. +X# +X# - The Tcl Interpreter type is implemented using a Python class. +X# Almost all functions with an Interpreter as first parameter are +X# methods of this class. +X# Applications can create derived classes to add additional commands +X# or to override specific internal functions. +X# +X# - Tcl errors are mapped to Python exceptions. +X# (I bet Ousterhout would have done the same in a language with +X# a proper exception mechanism). +X# +X# - Tcl expressions are evaluated by Python's built-in function eval(). +X# This makes Python Tcl scripts incompatible with C Tcl scripts, +X# but is the only sensible solution for a quick-and-dirty version. +X# It also makes an escape to Python possible. +X# +X# - The Backslash function interprets \<newline>, since it +X# can return a string instead of a character. +X +X +Xfrom TclUtil import * +X +X +X# Exceptions used to signify 'break' and 'continue' +X +XTclBreak = 'TclBreak' +XTclContinue = 'TclContinue' +XTclReturn = 'TclReturn' +X +X +Xclass CmdBuf(): +X # +X def Create(buffer): +X buffer.string = '' +X return buffer +X # +X def Assemble(buffer, str): +X buffer.string = buffer.string + str +X if buffer.string[-1:] = '\n': +X i, end = 0, len(buffer.string) +X try: +X while i < end: +X list, i = FindNextCommand( \ +X buffer.string, i, end, 0) +X except TclMatchingError: +X return '' +X except TclSyntaxError: +X pass # Let Eval() return the error +X ret = buffer.string +X buffer.string = '' +X return ret +X else: +X return '' +X +X +Xclass _Frame(): +X def Create(frame): +X frame.locals = {} +X return frame +X +Xclass _Proc(): +X # +X def Create(proc, (interp, args, body)): +X proc.interp = interp +X proc.args = SplitList(args) # Do this once here +X proc.body = body +X return proc +X # +X def Call(proc, argv): +X if len(argv) <> len(proc.args)+1: +X raise TclRuntimeError, \ +X 'wrong # args to proc "' + \ +X argv[0] + '"' +X # XXX No defaults or variable length 'args' yet +X frame = _Frame().Create() +X for i in range(len(proc.args)): +X frame.locals[proc.args[i]] = argv[i+1] +X proc.interp.stack.append(frame) +X try: +X value = proc.interp.Eval(proc.body) +X except TclReturn, value: +X pass +X del proc.interp.stack[-1:] +X return value +X +X +Ximport regexp +X_expand_prog = regexp.compile('([^[$\\]+|\n)*') +Xdel regexp +X +Xclass Interpreter(): +X # +X def Create(interp): +X interp.globals = {} +X interp.commands = {} +X interp.stack = [] +X interp.commands['break'] = interp.BreakCmd +X interp.commands['concat'] = interp.ConcatCmd +X interp.commands['continue'] = interp.ContinueCmd +X interp.commands['echo'] = interp.EchoCmd +X interp.commands['eval'] = interp.EvalCmd +X interp.commands['expr'] = interp.ExprCmd +X interp.commands['for'] = interp.ForCmd +X interp.commands['glob'] = interp.GlobCmd +X interp.commands['global'] = interp.GlobalCmd +X interp.commands['if'] = interp.IfCmd +X interp.commands['index'] = interp.IndexCmd +X interp.commands['list'] = interp.ListCmd +X interp.commands['proc'] = interp.ProcCmd +X interp.commands['rename'] = interp.RenameCmd +X interp.commands['return'] = interp.ReturnCmd +X interp.commands['set'] = interp.SetCmd +X return interp +X # +X def Delete(interp): +X # +X # Only break circular references here; +X # most things will be garbage-collected. +X # +X for name in interp.commands.keys(): +X del interp.commands[name] +X # +X def CreateCommand(interp, (name, proc)): +X interp.commands[name] = proc +X # +X def DeleteCommand(interp, (name)): +X del interp.commands[name] +X # +X # Local variables are maintained on the stack. +X # A local variable with value "None" is a dummy +X # meaning that the corresponding global variable +X # should be used. +X # +X def GetVar(interp, varName): +X dict = interp.globals +X if interp.stack: +X d = interp.stack[-1:][0].locals +X if d.has_key(varName) and d[varName] = None: +X pass +X else: +X dict = d +X if not dict.has_key(varName): +X raise TclRuntimeError, \ +X 'Variable "' + varName + '" not found' +X return dict[varName] +X # +X def SetVar(interp, (varName, newValue)): +X dict = interp.globals +X if interp.stack: +X d = interp.stack[-1:][0].locals +X if d.has_key(varName) and d[varName] = None: +X pass +X else: +X dict = d +X dict[varName] = newValue +X # +X def Expand(interp, (str, i, end)): +X if end <= i: return '' +X if str[i] = '{' and str[end-1] = '}': +X return str[i+1:end-1] +X if str[i] = '"' and str[end-1] = '"': +X i, end = i+1, end-1 +X result = '' +X while i < end: +X c = str[i] +X if c = '\\': +X x, i = Backslash(str, i, end) +X result = result + x +X elif c = '[': +X j = BalanceBrackets(str, i, end) +X x = interp.EvalBasic(str, i+1, j-1, 1) +X result = result + x +X i = j +X elif c = '$': +X i = i+1 +X j = FindVarName(str, i, end) +X name = str[i:j] +X i = j +X if not name: +X result = result + '$' +X else: +X if name[:1] = '{' and name[-1:] = '}': +X name = name[1:-1] +X result = result + interp.GetVar(name) +X else: +X j = _expand_prog.exec(str, i) +X j = min(j, end) +X result = result + str[i:j] +X i = j +X return result +X # +X def EvalBasic(interp, (str, i, end, bracketed)): +X result = '' +X while i < end: +X indexargv, i = FindNextCommand( \ +X str, i, end, bracketed) +X if indexargv: +X argv = [] +X for x, y in indexargv: +X arg = interp.Expand(str, x, y) +X argv.append(arg) +X name = argv[0] +X if not interp.commands.has_key(name): +X raise TclRuntimeError, \ +X 'Command "' + name + \ +X '" not found' +X result = interp.commands[name](argv) +X return result +X # +X def Eval(interp, str): +X return interp.EvalBasic(str, 0, len(str), 0) +X # +X def ExprBasic(interp, (str, begin, end)): +X expr = interp.Expand(str, begin, end) +X i = SkipSpaces(expr, 0, len(expr)) +X expr = expr[i:] +X try: +X return eval(expr, {}) +X except (NameError, TypeError, RuntimeError, EOFError), msg: +X import sys +X raise TclRuntimeError, sys.exc_type + ': ' + msg +X # +X def Expr(interp, str): +X return interp.ExprBasic(str, 0, len(str)) +X # +X # The rest are command implementations +X # +X def BreakCmd(interp, argv): +X if len(argv) <> 1: +X raise TclRuntimeError, 'usage: break' +X raise TclBreak +X # +X def ConcatCmd(interp, argv): +X if len(argv) < 2: +X raise TclRuntimeError, 'usage: concat arg ...' +X return Concat(argv[1:]) +X # +X def ContinueCmd(interp, argv): +X if len(argv) <> 1: +X raise TclRuntimeError, 'usage: continue' +X raise TclContinue +X # +X def EchoCmd(interp, argv): +X for arg in argv[1:]: print arg, +X print +X return '' +X # +X def EvalCmd(interp, argv): +X if len(argv) < 2: +X raise TclRuntimeError, 'usage: eval arg [arg ...]' +X str = Concat(argv[1:]) +X return interp.Eval(str) +X # +X def ExprCmd(interp, argv): +X if len(argv) <> 2: +X raise TclRuntimeError, 'usage: expr expression' +X expr = argv[1] +X result = interp.Expr(expr) +X if type(result) <> type(''): result = `result` +X return result +X # +X def ForCmd(interp, argv): +X if len(argv) <> 5: +X raise TclRuntimeError, \ +X 'usage: for start test next body' +X x = interp.Eval(argv[1]) +X while interp.Expr(argv[2]): +X try: +X x = interp.Eval(argv[4]) +X except TclBreak: +X break +X except TclContinue: +X pass +X x = interp.Eval(argv[3]) +X return '' +X # +X def GlobCmd(interp, argv): +X import macglob +X if len(argv) < 2: +X raise TclRuntimeError, 'usage: glob pattern ...' +X list = [] +X for pat in argv[1:]: +X list = list + macglob.glob(pat) +X if not list: +X raise TclRuntimeError, 'no match for glob pattern(s)' +X return BuildList(list) +X # +X def GlobalCmd(interp, argv): +X if len(argv) < 2: +X raise TclRuntimeError, 'usage: global varname ...' +X if not interp.stack: +X raise TclRuntimeError, 'global used outside proc' +X dict = interp.stack[-1:][0].locals +X for name in argv[1:]: +X dict[name] = None +X return '' +X # +X def IfCmd(interp, argv): +X argv = argv[:] +X if len(argv) > 2 and argv[2] = 'then': del argv[2] +X if len(argv) > 3 and argv[3] = 'else': del argv[3] +X if not 3 <= len(argv) <= 4: +X raise TclRuntimeError, \ +X 'usage: if test [then] trueBody [else] falseBody' +X if interp.Expr(argv[1]): +X return interp.Eval(argv[2]) +X if len(argv) > 3: +X return interp.Eval(argv[3]) +X return '' +X # +X def IndexCmd(interp, argv): +X if len(argv) <> 3: +X raise TclRuntimeError, 'usage: index value index' +X import string +X try: +X index = string.atoi(argv[2]) +X if index < 0: raise string.atoi_error +X except string.atoi_error: +X raise TclRuntimeError, 'bad index: ' + argv[2] +X list = SplitList(argv[1]) +X if index >= len(list): return '' +X return list[index] +X # +X def ListCmd(interp, argv): +X if len(argv) < 2: +X raise TclRuntimeError, 'usage: list arg ...' +X return BuildList(argv[1:]) +X # +X def ProcCmd(interp, argv): +X if len(argv) <> 4: +X raise TclRuntimeError, 'usage: proc name args body' +X x = _Proc().Create(interp, argv[2], argv[3]) +X interp.CreateCommand(argv[1], x.Call) +X return '' +X # +X def RenameCmd(interp, argv): +X if len(argv) <> 3: +X raise TclRuntimeError, 'usage: rename oldName newName' +X oldName, newName = argv[1], argv[2] +X if not interp.commands.has_key(oldName): +X raise TclRuntimeError, \ +X 'command "' + oldName + '" not found' +X if newName: interp.commands[newName] = interp.commands[oldName] +X del interp.commands[oldName] +X return '' +X # +X def ReturnCmd(interp, argv): +X if not 1 <= len(argv) <= 2: +X raise TclRuntimeError, 'usage: return [arg]' +X if len(argv) = 1: raise TclReturn, '' +X raise TclReturn, argv[1] +X # +X def SetCmd(interp, argv): +X n = len(argv) +X if not 2 <= n <= 3: +X raise TclRuntimeError, 'usage: set varname [newvalue]' +X if n = 2: return interp.GetVar(argv[1]) +X interp.SetVar(argv[1], argv[2]) +X return '' +X +X +X# The rest are just demos: +X +Xdef MainLoop(interp): +X buffer = CmdBuf().Create() +X if not interp.globals.has_key('ps1'): interp.globals['ps1'] = '% ' +X if not interp.globals.has_key('ps2'): interp.globals['ps2'] = '' +X psname = 'ps1' +X while 1: +X try: +X line = raw_input(interp.globals[psname]) +X except (EOFError, KeyboardInterrupt): +X print +X break +X line = buffer.Assemble(line + '\n') +X if not line: +X psname = 'ps2' +X else: +X psname = 'ps1' +X try: +X x = interp.Eval(line) +X if x <> '': print 'Result:', `x` +X except (TclRuntimeError, TclSyntaxError, \ +X TclMatchingError), msg: +X print 'Error:', msg +X except (TclBreak, TclContinue): +X print 'Error: break or continue outside loop' +X except TclReturn, value: +X # Return outside proc returns to main loop +X if value: print value +X +X +Xthe_interpreter = Interpreter().Create() +X +Xdef main(): +X MainLoop(the_interpreter) +X +X +X# XXX To do: +X# for proc: "args" and default arguments +X# More commands: +X# case +X# uplevel +X# info +X# string +X# list operations +X# error, catch +X# print +X# scan, format +X# source +X# history? +X# others? +EOF +fi +if test -s 'src/asa.c' +then echo '*** I will not over-write existing file src/asa.c' +else +echo 'x - src/asa.c' +sed 's/^X//' > 'src/asa.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Asynchronous audio module for Silicon Graphics 4D/20 under IRIX 3.3 +X Copyright 1990 Stichting Mathematisch Centrum, Amsterdam +X Author: Guido van Rossum, <[email protected]> +X Last modified: [email protected], Oct 14, 1990 +X +X Callers should #include "asa.h". +X +X This code is strongly IRIX 3.3 dependent. (Or are sproc() and +X friends standard SYSV now?) +X +X Caution: if you put printf's in the slave for debugging, use "-lmpc" +X to get the semaphore version of stdio! +X +X +X This file contains two library layers and a test program: +X +X +X The lower layer implements a simple asynchronous execution facility, +X built directly on the system calls sproc() and [un]blockproc(). +X +X A slave thread sits in an infinite loop waiting for work assigned to +X it by the master thread. Work is represented by a function pointer +X and an argument of type void*. The function returns a void* pointer +X which is transferred back to the master when it submits the next bit +X of work. Submitting a NULL function pointer can be used by the +X master to wait for completion of the previous work. This lower +X layer could be generally useful, but is currently implemented by +X static functions, for exclusive by the asynchronous audio layer. +X +X +X The higher layer implements an asynchronous interface to the +X /dev/audio device on the Silicon Graphics 4D/20. It defines the +X following functions: +X +X int asa_init() +X Required initialization function. The other functions will call +X abort() when they are called before asa_init(). It creates the +X slave process and returns a file descriptor for the audio +X device which can be used to set the sampling rate and output +X gain, etc. It prints a message to stderr and returns -1 if the +X initialization failed. Calling this function more than onece is +X harmless. +X +X void asa_start_read(char *buf, int len) +X Starts an asynchronous read call on the audio device. This +X waits for completion of the previous request, if any. +X +X void asa_start_write(char *buf, int len) +X Starts an asynchronous write call on the audio device. This +X waits for completion of the previous request, if any. +X +X int asa_poll() +X Polls whether the last asynchronous read or write request is +X finished. Returns -1 if no request was queued, 0 if the request +X is not yet finished, and 1 if it is finished. +X +X int asa_wait() +X Waits for completion if the last asynchronous read or write +X request. It returns the result of the read or write request, +X and sets the error code to the error code set by the request if +X the result is -1. If no request was queued, this also returns +X -1 but leaves the error code unchanged. Note: to get the error +X code, don't inspect the global variable errno but call the +X function oserror(). +X +X int asa_cancel() +X Cancels the last asynchronous read or write request (by sending +X the slave thread a signal for which it has a handler) then +X returns its result and error code as asa_wait(). +X +X void asa_done() +X Kills the slave process and closes the audio device. After +X this, if further use of the module is required, asa_init() +X should be called again. Calling this function when asa_init() +X has not been called is harmless. +X +X +X Finally, this file contains a simple test program that is compiled if +X MAIN is defined (e.g., compile with cc -DMAIN). It makes a recording +X and plays it back. The user must indicate begin and end of recording +X and play-back by pressing the Return key. +X*/ +X +X +X#include <stdio.h> +X#include <stdlib.h> +X#include <signal.h> +X#include <sys/types.h> +X#include <sys/prctl.h> +X +X#include "asa.h" +X +X +X/* Asynchronous execution facility (lower layer) */ +X +X +X/* Signal used to cancel requests in progress */ +X#define MYSIG SIGUSR1 +X +X/* Respective process IDs */ +Xstatic pid_t master_pid = -1; +Xstatic pid_t slave_pid = -1; +X +X/* Work and result "queue" (1 element) */ +Xstatic void * (*work_func)(); +Xstatic void *work_arg; +Xstatic void *work_result; +X +X/* Signal handler for MYSIG -- interrupts read or write system call */ +X +X/*ARGSUSED*/ +Xstatic void +Xhandler(sig) +X int sig; +X{ +X /* Reinstate the handler (non-BSD signal semantics) */ +X signal(sig, handler); +X} +X +X/* Subroutine to fiddle signals */ +X +Xstatic void +Xdosig(sig) +X int sig; +X{ +X if (signal(sig, SIG_IGN) != SIG_IGN) +X signal(sig, SIG_DFL); +X} +X +X/* Slave control flow */ +X +X/*ARGSUSED*/ +Xstatic void +Xslave(arg) +X void *arg; +X{ +X void * (*func)(); +X void *arg; +X void *result; +X +X /* Reset signal handlers that interactive programs often catch. +X The assumption is that if the master has a handler for these +X signals, it will be a cleanup function. The slave must die +X from these. */ +X dosig(SIGHUP); +X dosig(SIGQUIT); +X dosig(SIGTERM); +X dosig(SIGPIPE); +X +X /* Ignore SIGINT if caught or ignored */ +X if (signal(SIGINT, SIG_IGN) == SIG_DFL) +X signal(SIGINT, SIG_DFL); +X +X /* Let the handler install itself */ +X handler(MYSIG); +X +X /* Set slave_pid. This is also done in the master thread, but +X there is a race condition whereby the slave begins execution +X before the master has assigned the result of sproc() to +X slave_pid. So we set it here as well -- since this sets the +X same value it should be OK. */ +X slave_pid = getpid(); +X +X /* Set the dummy result returned by the first rendezvous */ +X result = NULL; +X +X /* Loop forever, waiting for and executing work */ +X for (;;) { +X /* First rendezvous: store previous result */ +X if (blockproc(slave_pid) < 0) +X perror("slave: [result] blockproc(slave_pid)"); +X work_result = result; +X if (unblockproc(master_pid) < 0) +X perror("slave: [result] unblockproc(master_pid)"); +X +X /* Second rendezvous: fetch work */ +X if (blockproc(slave_pid) < 0) +X perror("slave: [func,arg] blockproc(slave_pid)"); +X func = work_func; +X arg = work_arg; +X if (unblockproc(master_pid) < 0) +X perror("slave: [func,arg] unblockproc(master_pid)"); +X +X /* Execute work, computing new result */ +X if (func == NULL) { +X result = arg; +X } +X else { +X result = (*func)(arg); +X } +X } +X} +X +Xstatic int +Xslave_init() +X{ +X if (slave_pid > 0) +X return slave_pid; +X master_pid = getpid(); +X +X /* Reset the queue, in case this is a re-init after asa_done() */ +X work_result = NULL; +X work_func = NULL; +X work_arg = NULL; +X +X /* Create the slave process, sharing all segments and properties */ +X slave_pid = sproc(slave, PR_SALL, (char *)NULL); +X if (slave_pid < 0) +X perror("slave_init: sproc(slave, PR_SALL, NULL)"); +X +X /* Set up initial conditions---tricky! +X Both the master and the slave start with one credit, since +X both the result slot and the work/func slots are initially +X free. +X Note that we use setblockproccnt() for the master so a +X possible indeterminate semaphore value caused by a previous +X asa_done() at an unfortunate moment doesn't harm us. +X */ +X setblockproccnt(master_pid, 1); +X unblockproc(slave_pid); +X +X return slave_pid; +X} +X +Xstatic void +Xslave_done() +X{ +X if (slave_pid > 0) { +X if (kill(slave_pid, SIGKILL) < 0) +X perror("slave_done: kill(slave_pid, SIGKILL)"); +X } +X slave_pid = -1; +X} +X +X/* Queue new work and return result of previous work */ +X +Xstatic void * +Xrendezvous(func, arg) +X void * (*func)(); +X void *arg; +X{ +X void *result; +X +X if (slave_pid <= 0) +X abort(); /* Illegal call: not initialized properly */ +X +X /* First rendezvous: store new work */ +X if (blockproc(master_pid) < 0) +X perror("rendezvous: [func,arg] blockproc(master_pid)"); +X work_func = func; +X work_arg = arg; +X if (unblockproc(slave_pid) < 0) +X perror("rendezvous: [func,arg] unblockproc(slave_pid)"); +X +X /* Second rendezvous: fetch previous result */ +X if (blockproc(master_pid) < 0) +X perror("rendezvous: [result] blockproc(master_pid)"); +X result = work_result; +X if (unblockproc(slave_pid) < 0) +X perror("rendezvous: [result] unblockproc(slave_pid)"); +X +X return result; +X} +X +X +X/* Asynchronous audio interface (higher layer) */ +X +X +Xint audio_fd = -1; /* File descriptor -- not initialized yet */ +X +Xstatic struct queue { +X int func; /* 0 = read, 1 = write */ +X char *buf; +X int len; +X int result; +X int error; +X} queue[2]; +X +Xstatic int qindex = 0; +X +Xint +Xasa_init() +X{ +X int fd; +X char *p; +X +X if (audio_fd >= 0) +X return audio_fd; +X fd = open("/dev/audio", 2); +X if (fd < 0) { +X perror("asa_init: Can't open /dev/audio"); +X return -1; +X } +X if (slave_init() < 0) { +X perror("asa_init: Can't create slave process"); +X close(fd); +X return -1; +X } +X audio_fd = fd; +X return fd; +X} +X +Xvoid +Xasa_done() +X{ +X slave_done(); +X if (audio_fd >= 0) { +X if (close(audio_fd) < 0) +X perror("asa_done: close(audio_fd)"); +X } +X audio_fd = -1; +X} +X +Xstatic void * +Xrunjob(arg) +X void *arg; +X{ +X extern int errno; +X struct queue *q = (struct queue *)arg; +X char *buf = q->buf; +X int len = q->len; +X int n = 0; +X +X if (q->func == 0) +X n = read(audio_fd, buf, len); +X else +X n = write(audio_fd, buf, len); +X if (q->func == 0 && n >= 0) { +X while (--len >= n && buf[len] == '\0') +X ; +X n = len+1; +X } +X q->result = n; +X q->error = oserror(); +X return arg; +X} +X +Xstatic void +Xstartjob(func, buf, len) +X int func; +X char *buf; +X int len; +X{ +X struct queue *q; +X +X q = &queue[qindex]; +X qindex = (qindex+1) & 1; +X q->func = func; +X q->buf = buf; +X q->len = len; +X (void) rendezvous(runjob, (void *)q); +X} +X +Xvoid +Xasa_start_read(buf, len) +X char *buf; +X int len; +X{ +X memset(buf, '\0', len); +X startjob(0, buf, len); +X} +X +Xvoid +Xasa_start_write(buf, len) +X char *buf; +X int len; +X{ +X startjob(1, buf, len); +X} +X +Xint +Xasa_wait() +X{ +X struct queue *q; +X +X q = (struct queue *) rendezvous((void*(*)())NULL, (void *)NULL); +X if (q == NULL) { +X setoserror(0); +X return -1; /* No work was queued */ +X } +X setoserror(q->error); +X return q->result; +X} +X +Xint +Xasa_poll() +X{ +X int err; +X +X err = prctl(PR_ISBLOCKED, slave_pid); +X if (err < 0) { +X perror("prctl(PR_ISBLOCKED, slave_pid)"); +X return -1; +X } +X else if (err == 0) +X return 0; +X else if (work_result == NULL) { +X setoserror(0); +X return -1; +X } +X else +X return 1; +X} +X +Xint +Xasa_cancel() +X{ +X int result; +X +X kill(slave_pid, MYSIG); +X result = asa_wait(); +X return result; +X} +X +X +X#ifdef MAIN +X +X/* Test program */ +X +X#include <sys/audio.h> +X +Xmain() +X{ +X static char buf[10*16*1024]; /* 10 seconds of sound at 16K/sec */ +X int n; +X int afd; +X +X if ((afd = asa_init()) < 0) +X exit(1); +X ioctl(afd, AUDIOCSETRATE, 3); +X ioctl(afd, AUDIOCSETOUTGAIN, 0); +X printf("Poll returns %d\n", asa_poll()); +X go("Hit enter to start recording:\n"); +X asa_start_read(buf, sizeof buf); +X go("Hit enter to stop recording:\n"); +X /*printf("Poll returns %d\n", asa_poll());*/ +X n = asa_cancel(); +X if (n < 0) +X perror("Read failed"); +X else { +X printf("Got %d bytes\n", n); +X printf("Poll returns %d\n", asa_poll()); +X go("Hit enter to start playing:\n"); +X ioctl(afd, AUDIOCSETOUTGAIN, 50); +X asa_start_write(buf, n); +X go("Hit enter to stop playing:\n"); +X printf("Poll returns %d\n", asa_poll()); +X n = asa_cancel(); +X if (n < 0) +X perror("Write failed"); +X else +X printf("Stopped at %d bytes\n", n); +X } +X ioctl(afd, AUDIOCSETOUTGAIN, 0); +X asa_done(); +X exit(n < 0 ? 1 : 0); +X} +X +Xgo(str) +X char *str; +X{ +X char line[100]; +X +X sleep(1); +X fputs(str, stdout); +X fflush(stdout); +X fgets(line, sizeof line, stdin); +X} +X +X#endif /* MAIN */ +EOF +fi +if test -s 'src/bltinmodule.c' +then echo '*** I will not over-write existing file src/bltinmodule.c' +else +echo 'x - src/bltinmodule.c' +sed 's/^X//' > 'src/bltinmodule.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Built-in functions */ +X +X#include "allobjects.h" +X +X#include "node.h" +X#include "graminit.h" +X#include "errcode.h" +X#include "sysmodule.h" +X#include "bltinmodule.h" +X#include "import.h" +X#include "pythonrun.h" +X#include "compile.h" /* For ceval.h */ +X#include "ceval.h" +X#include "modsupport.h" +X +Xstatic object * +Xbuiltin_abs(self, v) +X object *self; +X object *v; +X{ +X /* XXX This should be a method in the as_number struct in the type */ +X if (v == NULL) { +X /* */ +X } +X else if (is_intobject(v)) { +X long x = getintvalue(v); +X if (x < 0) +X x = -x; +X return newintobject(x); +X } +X else if (is_floatobject(v)) { +X double x = getfloatvalue(v); +X if (x < 0) +X x = -x; +X return newfloatobject(x); +X } +X err_setstr(TypeError, "abs() argument must be float or int"); +X return NULL; +X} +X +Xstatic object * +Xbuiltin_chr(self, v) +X object *self; +X object *v; +X{ +X long x; +X char s[1]; +X if (v == NULL || !is_intobject(v)) { +X err_setstr(TypeError, "chr() must have int argument"); +X return NULL; +X } +X x = getintvalue(v); +X if (x < 0 || x >= 256) { +X err_setstr(RuntimeError, "chr() arg not in range(256)"); +X return NULL; +X } +X s[0] = x; +X return newsizedstringobject(s, 1); +X} +X +Xstatic object * +Xbuiltin_dir(self, v) +X object *self; +X object *v; +X{ +X object *d; +X if (v == NULL) { +X d = getlocals(); +X } +X else { +X if (!is_moduleobject(v)) { +X err_setstr(TypeError, +X "dir() argument, must be module or absent"); +X return NULL; +X } +X d = getmoduledict(v); +X } +X v = getdictkeys(d); +X if (sortlist(v) != 0) { +X DECREF(v); +X v = NULL; +X } +X return v; +X} +X +Xstatic object * +Xbuiltin_divmod(self, v) +X object *self; +X object *v; +X{ +X object *x, *y; +X long xi, yi, xdivy, xmody; +X if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { +X err_setstr(TypeError, "divmod() requires 2 int arguments"); +X return NULL; +X } +X x = gettupleitem(v, 0); +X y = gettupleitem(v, 1); +X if (!is_intobject(x) || !is_intobject(y)) { +X err_setstr(TypeError, "divmod() requires 2 int arguments"); +X return NULL; +X } +X xi = getintvalue(x); +X yi = getintvalue(y); +X if (yi == 0) { +X err_setstr(TypeError, "divmod() division by zero"); +X return NULL; +X } +X if (yi < 0) { +X xdivy = -xi / -yi; +X } +X else { +X xdivy = xi / yi; +X } +X xmody = xi - xdivy*yi; +X if (xmody < 0 && yi > 0 || xmody > 0 && yi < 0) { +X xmody += yi; +X xdivy -= 1; +X } +X v = newtupleobject(2); +X x = newintobject(xdivy); +X y = newintobject(xmody); +X if (v == NULL || x == NULL || y == NULL || +X settupleitem(v, 0, x) != 0 || +X settupleitem(v, 1, y) != 0) { +X XDECREF(v); +X XDECREF(x); +X XDECREF(y); +X return NULL; +X } +X return v; +X} +X +Xstatic object * +Xexec_eval(v, start) +X object *v; +X int start; +X{ +X object *str = NULL, *globals = NULL, *locals = NULL; +X int n; +X if (v != NULL) { +X if (is_stringobject(v)) +X str = v; +X else if (is_tupleobject(v) && +X ((n = gettuplesize(v)) == 2 || n == 3)) { +X str = gettupleitem(v, 0); +X globals = gettupleitem(v, 1); +X if (n == 3) +X locals = gettupleitem(v, 2); +X } +X } +X if (str == NULL || !is_stringobject(str) || +X globals != NULL && !is_dictobject(globals) || +X locals != NULL && !is_dictobject(locals)) { +X err_setstr(TypeError, +X "exec/eval arguments must be string[,dict[,dict]]"); +X return NULL; +X } +X return run_string(getstringvalue(str), start, globals, locals); +X} +X +Xstatic object * +Xbuiltin_eval(self, v) +X object *self; +X object *v; +X{ +X return exec_eval(v, eval_input); +X} +X +Xstatic object * +Xbuiltin_exec(self, v) +X object *self; +X object *v; +X{ +X return exec_eval(v, file_input); +X} +X +Xstatic object * +Xbuiltin_float(self, v) +X object *self; +X object *v; +X{ +X if (v == NULL) { +X /* */ +X } +X else if (is_floatobject(v)) { +X INCREF(v); +X return v; +X } +X else if (is_intobject(v)) { +X long x = getintvalue(v); +X return newfloatobject((double)x); +X } +X err_setstr(TypeError, "float() argument must be float or int"); +X return NULL; +X} +X +Xstatic object * +Xbuiltin_input(self, v) +X object *self; +X object *v; +X{ +X FILE *in = sysgetfile("stdin", stdin); +X FILE *out = sysgetfile("stdout", stdout); +X node *n; +X int err; +X object *m, *d; +X flushline(); +X if (v != NULL) +X printobject(v, out, PRINT_RAW); +X m = add_module("__main__"); +X d = getmoduledict(m); +X return run_file(in, "<stdin>", expr_input, d, d); +X} +X +Xstatic object * +Xbuiltin_int(self, v) +X object *self; +X object *v; +X{ +X if (v == NULL) { +X /* */ +X } +X else if (is_intobject(v)) { +X INCREF(v); +X return v; +X } +X else if (is_floatobject(v)) { +X double x = getfloatvalue(v); +X return newintobject((long)x); +X } +X err_setstr(TypeError, "int() argument must be float or int"); +X return NULL; +X} +X +Xstatic object * +Xbuiltin_len(self, v) +X object *self; +X object *v; +X{ +X long len; +X typeobject *tp; +X if (v == NULL) { +X err_setstr(TypeError, "len() without argument"); +X return NULL; +X } +X tp = v->ob_type; +X if (tp->tp_as_sequence != NULL) { +X len = (*tp->tp_as_sequence->sq_length)(v); +X } +X else if (tp->tp_as_mapping != NULL) { +X len = (*tp->tp_as_mapping->mp_length)(v); +X } +X else { +X err_setstr(TypeError, "len() of unsized object"); +X return NULL; +X } +X return newintobject(len); +X} +X +Xstatic object * +Xmin_max(v, sign) +X object *v; +X int sign; +X{ +X int i, n, cmp; +X object *w, *x; +X sequence_methods *sq; +X if (v == NULL) { +X err_setstr(TypeError, "min() or max() without argument"); +X return NULL; +X } +X sq = v->ob_type->tp_as_sequence; +X if (sq == NULL) { +X err_setstr(TypeError, "min() or max() of non-sequence"); +X return NULL; +X } +X n = (*sq->sq_length)(v); +X if (n == 0) { +X err_setstr(RuntimeError, "min() or max() of empty sequence"); +X return NULL; +X } +X w = (*sq->sq_item)(v, 0); /* Implies INCREF */ +X for (i = 1; i < n; i++) { +X x = (*sq->sq_item)(v, i); /* Implies INCREF */ +X cmp = cmpobject(x, w); +X if (cmp * sign > 0) { +X DECREF(w); +X w = x; +X } +X else +X DECREF(x); +X } +X return w; +X} +X +Xstatic object * +Xbuiltin_min(self, v) +X object *self; +X object *v; +X{ +X return min_max(v, -1); +X} +X +Xstatic object * +Xbuiltin_max(self, v) +X object *self; +X object *v; +X{ +X return min_max(v, 1); +X} +X +Xstatic object * +Xbuiltin_open(self, v) +X object *self; +X object *v; +X{ +X object *name, *mode; +X if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2 || +X !is_stringobject(name = gettupleitem(v, 0)) || +X !is_stringobject(mode = gettupleitem(v, 1))) { +X err_setstr(TypeError, "open() requires 2 string arguments"); +X return NULL; +X } +X v = newfileobject(getstringvalue(name), getstringvalue(mode)); +X return v; +X} +X +Xstatic object * +Xbuiltin_ord(self, v) +X object *self; +X object *v; +X{ +X if (v == NULL || !is_stringobject(v)) { +X err_setstr(TypeError, "ord() must have string argument"); +X return NULL; +X } +X if (getstringsize(v) != 1) { +X err_setstr(RuntimeError, "ord() arg must have length 1"); +X return NULL; +X } +X return newintobject((long)(getstringvalue(v)[0] & 0xff)); +X} +X +Xstatic object * +Xbuiltin_range(self, v) +X object *self; +X object *v; +X{ +X static char *errmsg = "range() requires 1-3 int arguments"; +X int i, n; +X long ilow, ihigh, istep; +X if (v != NULL && is_intobject(v)) { +X ilow = 0; ihigh = getintvalue(v); istep = 1; +X } +X else if (v == NULL || !is_tupleobject(v)) { +X err_setstr(TypeError, errmsg); +X return NULL; +X } +X else { +X n = gettuplesize(v); +X if (n < 1 || n > 3) { +X err_setstr(TypeError, errmsg); +X return NULL; +X } +X for (i = 0; i < n; i++) { +X if (!is_intobject(gettupleitem(v, i))) { +X err_setstr(TypeError, errmsg); +X return NULL; +X } +X } +X if (n == 3) { +X istep = getintvalue(gettupleitem(v, 2)); +X --n; +X } +X else +X istep = 1; +X ihigh = getintvalue(gettupleitem(v, --n)); +X if (n > 0) +X ilow = getintvalue(gettupleitem(v, 0)); +X else +X ilow = 0; +X } +X if (istep == 0) { +X err_setstr(RuntimeError, "zero step for range()"); +X return NULL; +X } +X /* XXX ought to check overflow of subtraction */ +X if (istep > 0) +X n = (ihigh - ilow + istep - 1) / istep; +X else +X n = (ihigh - ilow + istep + 1) / istep; +X if (n < 0) +X n = 0; +X v = newlistobject(n); +X if (v == NULL) +X return NULL; +X for (i = 0; i < n; i++) { +X object *w = newintobject(ilow); +X if (w == NULL) { +X DECREF(v); +X return NULL; +X } +X setlistitem(v, i, w); +X ilow += istep; +X } +X return v; +X} +X +Xstatic object * +Xbuiltin_raw_input(self, v) +X object *self; +X object *v; +X{ +X FILE *in = sysgetfile("stdin", stdin); +X FILE *out = sysgetfile("stdout", stdout); +X char *p; +X int err; +X int n = 1000; +X flushline(); +X if (v != NULL) +X printobject(v, out, PRINT_RAW); +X v = newsizedstringobject((char *)NULL, n); +X if (v != NULL) { +X if ((err = fgets_intr(getstringvalue(v), n+1, in)) != E_OK) { +X err_input(err); +X DECREF(v); +X return NULL; +X } +X else { +X n = strlen(getstringvalue(v)); +X if (n > 0 && getstringvalue(v)[n-1] == '\n') +X n--; +X resizestring(&v, n); +X } +X } +X return v; +X} +X +Xstatic object * +Xbuiltin_reload(self, v) +X object *self; +X object *v; +X{ +X return reload_module(v); +X} +X +Xstatic object * +Xbuiltin_type(self, v) +X object *self; +X object *v; +X{ +X if (v == NULL) { +X err_setstr(TypeError, "type() requres an argument"); +X return NULL; +X } +X v = (object *)v->ob_type; +X INCREF(v); +X return v; +X} +X +Xstatic struct methodlist builtin_methods[] = { +X {"abs", builtin_abs}, +X {"chr", builtin_chr}, +X {"dir", builtin_dir}, +X {"divmod", builtin_divmod}, +X {"eval", builtin_eval}, +X {"exec", builtin_exec}, +X {"float", builtin_float}, +X {"input", builtin_input}, +X {"int", builtin_int}, +X {"len", builtin_len}, +X {"max", builtin_max}, +X {"min", builtin_min}, +X {"open", builtin_open}, /* XXX move to OS module */ +X {"ord", builtin_ord}, +X {"range", builtin_range}, +X {"raw_input", builtin_raw_input}, +X {"reload", builtin_reload}, +X {"type", builtin_type}, +X {NULL, NULL}, +X}; +X +Xstatic object *builtin_dict; +X +Xobject * +Xgetbuiltin(name) +X char *name; +X{ +X return dictlookup(builtin_dict, name); +X} +X +X/* Predefined exceptions */ +X +Xobject *RuntimeError; +Xobject *EOFError; +Xobject *TypeError; +Xobject *MemoryError; +Xobject *NameError; +Xobject *SystemError; +Xobject *KeyboardInterrupt; +X +Xstatic object * +Xnewstdexception(name, message) +X char *name, *message; +X{ +X object *v = newstringobject(message); +X if (v == NULL || dictinsert(builtin_dict, name, v) != 0) +X fatal("no mem for new standard exception"); +X return v; +X} +X +Xstatic void +Xiniterrors() +X{ +X RuntimeError = newstdexception("RuntimeError", "run-time error"); +X EOFError = newstdexception("EOFError", "end-of-file read"); +X TypeError = newstdexception("TypeError", "type error"); +X MemoryError = newstdexception("MemoryError", "out of memory"); +X NameError = newstdexception("NameError", "undefined name"); +X SystemError = newstdexception("SystemError", "system error"); +X KeyboardInterrupt = +X newstdexception("KeyboardInterrupt", "keyboard interrupt"); +X} +X +Xvoid +Xinitbuiltin() +X{ +X object *m; +X m = initmodule("builtin", builtin_methods); +X builtin_dict = getmoduledict(m); +X INCREF(builtin_dict); +X initerrors(); +X (void) dictinsert(builtin_dict, "None", None); +X} +EOF +fi +if test -s 'src/cgen' +then echo '*** I will not over-write existing file src/cgen' +else +echo 'x - src/cgen' +sed 's/^X//' > 'src/cgen' << 'EOF' +X# Python script to parse cstubs file for gl and generate C stubs. +X# usage: python cgen <cstubs >glmodule.c +X# +X# XXX BUG return arrays generate wrong code +X# XXX need to change error returns into gotos to free mallocked arrays +X +X +Ximport string +Ximport sys +X +X +X# Function to print to stderr +X# +Xdef err(args): +X savestdout = sys.stdout +X try: +X sys.stdout = sys.stderr +X for i in args: +X print i, +X print +X finally: +X sys.stdout = savestdout +X +X +X# The set of digits that form a number +X# +Xdigits = '0123456789' +X +X +X# Function to extract a string of digits from the front of the string. +X# Returns the leading string of digits and the remaining string. +X# If no number is found, returns '' and the original string. +X# +Xdef getnum(s): +X n = '' +X while s and s[0] in digits: +X n = n + s[0] +X s = s[1:] +X return n, s +X +X +X# Function to check if a string is a number +X# +Xdef isnum(s): +X if not s: return 0 +X for c in s: +X if not c in digits: return 0 +X return 1 +X +X +X# Allowed function return types +X# +Xreturn_types = ['void', 'short', 'long'] +X +X +X# Allowed function argument types +X# +Xarg_types = ['char', 'string', 'short', 'float', 'long', 'double'] +X +X +X# Need to classify arguments as follows +X# simple input variable +X# simple output variable +X# input array +X# output array +X# input giving size of some array +X# +X# Array dimensions can be specified as follows +X# constant +X# argN +X# constant * argN +X# retval +X# constant * retval +X# +X# The dimensions given as constants * something are really +X# arrays of points where points are 2- 3- or 4-tuples +X# +X# We have to consider three lists: +X# python input arguments +X# C stub arguments (in & out) +X# python output arguments (really return values) +X# +X# There is a mapping from python input arguments to the input arguments +X# of the C stub, and a further mapping from C stub arguments to the +X# python return values +X +X +X# Exception raised by checkarg() and generate() +X# +Xarg_error = 'bad arg' +X +X +X# Function to check one argument. +X# Arguments: the type and the arg "name" (really mode plus subscript). +X# Raises arg_error if something's wrong. +X# Return type, mode, factor, rest of subscript; factor and rest may be empty. +X# +Xdef checkarg(type, arg): +X # +X # Turn "char *x" into "string x". +X # +X if type = 'char' and arg[0] = '*': +X type = 'string' +X arg = arg[1:] +X # +X # Check that the type is supported. +X # +X if type not in arg_types: +X raise arg_error, ('bad type', type) +X # +X # Split it in the mode (first character) and the rest. +X # +X mode, rest = arg[:1], arg[1:] +X # +X # The mode must be 's' for send (= input) or 'r' for return argument. +X # +X if mode not in ('r', 's'): +X raise arg_error, ('bad arg mode', mode) +X # +X # Is it a simple argument: if so, we are done. +X # +X if not rest: +X return type, mode, '', '' +X # +X # Not a simple argument; must be an array. +X # The 'rest' must be a subscript enclosed in [ and ]. +X # The subscript must be one of the following forms, +X # otherwise we don't handle it (where N is a number): +X # N +X # argN +X # retval +X # N*argN +X # N*retval +X # +X if rest[:1] <> '[' or rest[-1:] <> ']': +X raise arg_error, ('subscript expected', rest) +X sub = rest[1:-1] +X # +X # Is there a leading number? +X # +X num, sub = getnum(sub) +X if num: +X # There is a leading number +X if not sub: +X # The subscript is just a number +X return type, mode, num, '' +X if sub[:1] = '*': +X # There is a factor prefix +X sub = sub[1:] +X else: +X raise arg_error, ('\'*\' expected', sub) +X if sub = 'retval': +X # size is retval -- must be a reply argument +X if mode <> 'r': +X raise arg_error, ('non-r mode with [retval]', mode) +X elif sub[:3] <> 'arg' or not isnum(sub[3:]): +X raise arg_error, ('bad subscript', sub) +X # +X return type, mode, num, sub +X +X +X# List of functions for which we have generated stubs +X# +Xfunctions = [] +X +X +X# Generate the stub for the given function, using the database of argument +X# information build by successive calls to checkarg() +X# +Xdef generate(type, func, database): +X # +X # Check that we can handle this case: +X # no variable size reply arrays yet +X # +X n_in_args = 0 +X n_out_args = 0 +X # +X for a_type, a_mode, a_factor, a_sub in database: +X if a_mode = 's': +X n_in_args = n_in_args + 1 +X elif a_mode = 'r': +X n_out_args = n_out_args + 1 +X else: +X # Can't happen +X raise arg_error, ('bad a_mode', a_mode) +X if (a_mode = 'r' and a_sub) or a_sub = 'retval': +X e = 'Function', func, 'too complicated:' +X err(e + (a_type, a_mode, a_factor, a_sub)) +X print '/* XXX Too complicated to generate code for */' +X return +X # +X functions.append(func) +X # +X # Stub header +X # +X print +X print 'static object *' +X print 'gl_' + func + '(self, args)' +X print '\tobject *self;' +X print '\tobject *args;' +X print '{' +X # +X # Declare return value if any +X # +X if type <> 'void': +X print '\t' + type, 'retval;' +X # +X # Declare arguments +X # +X for i in range(len(database)): +X a_type, a_mode, a_factor, a_sub = database[i] +X print '\t' + a_type, +X if a_sub: +X print '*', +X print 'arg' + `i+1`, +X if a_factor and not a_sub: +X print '[', a_factor, ']', +X print ';' +X # +X # Find input arguments derived from array sizes +X # +X for i in range(len(database)): +X a_type, a_mode, a_factor, a_sub = database[i] +X if a_mode = 's' and a_sub[:3] = 'arg' and isnum(a_sub[3:]): +X # Sending a variable-length array +X n = eval(a_sub[3:]) +X if 1 <= n <= len(database): +X b_type, b_mode, b_factor, b_sub = database[n-1] +X if b_mode = 's': +X database[n-1] = b_type, 'i', a_factor, `i` +X n_in_args = n_in_args - 1 +X # +X # Assign argument positions in the Python argument list +X # +X in_pos = [] +X i_in = 0 +X for i in range(len(database)): +X a_type, a_mode, a_factor, a_sub = database[i] +X if a_mode = 's': +X in_pos.append(i_in) +X i_in = i_in + 1 +X else: +X in_pos.append(-1) +X # +X # Get input arguments +X # +X for i in range(len(database)): +X a_type, a_mode, a_factor, a_sub = database[i] +X if a_mode = 'i': +X # +X # Implicit argument; +X # a_factor is divisor if present, +X # a_sub indicates which arg (`database index`) +X # +X j = eval(a_sub) +X print '\tif', +X print '(!geti' + a_type + 'arraysize(args,', +X print `n_in_args` + ',', +X print `in_pos[j]` + ',', +X print '&arg' + `i+1` + '))' +X print '\t\treturn NULL;' +X if a_factor: +X print '\targ' + `i+1`, +X print '= arg' + `i+1`, +X print '/', a_factor + ';' +X elif a_mode = 's': +X if a_sub: # Allocate memory for varsize array +X print '\tif ((arg' + `i+1`, '=', +X print 'NEW(' + a_type + ',', +X if a_factor: print a_factor, '*', +X print a_sub, ')) == NULL)' +X print '\t\treturn err_nomem();' +X print '\tif', +X if a_factor or a_sub: # Get a fixed-size array array +X print '(!geti' + a_type + 'array(args,', +X print `n_in_args` + ',', +X print `in_pos[i]` + ',', +X if a_factor: print a_factor, +X if a_factor and a_sub: print '*', +X if a_sub: print a_sub, +X print ', arg' + `i+1` + '))' +X else: # Get a simple variable +X print '(!geti' + a_type + 'arg(args,', +X print `n_in_args` + ',', +X print `in_pos[i]` + ',', +X print '&arg' + `i+1` + '))' +X print '\t\treturn NULL;' +X # +X # Begin of function call +X # +X if type <> 'void': +X print '\tretval =', func + '(', +X else: +X print '\t' + func + '(', +X # +X # Argument list +X # +X for i in range(len(database)): +X if i > 0: print ',', +X a_type, a_mode, a_factor, a_sub = database[i] +X if a_mode = 'r' and not a_factor: +X print '&', +X print 'arg' + `i+1`, +X # +X # End of function call +X # +X print ');' +X # +X # Free varsize arrays +X # +X for i in range(len(database)): +X a_type, a_mode, a_factor, a_sub = database[i] +X if a_mode = 's' and a_sub: +X print '\tDEL(arg' + `i+1` + ');' +X # +X # Return +X # +X if n_out_args: +X # +X # Multiple return values -- construct a tuple +X # +X if type <> 'void': +X n_out_args = n_out_args + 1 +X if n_out_args = 1: +X for i in range(len(database)): +X a_type, a_mode, a_factor, a_sub = database[i] +X if a_mode = 'r': +X break +X else: +X raise arg_error, 'expected r arg not found' +X print '\treturn', +X print mkobject(a_type, 'arg' + `i+1`) + ';' +X else: +X print '\t{ object *v = newtupleobject(', +X print n_out_args, ');' +X print '\t if (v == NULL) return NULL;' +X i_out = 0 +X if type <> 'void': +X print '\t settupleitem(v,', +X print `i_out` + ',', +X print mkobject(type, 'retval') + ');' +X i_out = i_out + 1 +X for i in range(len(database)): +X a_type, a_mode, a_factor, a_sub = database[i] +X if a_mode = 'r': +X print '\t settupleitem(v,', +X print `i_out` + ',', +X s = mkobject(a_type, 'arg' + `i+1`) +X print s + ');' +X i_out = i_out + 1 +X print '\t return v;' +X print '\t}' +X else: +X # +X # Simple function return +X # Return None or return value +X # +X if type = 'void': +X print '\tINCREF(None);' +X print '\treturn None;' +X else: +X print '\treturn', mkobject(type, 'retval') + ';' +X # +X # Stub body closing brace +X # +X print '}' +X +X +X# Subroutine to return a function call to mknew<type>object(<arg>) +X# +Xdef mkobject(type, arg): +X return 'mknew' + type + 'object(' + arg + ')' +X +X +X# Input line number +Xlno = 0 +X +X +X# Input is divided in two parts, separated by a line containing '%%'. +X# <part1> -- literally copied to stdout +X# <part2> -- stub definitions +X +X# Variable indicating the current input part. +X# +Xpart = 1 +X +X# Main loop over the input +X# +Xwhile 1: +X try: +X line = raw_input() +X except EOFError: +X break +X # +X lno = lno+1 +X words = string.split(line) +X # +X if part = 1: +X # +X # In part 1, copy everything literally +X # except look for a line of just '%%' +X # +X if words = ['%%']: +X part = part + 1 +X else: +X # +X # Look for names of manually written +X # stubs: a single percent followed by the name +X # of the function in Python. +X # The stub name is derived by prefixing 'gl_'. +X # +X if words and words[0][0] = '%': +X func = words[0][1:] +X if (not func) and words[1:]: +X func = words[1] +X if func: +X functions.append(func) +X else: +X print line +X elif not words: +X pass # skip empty line +X elif words[0] = '#include': +X print line +X elif words[0][:1] = '#': +X pass # ignore comment +X elif words[0] not in return_types: +X err('Line', lno, ': bad return type :', words[0]) +X elif len(words) < 2: +X err('Line', lno, ': no funcname :', line) +X else: +X if len(words) % 2 <> 0: +X err('Line', lno, ': odd argument list :', words[2:]) +X else: +X database = [] +X try: +X for i in range(2, len(words), 2): +X x = checkarg(words[i], words[i+1]) +X database.append(x) +X print +X print '/*', +X for w in words: print w, +X print '*/' +X generate(words[0], words[1], database) +X except arg_error, msg: +X err('Line', lno, ':', msg) +X +X +Xprint +Xprint 'static struct methodlist gl_methods[] = {' +Xfor func in functions: +X print '\t{"' + func + '", gl_' + func + '},' +Xprint '\t{NULL, NULL} /* Sentinel */' +Xprint '};' +Xprint +Xprint 'initgl()' +Xprint '{' +Xprint '\tinitmodule("gl", gl_methods);' +Xprint '}' +EOF +fi +echo 'Part 10 out of 21 of pack.out complete.' +exit 0 diff --git a/shar/python-0.9.1-11-21.shar b/shar/python-0.9.1-11-21.shar new file mode 100644 index 0000000..59aa0a2 --- /dev/null +++ b/shar/python-0.9.1-11-21.shar @@ -0,0 +1,2618 @@ +: This is a shell archive. +: Extract with 'sh this_file'. +: +: Extract part 01 first since it makes all directories +echo 'Start of pack.out, part 11 out of 21:' +if test -s 'lib/Buttons.py' +then echo '*** I will not over-write existing file lib/Buttons.py' +else +echo 'x - lib/Buttons.py' +sed 's/^X//' > 'lib/Buttons.py' << 'EOF' +X# Module 'Buttons' +X +X +X# Import module 'rect' renamed as '_rect' to avoid exporting it on +X# 'from Buttons import *' +X# +Ximport rect +X_rect = rect +Xdel rect +X +X +X# Field indices in mouse event detail +X# +X_HV = 0 +X_CLICKS = 1 +X_BUTTON = 2 +X_MASK = 3 +X +X +X# LabelAppearance provides defaults for all appearance methods. +X# selected state not visible +X# disabled --> crossed out +X# hilited --> inverted +X# +Xclass LabelAppearance(): +X # +X # Initialization +X # +X def init_appearance(self): +X self.bounds = _rect.empty +X self.enabled = 1 +X self.hilited = 0 +X self.selected = 0 +X self.text = '' +X # +X # Size enquiry +X # +X def minsize(self, m): +X try: +X self.text = self.text +X except NameError: +X self.text = '' +X return m.textwidth(self.text) + 6, m.lineheight() + 6 +X # +X def getbounds(self): +X return self.bounds +X # +X # Changing the parameters +X # +X def settext(self, text): +X self.text = text +X if self.bounds <> _rect.empty: +X self.recalctextpos() +X self.redraw() +X # +X def setbounds(self, bounds): +X if self.bounds <> _rect.empty: +X self.parent.change(self.bounds) +X self.bounds = bounds +X if self.bounds <> _rect.empty: +X self.recalc() +X self.parent.change(bounds) +X # +X # Changing the state bits +X # +X def enable(self, flag): +X if flag <> self.enabled: +X self.enabled = flag +X if self.bounds <> _rect.empty: +X self.flipenable(self.parent.begindrawing()) +X # +X def hilite(self, flag): +X if flag <> self.hilited: +X self.hilited = flag +X if self.bounds <> _rect.empty: +X self.fliphilite(self.parent.begindrawing()) +X # +X def select(self, flag): +X if flag <> self.selected: +X self.selected = flag +X if self.bounds <> _rect.empty: +X self.redraw() +X # +X # Recalculate the box bounds and text position. +X # This can be overridden by buttons that draw different boxes +X # or want their text in a different position. +X # +X def recalc(self): +X if self.bounds <> _rect.empty: +X self.recalcbounds() +X self.recalctextpos() +X # +X def recalcbounds(self): +X self.hilitebounds = _rect.inset(self.bounds, (3, 3)) +X self.crossbounds = self.bounds +X # +X def recalctextpos(self): +X (left, top), (right, bottom) = self.bounds +X m = self.parent.beginmeasuring() +X h = (left + right - m.textwidth(self.text)) / 2 +X v = (top + bottom - m.lineheight()) / 2 +X self.textpos = h, v +X # +X # Generic drawing interface. +X # Do not override redraw() or draw() methods; override drawit() c.s. +X # +X def redraw(self): +X if self.bounds <> _rect.empty: +X self.draw(self.parent.begindrawing(), self.bounds) +X # +X def draw(self, (d, area)): +X area = _rect.intersect(area, self.bounds) +X if area = _rect.empty: +X return +X d.cliprect(area) +X d.erase(self.bounds) +X self.drawit(d) +X d.noclip() +X # +X # The drawit() method is fairly generic but may be overridden. +X # +X def drawit(self, d): +X self.drawpict(d) +X if self.text: +X d.text(self.textpos, self.text) +X if not self.enabled: +X self.flipenable(d) +X if self.hilited: +X self.fliphilite(d) +X # +X # Default drawing detail functions. +X # Overriding these is normally sufficient to get different +X # appearances. +X # +X def drawpict(self, d): +X pass +X # +X def flipenable(self, d): +X _xorcross(d, self.crossbounds) +X # +X def fliphilite(self, d): +X d.invert(self.hilitebounds) +X +X +X# ButtonAppearance displays a centered string in a box. +X# selected --> bold border +X# disabled --> crossed out +X# hilited --> inverted +X# +Xclass ButtonAppearance() = LabelAppearance(): +X # +X def drawpict(self, d): +X d.box(_rect.inset(self.bounds, (1, 1))) +X if self.selected: +X # Make a thicker box +X d.box(self.bounds) +X d.box(_rect.inset(self.bounds, (2, 2))) +X d.box(_rect.inset(self.bounds, (3, 3))) +X # +X +X +X# CheckAppearance displays a small square box and a left-justified string. +X# selected --> a cross appears in the box +X# disabled --> whole button crossed out +X# hilited --> box is inverted +X# +Xclass CheckAppearance() = LabelAppearance(): +X # +X def minsize(self, m): +X width, height = m.textwidth(self.text) + 6, m.lineheight() + 6 +X return width + height + m.textwidth(' '), height +X # +X def drawpict(self, d): +X d.box(self.boxbounds) +X if self.selected: _xorcross(d, self.boxbounds) +X # +X def recalcbounds(self): +X LabelAppearance.recalcbounds(self) +X (left, top), (right, bottom) = self.bounds +X self.size = bottom - top - 4 +X self.boxbounds = (left+2, top+2), (left+2+self.size, bottom-2) +X self.hilitebounds = self.boxbounds +X # +X def recalctextpos(self): +X m = self.parent.beginmeasuring() +X (left, top), (right, bottom) = self.boxbounds +X h = right + m.textwidth(' ') +X v = top + (self.size - m.lineheight()) / 2 +X self.textpos = h, v +X # +X +X +X# RadioAppearance displays a round indicator and a left-justified string. +X# selected --> a dot appears in the indicator +X# disabled --> whole button crossed out +X# hilited --> indicator is inverted +X# +Xclass RadioAppearance() = CheckAppearance(): +X # +X def drawpict(self, d): +X (left, top), (right, bottom) = self.boxbounds +X radius = self.size / 2 +X h, v = left + radius, top + radius +X d.circle((h, v), radius) +X if self.selected: +X some = radius/3 +X d.paint((h-some, v-some), (h+some, v+some)) +X # +X +X +X# NoReactivity ignores mouse events. +X# +Xclass NoReactivity(): +X def init_reactivity(self): pass +X +X +X# BaseReactivity defines hooks and asks for mouse events, +X# but provides only dummy mouse event handlers. +X# The trigger methods call the corresponding hooks set by the user. +X# Hooks (and triggers) mean the following: +X# down_hook called on some mouse-down events +X# move_hook called on some mouse-move events +X# up_hook called on mouse-up events +X# on_hook called for buttons with on/off state, when it goes on +X# hook called when a button 'fires' or a radiobutton goes on +X# There are usually extra conditions, e.g., hooks are only called +X# when the button is enabled, or active, or selected (on). +X# +Xclass BaseReactivity(): +X # +X def init_reactivity(self): +X self.down_hook = self.move_hook = self.up_hook = \ +X self.on_hook = self.off_hook = \ +X self.hook = self.active = 0 +X self.parent.need_mouse(self) +X # +X def mousetest(self, hv): +X return _rect.pointinrect(hv, self.bounds) +X # +X def mouse_down(self, detail): +X pass +X # +X def mouse_move(self, detail): +X pass +X # +X def mouse_up(self, detail): +X pass +X # +X def down_trigger(self): +X if self.down_hook: self.down_hook(self) +X # +X def move_trigger(self): +X if self.move_hook: self.move_hook(self) +X # +X def up_trigger(self): +X if self.up_hook: self.up_hook(self) +X # +X def on_trigger(self): +X if self.on_hook: self.on_hook(self) +X # +X def off_trigger(self): +X if self.off_hook: self.off_hook(self) +X # +X def trigger(self): +X if self.hook: self.hook(self) +X +X +X# ToggleReactivity acts like a simple pushbutton. +X# It toggles its hilite state on mouse down events. +X# +Xclass ToggleReactivity() = BaseReactivity(): +X # +X def mouse_down(self, detail): +X if self.enabled and self.mousetest(detail[_HV]): +X self.active = 1 +X self.hilite(not self.hilited) +X self.down_trigger() +X # +X def mouse_move(self, detail): +X if self.active: +X self.move_trigger() +X # +X def mouse_up(self, detail): +X if self.active: +X self.up_trigger() +X self.active = 0 +X # +X def down_trigger(self): +X if self.hilited: +X self.on_trigger() +X else: +X self.off_trigger() +X self.trigger() +X # +X +X +X# TriggerReactivity acts like a fancy pushbutton. +X# It hilites itself while the mouse is down within its bounds. +X# +Xclass TriggerReactivity() = BaseReactivity(): +X # +X def mouse_down(self, detail): +X if self.enabled and self.mousetest(detail[_HV]): +X self.active = 1 +X self.hilite(1) +X self.down_trigger() +X # +X def mouse_move(self, detail): +X if self.active: +X self.hilite(self.mousetest(detail[_HV])) +X if self.hilited: +X self.move_trigger() +X # +X def mouse_up(self, detail): +X if self.active: +X self.hilite(self.mousetest(detail[_HV])) +X if self.hilited: +X self.up_trigger() +X self.trigger() +X self.active = 0 +X self.hilite(0) +X # +X +X +X# CheckReactivity handles mouse events like TriggerReactivity, +X# It overrides the up_trigger method to flip its selected state. +X# +Xclass CheckReactivity() = TriggerReactivity(): +X # +X def up_trigger(self): +X self.select(not self.selected) +X if self.selected: +X self.on_trigger() +X else: +X self.off_trigger() +X self.trigger() +X +X +X# RadioReactivity turns itself on and the other buttons in its group +X# off when its up_trigger method is called. +X# +Xclass RadioReactivity() = TriggerReactivity(): +X # +X def init_reactivity(self): +X TriggerReactivity.init_reactivity(self) +X self.group = [] +X # +X def up_trigger(self): +X for b in self.group: +X if b <> self: +X if b.selected: +X b.select(0) +X b.off_trigger() +X self.select(1) +X self.on_trigger() +X self.trigger() +X +X +X# Auxiliary class for 'define' method. +X# Call the initializers in the right order. +X# +Xclass Define(): +X # +X def define(self, parent): +X self.parent = parent +X parent.addchild(self) +X self.init_appearance() +X self.init_reactivity() +X return self +X # +X def destroy(self): +X self.parent = 0 +X # +X def definetext(self, (parent, text)): +X self = self.define(parent) +X self.settext(text) +X return self +X +X +X# Subroutine to cross out a rectangle. +X# +Xdef _xorcross(d, bounds): +X ((left, top), (right, bottom)) = bounds +X # This is s bit funny to make it look better +X left = left + 2 +X right = right - 2 +X top = top + 2 +X bottom = bottom - 3 +X d.xorline(((left, top), (right, bottom))) +X d.xorline((left, bottom), (right, top)) +X +X +X# Ready-made button classes. +X# +Xclass Label() = NoReactivity(), LabelAppearance(), Define(): pass +Xclass PushButton() = TriggerReactivity(), ButtonAppearance(), Define(): pass +Xclass CheckButton() = CheckReactivity(), CheckAppearance(), Define(): pass +Xclass RadioButton() = RadioReactivity(), RadioAppearance(), Define(): pass +Xclass ToggleButton() = ToggleReactivity(), ButtonAppearance(), Define(): pass +EOF +fi +if test -s 'lib/TclUtil.py' +then echo '*** I will not over-write existing file lib/TclUtil.py' +else +echo 'x - lib/TclUtil.py' +sed 's/^X//' > 'lib/TclUtil.py' << 'EOF' +X# Utilities used by 'Tcl' emulator. +X +X +X# Many functions in this file parse specific constructs from strings. +X# In order to limit the number of slice operations (the strings can +X# be very large), they always receive indices into the string that +X# indicate the slice of the string that should be considered. +X# The return value is in general another index, pointing to the first +X# character in the string beyond the recognized construct. +X# Errors are reported as exceptions (TclSyntaxError, TclMatchingError). +X# A few functions have multiple return values. +X +X +X# For efficiency, the Tcl "tokenizing" routines used pre-compiled +X# regular expressions. This is less readable but should be much faster +X# than scanning the string a character at a time. +X# +X# The global variables +X# containing the compiled regexp's are named _foo_prog where foo is +X# an indication of the function that uses them. +X# +X# The patterns always +X# have the form <something>* so they always match at the start of the +X# search buffer---maybe with the empty string. This makes it possible +X# to use the expression "_foo_prog.exec(str, i)[0][1]" to find the first +X# character beyond the matched string. Note that this may be beyond the +X# end variable -- where this matters, "min(i, end)" is used. +X +X# Constructs that cannot +X# be recognized by a finite automaton (like matching braces) are scanned +X# by a hybrid technique where the regular expression excludes the +X# braces. +X# +X# Many regular expressions contain an expression that matches +X# a Tcl backslash sequence as a subpart: +X# \\\\C?M?(.|\n) +X# +X# This is a bit hard to +X# read because the backslash contained in it must be doubled twice: +X# once to get past Python's backslash mechanism, once to get past that +X# of regular expressions. It uses (.|\n) to match absolutely +X# *every character*, becase the MULTILINE regular expression package does +X# not accept '\n' as a match for '.'. +X# +X# There is also a simplification in the pattern for backslashes: +X# *any* single character following a backslash is escaped, +X# so hex and octal +X# excapes are not scanned fully. The forms \Cx, \Mx and \CMx are +X# scanned correctly, as these may hide a special character. +X# (This does not invalidate the recognition of strings, although the +X# match is effectuated in a different way than by the Backslash function.) +X +Ximport regexp +X +X +X# Exceptions raised for various error conditions. +X +XTclAssertError = 'Tcl assert error' +XTclSyntaxError = 'Tcl syntax error' +XTclRuntimeError = 'Tcl runtime error' +XTclMatchingError = 'Tcl matching error' +X +X +X# Find a variable name. +X# A variable name is either a (possiblly empty) sequence of letters, +X# digits and underscores, or anything enclosed in matching braces. +X# Return the index past the end of the name. +X +X_varname_prog = regexp.compile('[a-zA-Z0-9_]*') +X +Xdef FindVarName(str, i, end): +X if i < end and str[i] = '{': return BalanceBraces(str, i, end) +X i = _varname_prog.exec(str, i)[0][1] +X return min(i, end) +X +X +X# Split a list into its elements. +X# Return a list of elements (strings). +X +Xdef SplitList(str): +X i, end = 0, len(str) +X list = [] +X while 1: +X i = SkipSpaces(str, i, end) +X if i >= end: break +X j = i +X i = FindNextElement(str, i, end) +X if str[j] = '{' and str[i-1] = '}': +X element = str[j+1:i-1] +X else: +X element = Collapse(str[j:i]) +X list.append(element) +X return list +X +X +X# Find the next element from a list. +X +X_element_prog = regexp.compile('([^ \t\n\\]+|\\\\C?M?(.|\n))*') +X +Xdef FindNextElement(str, i, end): +X if i < end and str[i] = '{': +X i = BalanceBraces(str, i, end) +X if i < end and str[i] not in ' \t\n': +X raise TclSyntaxError, 'Garbage after } in list' +X return i +X i = _element_prog.exec(str, i)[0][1] +X return min(i, end) +X +X +X# Copy a string, expanding all backslash sequences. +X +X_collapse_prog = regexp.compile('(\n|[^\\]+)*') +X +Xdef Collapse(str): +X if '\\' not in str: return str +X i, end = 0, len(str) +X result = '' +X while i < end: +X j = _collapse_prog.exec(str, i)[0][1] +X j = min(j, end) +X result = result + str[i:j] +X if j >= end: break +X c = str[j] +X if c <> '\\': raise TclAssertError, 'collapse error' +X x, i = Backslash(str, j, end) +X result = result + x +X return result +X +X +X# Find the next full command. +X# Return a list of begin, end indices of words in the string, +X# and an index pointing just after the terminating newline or +X# semicolon. +X# Initial spaces are skipped. +X# If the command begins with '#', it is considered empty and +X# characters until '\n' are skipped. +X +X_eol_prog = regexp.compile('[^\n]*') +X +Xdef FindNextCommand(str, i, end, bracketed): +X i = SkipSpaces(str, i, end) +X if i >= end: return [], end +X if str[i] = '#': +X i = _eol_prog.exec(str, i) +X i = min(i, end) +X if i < end and str[i] = '\n': i = i+1 +X return [], i +X if bracketed: terminators = [';'] +X else: terminators = [';', '\n'] +X list = [] +X while i < end: +X j = FindNextWord(str, i, end) +X word = str[i:j] +X if word in terminators: +X i = j +X break +X if word <> '\n': list.append(i, j) +X i = SkipSpaces(str, j, end) +X return list, i +X +X +X# Find the next word of a command. +X# Semicolon and newline terminate words but also count as a word +X# themselves. +X# The start index must point to the start of the word. +X +X_word_prog = regexp.compile('([^ \t\n;[\\]+|\\\\C?M?(.|\n))*') +X +Xdef FindNextWord(str, i, end): +X if i >= end: return end +X if str[i] in '{"': +X if str[i] = '{': i = BalanceBraces(str, i, end) +X else: i = BalanceQuotes(str, i, end) +X if i >= end or str[i] in ' \t\n;': return min(i, end) +X raise TclSyntaxError, 'Garbage after } or "' +X begin = i +X while i < end: +X i = _word_prog.exec(str, i)[0][1] +X if i >= end: +X i = end +X break +X c = str[i] +X if c in ' \t': break +X if c in ';\n': +X if i = begin: i = i+1 +X break +X if c = '[': i = BalanceBrackets(str, i, end) +X else: raise TclAssertError, 'word error' +X return i +X +X +X# Parse balanced brackets from str[i:end]. +X# str[i] must be '['. +X# Returns end such that str[i:end] ends with ']' +X# and contains balanced braces and brackets. +X +X_brackets_prog = regexp.compile('([^][{\\]+|\n|\\\\C?M?(.|\n))*') +X +Xdef BalanceBrackets(str, i, end): +X if i >= end or str[i] <> '[': +X raise TclAssertError, 'BalanceBrackets' +X nesting = 0 +X while i < end: +X i = _brackets_prog.exec(str, i)[0][1] +X if i >= end: break +X c = str[i] +X if c = '{': i = BalanceBraces(str, i, end) +X else: +X i = i+1 +X if c = '[': nesting = nesting + 1 +X elif c = ']': +X nesting = nesting - 1 +X if nesting = 0: return i +X else: raise TclAssertError, 'brackets error' +X raise TclMatchingError, 'Unmatched bracket ([)' +X +X +X# Parse balanced braces from str[i:end]. +X# str[i] must be '{'. +X# Returns end such that str[i:end] ends with '}' +X# and contains balanced braces. +X +X_braces_prog = regexp.compile('([^{}\\]+|\n|\\\\C?M?(.|\n))*') +X +Xdef BalanceBraces(str, i, end): +X if i >= end or str[i] <> '{': +X raise TclAssertError, 'BalanceBraces' +X nesting = 0 +X while i < end: +X i = _braces_prog.exec(str, i)[0][1] +X if i >= end: break +X c = str[i] +X i = i+1 +X if c = '{': nesting = nesting + 1 +X elif c = '}': +X nesting = nesting - 1 +X if nesting = 0: return i +X else: raise TclAssertError, 'braces error' +X raise TclMatchingError, 'Unmatched brace ({)' +X +X +X# Parse double quotes from str[i:end]. +X# str[i] must be '"'. +X# Returns end such that str[i:end] ends with an unescaped '"'. +X +X_quotes_prog = regexp.compile('([^"\\]+|\n|\\\\C?M?(.|\n))*') +X +Xdef BalanceQuotes(str, i, end): +X if i >= end or str[i] <> '"': +X raise TclAssertError, 'BalanceQuotes' +X i = _quotes_prog.exec(str, i+1)[0][1] +X if i < end and str[i] = '"': return i+1 +X raise TclMatchingError, 'Unmatched quote (")' +X +X +X# Static data used by Backslash() +X +X_bstab = {} +X_bstab['n'] = '\n' +X_bstab['r'] = '\r' +X_bstab['t'] = '\t' +X_bstab['b'] = '\b' +X_bstab['e'] = '\033' +X_bstab['\n'] = '' +Xfor c in ' {}[]$";\\': _bstab[c] = c +Xdel c +X +X# Backslash interpretation. +X# First character must be a backslash. +X# Return a pair (<replacement string>, <end of sequence>). +X# Unrecognized or incomplete backslash sequences are not errors; +X# this takes only the backslash itself off the string. +X +Xdef Backslash(str, i, end): +X if i >= end or str[i] <> '\\': +X raise TclAssertError, 'Backslash' +X i = i+1 +X if i = end: return '\\', i +X c = str[i] +X i = i+1 +X if _bstab.has_key(c): return _bstab[c], i +X if c = 'C': +X if i = end: return '\\', i-1 +X c = str[i] +X i = i+1 +X if c = 'M': +X if i = end: return '\\', i-2 +X c = str[i] +X i = i+1 +X x = ord(c) % 040 + 0200 +X else: +X x = ord(c) % 040 +X return chr(x), i +X elif c = 'M': +X if i = end: return '\\', i-1 +X c = str[i] +X i = i+1 +X x = ord(c) +X if x < 0200: x = x + 0200 +X return chr(x), i +X elif c and c in '0123456789': +X x = ord(c) - ord('0') +X end = min(end, i+2) +X while i < end: +X c = str[i] +X if c not in '0123456789': break +X i = i+1 +X x = x*8 + ord(c) - ord('0') +X return ord(x), i +X else: +X # Not something that we recognize +X return '\\', i-1 +X +X +X# Skip over spaces and tabs (but not newlines). +X +X_spaces_prog = regexp.compile('[ \t]*') +X +Xdef SkipSpaces(str, i, end): +X i = _spaces_prog.exec(str, i)[0][1] +X return min(i, end) +X +X +X# Concatenate the elements of a list with intervening spaces. +X +Xdef Concat(argv): +X result = '' +X sep = '' +X for arg in argv: +X result = result + (sep + arg) +X sep = ' ' +X return result +X +X +X# Concatenate list elements, adding braces etc. to make them parseable +X# again with SplitList. +X +Xdef BuildList(argv): +X result = '' +X sep = '' +X for arg in argv: +X arg = AddBraces(arg) +X result = result + (sep + arg) +X sep = ' ' +X return result +X +X +X# Add braces around a string if necessary to make it parseable by SplitList. +X +Xdef AddBraces(str): +X # Special case for empty string +X if str = '': return '{}' +X # See if it contains balanced braces +X res = '{' + str + '}' +X if TryNextElement(res): +X # See if it would survive unquoted +X # XXX should escape [] and $ as well??? +X if TryNextElement(str) and Collapse(str) = str: return str +X # No -- return with added braces +X return res +X # Unbalanced braces. Add backslashes before suspect characters +X res = '' +X for c in str: +X if c in '$\\[]{} ;': c = '\\' + c +X elif c = '\n': c = '\\n' +X elif c = '\t': c = '\\t' +X res = res + c +X return res +X +X +Xdef TryNextElement(str): +X end = len(str) +X try: +X i = FindNextElement(str, 0, end) +X return i = end +X except (TclSyntaxError, TclMatchingError): +X return 0 +EOF +fi +if test -s 'lib/testall.py' +then echo '*** I will not over-write existing file lib/testall.py' +else +echo 'x - lib/testall.py' +sed 's/^X//' > 'lib/testall.py' << 'EOF' +X# Module 'testall' +X# +X# Python test set, should exercise: +X# - all lexical and grammatical constructs +X# - all opcodes from "opcode.h" +X# - all operations on all object types +X# - all builtin functions +X# Ideally also: +X# - all possible exception situations (Thank God we've got 'try') +X# - all boundary cases +X +X +XTestFailed = 'testall -- test failed' # Exception +X +X +X######################################################### +X# Part 1. Test all lexical and grammatical constructs. +X# This just tests whether the parser accepts them all. +X######################################################### +X +Xprint '1. Parser' +X +Xprint '1.1 Tokens' +X +Xprint '1.1.1 Backslashes' +X +X# Backslash means line continuation: +Xx = 1 \ +X+ 1 +Xif x <> 2: raise TestFailed, 'backslash for line continuation' +X +X# Backslash does not means continuation in comments :\ +Xx = 0 +Xif x <> 0: raise TestFailed, 'backslash ending comment' +X +Xprint '1.1.2 Number formats' +X +Xif 0xff <> 255: raise TestFailed, 'hex number' +Xif 0377 <> 255: raise TestFailed, 'octal number' +Xx = 3.14 +Xx = 0.314 +Xx = 3e14 +Xx = 3E14 +Xx = 3e-14 +X +Xprint '1.2 Grammar' +X +Xprint 'single_input' # NEWLINE | simple_stmt | compound_stmt NEWLINE +X# XXX can't test in a script -- this rule is only used when interactive +X +Xprint 'file_input' # (NEWLINE | stmt)* ENDMARKER +X# Being tested as this very moment this very module +X +Xprint 'expr_input' # testlist NEWLINE +X# XXX Hard to test -- used only in calls to input() +X +Xprint 'eval_input' # testlist ENDMARKER +Xx = eval('1, 0 or 1') +X +Xprint 'funcdef' # 'def' NAME parameters ':' suite +X### parameters: '(' [fplist] ')' +X### fplist: fpdef (',' fpdef)* +X### fpdef: NAME | '(' fplist ')' +Xdef f1(): pass +Xdef f2(one_argument): pass +Xdef f3(two, arguments): pass +Xdef f4(two, (compound, (arguments))): pass +X +X### stmt: simple_stmt | compound_stmt +X### simple_stmt: expr_stmt | print_stmt | pass_stmt | del_stmt | flow_stmt | import_stmt +X# Tested below +X +Xprint 'expr_stmt' # (exprlist '=')* exprlist NEWLINE +X1 +X1, 2, 3 +Xx = 1 +Xx = 1, 2, 3 +Xx = y = z = 1, 2, 3 +Xx, y, z = 1, 2, 3 +Xabc = a, b, c = x, y, z = xyz = 1, 2, (3, 4) +X# NB these variables are deleted below +X +Xprint 'print_stmt' # 'print' (test ',')* [test] NEWLINE +Xprint 1, 2, 3 +Xprint 1, 2, 3, +Xprint +Xprint 0 or 1, 0 or 1, +Xprint 0 or 1 +X +Xprint 'del_stmt' # 'del' exprlist NEWLINE +Xdel abc +Xdel x, y, (z, xyz) +X +Xprint 'pass_stmt' # 'pass' NEWLINE +Xpass +X +Xprint 'flow_stmt' # break_stmt | return_stmt | raise_stmt +X# Tested below +X +Xprint 'break_stmt' # 'break' NEWLINE +Xwhile 1: break +X +Xprint 'return_stmt' # 'return' [testlist] NEWLINE +Xdef g1(): return +Xdef g2(): return 1 +Xg1() +Xx = g2() +X +Xprint 'raise_stmt' # 'raise' expr [',' expr] NEWLINE +Xtry: raise RuntimeError, 'just testing' +Xexcept RuntimeError: pass +Xtry: raise KeyboardInterrupt +Xexcept KeyboardInterrupt: pass +X +Xprint 'import_stmt' # 'import' NAME (',' NAME)* NEWLINE | 'from' NAME 'import' ('*' | NAME (',' NAME)*) NEWLINE +X[1] +Ximport sys +X[2] +Ximport time, math +X[3] +Xfrom time import sleep +X[4] +Xfrom math import * +X[5] +Xfrom sys import modules, ps1, ps2 +X[6] +X +X### compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef +X# Tested below +X +Xprint 'if_stmt' # 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] +Xif 1: pass +Xif 1: pass +Xelse: pass +Xif 0: pass +Xelif 0: pass +Xif 0: pass +Xelif 0: pass +Xelif 0: pass +Xelif 0: pass +Xelse: pass +X +Xprint 'while_stmt' # 'while' test ':' suite ['else' ':' suite] +Xwhile 0: pass +Xwhile 0: pass +Xelse: pass +X +Xprint 'for_stmt' # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] +X[1] +Xfor i in 1, 2, 3: pass +X[2] +Xfor i, j, k in (): pass +Xelse: pass +X[3] +X +Xprint 'try_stmt' # 'try' ':' suite (except_clause ':' suite)* ['finally' ':' suite] +X### except_clause: 'except' [expr [',' expr]] +Xtry: pass +Xtry: 1/0 +Xexcept RuntimeError: pass +Xtry: 1/0 +Xexcept EOFError: pass +Xexcept TypeError, msg: pass +Xexcept RuntimeError, msg: pass +Xexcept: pass +Xtry: pass +Xfinally: pass +Xtry: 1/0 +Xexcept: pass +Xfinally: pass +X +Xprint 'suite' # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT +Xif 1: pass +Xif 1: +X pass +Xif 1: +X # +X # +X # +X pass +X pass +X # +X pass +X # +X +Xprint 'test' # and_test ('or' and_test)* +X### and_test: not_test ('and' not_test)* +X### not_test: 'not' not_test | comparison +X### comparison: expr (comp_op expr)* +X### comp_op: '<'|'>'|'='|'>' '='|'<' '='|'<' '>'|'in'|'not' 'in'|'is'|'is' 'not' +Xif 1: pass +Xif 1 = 1: pass +Xif 1 < 1 > 1 = 1 >= 1 <= 1 <> 1 in 1 not in 1 is 1 is not 1: pass +Xif not 1 = 1 = 1: pass +Xif not 1 = 1 and 1 and 1: pass +Xif 1 and 1 or 1 and 1 and 1 or not 1 = 1 = 1 and 1: pass +X +Xprint 'expr' # term (('+'|'-') term)* +Xx = 1 +Xx = 1 + 1 +Xx = 1 - 1 - 1 +Xx = 1 - 1 + 1 - 1 + 1 +X +Xprint 'term' # factor (('*'|'/'|'%') factor)* +Xx = 1 * 1 +Xx = 1 / 1 +Xx = 1 % 1 +Xx = 1 / 1 * 1 % 1 +X +Xprint 'factor' # ('+'|'-') factor | atom trailer* +X### trailer: '(' [testlist] ')' | '[' subscript ']' | '.' NAME +X### subscript: expr | [expr] ':' [expr] +Xx = +1 +Xx = -1 +Xx = 1 +Xc = sys.ps1[0] +Xx = time.time() +Xx = sys.modules['time'].time() +Xa = '01234' +Xc = a[0] +Xc = a[0:5] +Xc = a[:5] +Xc = a[0:] +Xc = a[:] +Xc = a[-5:] +Xc = a[:-1] +Xc = a[-4:-3] +X +Xprint 'atom' # '(' [testlist] ')' | '[' [testlist] ']' | '{' '}' | '`' testlist '`' | NAME | NUMBER | STRING +Xx = (1) +Xx = (1 or 2 or 3) +Xx = (1 or 2 or 3, 2, 3) +Xx = [] +Xx = [1] +Xx = [1 or 2 or 3] +Xx = [1 or 2 or 3, 2, 3] +Xx = [] +Xx = {} +Xx = `x` +Xx = x +Xx = 'x' +Xx = 123 +X +X### exprlist: expr (',' expr)* [','] +X### testlist: test (',' test)* [','] +X# These have been exercised enough above +X +Xprint 'classdef' # 'class' NAME parameters ['=' baselist] ':' suite +X### baselist: atom arguments (',' atom arguments)* +X### arguments: '(' [testlist] ')' +Xclass B(): pass +Xclass C1() = B(): pass +Xclass C2() = B(): pass +Xclass D() = C1(), C2(), B(): pass +Xclass C(): +X def meth1(self): pass +X def meth2(self, arg): pass +X def meth3(self, (a1, a2)): pass +X +X +X######################################################### +X# Part 2. Test all opcodes from "opcode.h" +X######################################################### +X +Xprint '2. Opcodes' +Xprint 'XXX Not yet fully implemented' +X +Xprint '2.1 try inside for loop' +Xn = 0 +Xfor i in range(10): +X n = n+i +X try: 1/0 +X except NameError: pass +X except RuntimeError: pass +X except TypeError: pass +X finally: pass +X try: pass +X except: pass +X try: pass +X finally: pass +X n = n+i +Xif n <> 90: +X raise TestFailed, 'try inside for' +X +X +X######################################################### +X# Part 3. Test all operations on all object types +X######################################################### +X +Xprint '3. Object types' +Xprint 'XXX Not yet implemented' +X +X +X######################################################### +X# Part 4. Test all built-in functions +X######################################################### +X +Xprint '4. Built-in functions' +X +Xprint 'abs' +Xif abs(0) <> 0: raise TestFailed, 'abs(0)' +Xif abs(1234) <> 1234: raise TestFailed, 'abs(1234)' +Xif abs(-1234) <> 1234: raise TestFailed, 'abs(-1234)' +Xif abs(0.0) <> 0.0: raise TestFailed, 'abs(0.0)' +Xif abs(3.14) <> 3.14: raise TestFailed, 'abs(3.14)' +Xif abs(-3.14) <> 3.14: raise TestFailed, 'abs(-3.14)' +X +Xprint 'dir' +Xif 'x' not in dir(): raise TestFailed, 'dir()' +Xif 'modules' not in dir(sys): raise TestFailed, 'dir(sys)' +X +Xprint 'divmod' +Xif divmod(12, 7) <> (1, 5): raise TestFailed, 'divmod(12, 7)' +Xif divmod(-12, 7) <> (-2, 2): raise TestFailed, 'divmod(-12, 7)' +Xif divmod(12, -7) <> (-2, -2): raise TestFailed, 'divmod(12, -7)' +Xif divmod(-12, -7) <> (1, -5): raise TestFailed, 'divmod(-12, -7)' +X +Xprint 'eval' +Xif eval('1+1') <> 2: raise TestFailed, 'eval(\'1+1\')' +X +Xprint 'exec' +Xexec('z=1+1\n') +Xif z <> 2: raise TestFailed, 'exec(\'z=1+1\'\\n)' +X +Xprint 'float' +Xif float(3.14) <> 3.14: raise TestFailed, 'float(3.14)' +Xif float(314) <> 314.0: raise TestFailed, 'float(314)' +X +Xprint 'input' +X# Can't test in a script +X +Xprint 'int' +Xif int(100) <> 100: raise TestFailed, 'int(100)' +Xif int(3.14) <> 3: raise TestFailed, 'int(3.14)' +X +Xprint 'len' +Xif len('123') <> 3: raise TestFailed, 'len(\'123\')' +Xif len(()) <> 0: raise TestFailed, 'len(())' +Xif len((1, 2, 3, 4)) <> 4: raise TestFailed, 'len((1, 2, 3, 4))' +Xif len([1, 2, 3, 4]) <> 4: raise TestFailed, 'len([1, 2, 3, 4])' +Xif len({}) <> 0: raise TestFailed, 'len({})' +X +Xprint 'min' +Xif min('123123') <> '1': raise TestFailed, 'min(\'123123\')' +Xif min(1, 2, 3) <> 1: raise TestFailed, 'min(1, 2, 3)' +Xif min((1, 2, 3, 1, 2, 3)) <> 1: raise TestFailed, 'min((1, 2, 3, 1, 2, 3))' +Xif min([1, 2, 3, 1, 2, 3]) <> 1: raise TestFailed, 'min([1, 2, 3, 1, 2, 3])' +X +Xprint 'max' +Xif max('123123') <> '3': raise TestFailed, 'max(\'123123\')' +Xif max(1, 2, 3) <> 3: raise TestFailed, 'max(1, 2, 3)' +Xif max((1, 2, 3, 1, 2, 3)) <> 3: raise TestFailed, 'max((1, 2, 3, 1, 2, 3))' +Xif max([1, 2, 3, 1, 2, 3]) <> 3: raise TestFailed, 'max([1, 2, 3, 1, 2, 3])' +X +Xprint 'open' +Xprint 'NB! This test creates a file named "@test" in the current directory.' +Xfp = open('@test', 'w') +Xfp.write('The quick brown fox jumps over the lazy dog') +Xfp.write('.\n') +Xfp.write('Dear John\n') +Xfp.write('XXX'*100) +Xfp.write('YYY'*100) +Xfp.close() +Xdel fp +Xfp = open('@test', 'r') +Xif fp.readline() <> 'The quick brown fox jumps over the lazy dog.\n': +X raise TestFailed, 'readline()' +Xif fp.readline(4) <> 'Dear': raise TestFailed, 'readline(4) # short' +Xif fp.readline(100) <> ' John\n': raise TestFailed, 'readline(100)' +Xif fp.read(300) <> 'XXX'*100: raise TestFailed, 'read(300)' +Xif fp.read(1000) <> 'YYY'*100: raise TestFailed, 'read(1000) # truncate' +Xfp.close() +Xdel fp +X +Xprint 'range' +Xif range(3) <> [0, 1, 2]: raise TestFailed, 'range(3)' +Xif range(1, 5) <> [1, 2, 3, 4]: raise TestFailed, 'range(1, 5)' +Xif range(0) <> []: raise TestFailed, 'range(0)' +Xif range(-3) <> []: raise TestFailed, 'range(-3)' +Xif range(1, 10, 3) <> [1, 4, 7]: raise TestFailed, 'range(1, 10, 3)' +Xif range(5, -5, -3) <> [5, 2, -1, -4]: raise TestFailed, 'range(5, -5, -3)' +X +Xprint 'raw_input' +Xsavestdin = sys.stdin +Xtry: +X sys.stdin = open('@test', 'r') +X if raw_input() <> 'The quick brown fox jumps over the lazy dog.': +X raise TestFailed, 'raw_input()' +X if raw_input('testing\n') <> 'Dear John': +X raise TestFailed, 'raw_input(\'testing\\n\')' +Xfinally: +X sys.stdin = savestdin +X +Xprint 'reload' +Ximport string +Xreload(string) +X +Xprint 'type' +Xif type('') <> type('123') or type('') = type(()): +X raise TestFailed, 'type()' +X +X +Xprint 'Passed all tests.' +X +Xtry: +X import mac +X unlink = mac.unlink +Xexcept NameError: +X try: +X import posix +X unlink = posix.unlink +X except NameError: +X pass +X +Xunlink('@test') +Xprint 'Unlinked @test' +EOF +fi +if test -s 'src/listobject.c' +then echo '*** I will not over-write existing file src/listobject.c' +else +echo 'x - src/listobject.c' +sed 's/^X//' > 'src/listobject.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* List object implementation */ +X +X#include "allobjects.h" +X +Xobject * +Xnewlistobject(size) +X int size; +X{ +X int i; +X listobject *op; +X if (size < 0) { +X err_badcall(); +X return NULL; +X } +X op = (listobject *) malloc(sizeof(listobject)); +X if (op == NULL) { +X return err_nomem(); +X } +X if (size <= 0) { +X op->ob_item = NULL; +X } +X else { +X op->ob_item = (object **) malloc(size * sizeof(object *)); +X if (op->ob_item == NULL) { +X free((ANY *)op); +X return err_nomem(); +X } +X } +X NEWREF(op); +X op->ob_type = &Listtype; +X op->ob_size = size; +X for (i = 0; i < size; i++) +X op->ob_item[i] = NULL; +X return (object *) op; +X} +X +Xint +Xgetlistsize(op) +X object *op; +X{ +X if (!is_listobject(op)) { +X err_badcall(); +X return -1; +X } +X else +X return ((listobject *)op) -> ob_size; +X} +X +Xobject * +Xgetlistitem(op, i) +X object *op; +X int i; +X{ +X if (!is_listobject(op)) { +X err_badcall(); +X return NULL; +X } +X if (i < 0 || i >= ((listobject *)op) -> ob_size) { +X err_setstr(IndexError, "list index out of range"); +X return NULL; +X } +X return ((listobject *)op) -> ob_item[i]; +X} +X +Xint +Xsetlistitem(op, i, newitem) +X register object *op; +X register int i; +X register object *newitem; +X{ +X register object *olditem; +X if (!is_listobject(op)) { +X if (newitem != NULL) +X DECREF(newitem); +X err_badcall(); +X return -1; +X } +X if (i < 0 || i >= ((listobject *)op) -> ob_size) { +X if (newitem != NULL) +X DECREF(newitem); +X err_setstr(IndexError, "list assignment index out of range"); +X return -1; +X } +X olditem = ((listobject *)op) -> ob_item[i]; +X ((listobject *)op) -> ob_item[i] = newitem; +X if (olditem != NULL) +X DECREF(olditem); +X return 0; +X} +X +Xstatic int +Xins1(self, where, v) +X listobject *self; +X int where; +X object *v; +X{ +X int i; +X object **items; +X if (v == NULL) { +X err_badcall(); +X return -1; +X } +X items = self->ob_item; +X RESIZE(items, object *, self->ob_size+1); +X if (items == NULL) { +X err_nomem(); +X return -1; +X } +X if (where < 0) +X where = 0; +X if (where > self->ob_size) +X where = self->ob_size; +X for (i = self->ob_size; --i >= where; ) +X items[i+1] = items[i]; +X INCREF(v); +X items[where] = v; +X self->ob_item = items; +X self->ob_size++; +X return 0; +X} +X +Xint +Xinslistitem(op, where, newitem) +X object *op; +X int where; +X object *newitem; +X{ +X if (!is_listobject(op)) { +X err_badcall(); +X return -1; +X } +X return ins1((listobject *)op, where, newitem); +X} +X +Xint +Xaddlistitem(op, newitem) +X object *op; +X object *newitem; +X{ +X if (!is_listobject(op)) { +X err_badcall(); +X return -1; +X } +X return ins1((listobject *)op, +X (int) ((listobject *)op)->ob_size, newitem); +X} +X +X/* Methods */ +X +Xstatic void +Xlist_dealloc(op) +X listobject *op; +X{ +X int i; +X for (i = 0; i < op->ob_size; i++) { +X if (op->ob_item[i] != NULL) +X DECREF(op->ob_item[i]); +X } +X if (op->ob_item != NULL) +X free((ANY *)op->ob_item); +X free((ANY *)op); +X} +X +Xstatic void +Xlist_print(op, fp, flags) +X listobject *op; +X FILE *fp; +X int flags; +X{ +X int i; +X fprintf(fp, "["); +X for (i = 0; i < op->ob_size && !StopPrint; i++) { +X if (i > 0) { +X fprintf(fp, ", "); +X } +X printobject(op->ob_item[i], fp, flags); +X } +X fprintf(fp, "]"); +X} +X +Xobject * +Xlist_repr(v) +X listobject *v; +X{ +X object *s, *t, *comma; +X int i; +X s = newstringobject("["); +X comma = newstringobject(", "); +X for (i = 0; i < v->ob_size && s != NULL; i++) { +X if (i > 0) +X joinstring(&s, comma); +X t = reprobject(v->ob_item[i]); +X joinstring(&s, t); +X DECREF(t); +X } +X DECREF(comma); +X t = newstringobject("]"); +X joinstring(&s, t); +X DECREF(t); +X return s; +X} +X +Xstatic int +Xlist_compare(v, w) +X listobject *v, *w; +X{ +X int len = (v->ob_size < w->ob_size) ? v->ob_size : w->ob_size; +X int i; +X for (i = 0; i < len; i++) { +X int cmp = cmpobject(v->ob_item[i], w->ob_item[i]); +X if (cmp != 0) +X return cmp; +X } +X return v->ob_size - w->ob_size; +X} +X +Xstatic int +Xlist_length(a) +X listobject *a; +X{ +X return a->ob_size; +X} +X +Xstatic object * +Xlist_item(a, i) +X listobject *a; +X int i; +X{ +X if (i < 0 || i >= a->ob_size) { +X err_setstr(IndexError, "list index out of range"); +X return NULL; +X } +X INCREF(a->ob_item[i]); +X return a->ob_item[i]; +X} +X +Xstatic object * +Xlist_slice(a, ilow, ihigh) +X listobject *a; +X int ilow, ihigh; +X{ +X listobject *np; +X int i; +X if (ilow < 0) +X ilow = 0; +X else if (ilow > a->ob_size) +X ilow = a->ob_size; +X if (ihigh < 0) +X ihigh = 0; +X if (ihigh < ilow) +X ihigh = ilow; +X else if (ihigh > a->ob_size) +X ihigh = a->ob_size; +X np = (listobject *) newlistobject(ihigh - ilow); +X if (np == NULL) +X return NULL; +X for (i = ilow; i < ihigh; i++) { +X object *v = a->ob_item[i]; +X INCREF(v); +X np->ob_item[i - ilow] = v; +X } +X return (object *)np; +X} +X +Xstatic object * +Xlist_concat(a, bb) +X listobject *a; +X object *bb; +X{ +X int size; +X int i; +X listobject *np; +X if (!is_listobject(bb)) { +X err_badarg(); +X return NULL; +X } +X#define b ((listobject *)bb) +X size = a->ob_size + b->ob_size; +X np = (listobject *) newlistobject(size); +X if (np == NULL) { +X return err_nomem(); +X } +X for (i = 0; i < a->ob_size; i++) { +X object *v = a->ob_item[i]; +X INCREF(v); +X np->ob_item[i] = v; +X } +X for (i = 0; i < b->ob_size; i++) { +X object *v = b->ob_item[i]; +X INCREF(v); +X np->ob_item[i + a->ob_size] = v; +X } +X return (object *)np; +X#undef b +X} +X +Xstatic int +Xlist_ass_item(a, i, v) +X listobject *a; +X int i; +X object *v; +X{ +X if (i < 0 || i >= a->ob_size) { +X err_setstr(IndexError, "list assignment index out of range"); +X return -1; +X } +X if (v == NULL) +X return list_ass_slice(a, i, i+1, v); +X INCREF(v); +X DECREF(a->ob_item[i]); +X a->ob_item[i] = v; +X return 0; +X} +X +Xstatic int +Xlist_ass_slice(a, ilow, ihigh, v) +X listobject *a; +X int ilow, ihigh; +X object *v; +X{ +X object **item; +X int n; /* Size of replacement list */ +X int d; /* Change in size */ +X int k; /* Loop index */ +X#define b ((listobject *)v) +X if (v == NULL) +X n = 0; +X else if (is_listobject(v)) +X n = b->ob_size; +X else { +X err_badarg(); +X return -1; +X } +X if (ilow < 0) +X ilow = 0; +X else if (ilow > a->ob_size) +X ilow = a->ob_size; +X if (ihigh < 0) +X ihigh = 0; +X if (ihigh < ilow) +X ihigh = ilow; +X else if (ihigh > a->ob_size) +X ihigh = a->ob_size; +X item = a->ob_item; +X d = n - (ihigh-ilow); +X if (d <= 0) { /* Delete -d items; DECREF ihigh-ilow items */ +X for (k = ilow; k < ihigh; k++) +X DECREF(item[k]); +X if (d < 0) { +X for (/*k = ihigh*/; k < a->ob_size; k++) +X item[k+d] = item[k]; +X a->ob_size += d; +X RESIZE(item, object *, a->ob_size); /* Can't fail */ +X a->ob_item = item; +X } +X } +X else { /* Insert d items; DECREF ihigh-ilow items */ +X RESIZE(item, object *, a->ob_size + d); +X if (item == NULL) { +X err_nomem(); +X return -1; +X } +X for (k = a->ob_size; --k >= ihigh; ) +X item[k+d] = item[k]; +X for (/*k = ihigh-1*/; k >= ilow; --k) +X DECREF(item[k]); +X a->ob_item = item; +X a->ob_size += d; +X } +X for (k = 0; k < n; k++, ilow++) { +X object *w = b->ob_item[k]; +X INCREF(w); +X item[ilow] = w; +X } +X return 0; +X#undef b +X} +X +Xstatic object * +Xins(self, where, v) +X listobject *self; +X int where; +X object *v; +X{ +X if (ins1(self, where, v) != 0) +X return NULL; +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xlistinsert(self, args) +X listobject *self; +X object *args; +X{ +X int i; +X if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2) { +X err_badarg(); +X return NULL; +X } +X if (!getintarg(gettupleitem(args, 0), &i)) +X return NULL; +X return ins(self, i, gettupleitem(args, 1)); +X} +X +Xstatic object * +Xlistappend(self, args) +X listobject *self; +X object *args; +X{ +X return ins(self, (int) self->ob_size, args); +X} +X +Xstatic int +Xcmp(v, w) +X char *v, *w; +X{ +X return cmpobject(* (object **) v, * (object **) w); +X} +X +Xstatic object * +Xlistsort(self, args) +X listobject *self; +X object *args; +X{ +X if (args != NULL) { +X err_badarg(); +X return NULL; +X } +X err_clear(); +X if (self->ob_size > 1) +X qsort((char *)self->ob_item, +X (int) self->ob_size, sizeof(object *), cmp); +X if (err_occurred()) +X return NULL; +X INCREF(None); +X return None; +X} +X +Xint +Xsortlist(v) +X object *v; +X{ +X if (v == NULL || !is_listobject(v)) { +X err_badcall(); +X return -1; +X } +X v = listsort((listobject *)v, (object *)NULL); +X if (v == NULL) +X return -1; +X DECREF(v); +X return 0; +X} +X +Xstatic struct methodlist list_methods[] = { +X {"append", listappend}, +X {"insert", listinsert}, +X {"sort", listsort}, +X {NULL, NULL} /* sentinel */ +X}; +X +Xstatic object * +Xlist_getattr(f, name) +X listobject *f; +X char *name; +X{ +X return findmethod(list_methods, (object *)f, name); +X} +X +Xstatic sequence_methods list_as_sequence = { +X list_length, /*sq_length*/ +X list_concat, /*sq_concat*/ +X 0, /*sq_repeat*/ +X list_item, /*sq_item*/ +X list_slice, /*sq_slice*/ +X list_ass_item, /*sq_ass_item*/ +X list_ass_slice, /*sq_ass_slice*/ +X}; +X +Xtypeobject Listtype = { +X OB_HEAD_INIT(&Typetype) +X 0, +X "list", +X sizeof(listobject), +X 0, +X list_dealloc, /*tp_dealloc*/ +X list_print, /*tp_print*/ +X list_getattr, /*tp_getattr*/ +X 0, /*tp_setattr*/ +X list_compare, /*tp_compare*/ +X list_repr, /*tp_repr*/ +X 0, /*tp_as_number*/ +X &list_as_sequence, /*tp_as_sequence*/ +X 0, /*tp_as_mapping*/ +X}; +EOF +fi +if test -s 'src/parser.c' +then echo '*** I will not over-write existing file src/parser.c' +else +echo 'x - src/parser.c' +sed 's/^X//' > 'src/parser.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Parser implementation */ +X +X/* For a description, see the comments at end of this file */ +X +X/* XXX To do: error recovery */ +X +X#include "pgenheaders.h" +X#include "assert.h" +X#include "token.h" +X#include "grammar.h" +X#include "node.h" +X#include "parser.h" +X#include "errcode.h" +X +X +X#ifdef DEBUG +Xextern int debugging; +X#define D(x) if (!debugging); else x +X#else +X#define D(x) +X#endif +X +X +X/* STACK DATA TYPE */ +X +Xstatic void s_reset PROTO((stack *)); +X +Xstatic void +Xs_reset(s) +X stack *s; +X{ +X s->s_top = &s->s_base[MAXSTACK]; +X} +X +X#define s_empty(s) ((s)->s_top == &(s)->s_base[MAXSTACK]) +X +Xstatic int s_push PROTO((stack *, dfa *, node *)); +X +Xstatic int +Xs_push(s, d, parent) +X register stack *s; +X dfa *d; +X node *parent; +X{ +X register stackentry *top; +X if (s->s_top == s->s_base) { +X fprintf(stderr, "s_push: parser stack overflow\n"); +X return -1; +X } +X top = --s->s_top; +X top->s_dfa = d; +X top->s_parent = parent; +X top->s_state = 0; +X return 0; +X} +X +X#ifdef DEBUG +X +Xstatic void s_pop PROTO((stack *)); +X +Xstatic void +Xs_pop(s) +X register stack *s; +X{ +X if (s_empty(s)) { +X fprintf(stderr, "s_pop: parser stack underflow -- FATAL\n"); +X abort(); +X } +X s->s_top++; +X} +X +X#else /* !DEBUG */ +X +X#define s_pop(s) (s)->s_top++ +X +X#endif +X +X +X/* PARSER CREATION */ +X +Xparser_state * +Xnewparser(g, start) +X grammar *g; +X int start; +X{ +X parser_state *ps; +X +X if (!g->g_accel) +X addaccelerators(g); +X ps = NEW(parser_state, 1); +X if (ps == NULL) +X return NULL; +X ps->p_grammar = g; +X ps->p_tree = newtree(start); +X if (ps->p_tree == NULL) { +X DEL(ps); +X return NULL; +X } +X s_reset(&ps->p_stack); +X (void) s_push(&ps->p_stack, finddfa(g, start), ps->p_tree); +X return ps; +X} +X +Xvoid +Xdelparser(ps) +X parser_state *ps; +X{ +X /* NB If you want to save the parse tree, +X you must set p_tree to NULL before calling delparser! */ +X freetree(ps->p_tree); +X DEL(ps); +X} +X +X +X/* PARSER STACK OPERATIONS */ +X +Xstatic int shift PROTO((stack *, int, char *, int, int)); +X +Xstatic int +Xshift(s, type, str, newstate, lineno) +X register stack *s; +X int type; +X char *str; +X int newstate; +X int lineno; +X{ +X assert(!s_empty(s)); +X if (addchild(s->s_top->s_parent, type, str, lineno) == NULL) { +X fprintf(stderr, "shift: no mem in addchild\n"); +X return -1; +X } +X s->s_top->s_state = newstate; +X return 0; +X} +X +Xstatic int push PROTO((stack *, int, dfa *, int, int)); +X +Xstatic int +Xpush(s, type, d, newstate, lineno) +X register stack *s; +X int type; +X dfa *d; +X int newstate; +X int lineno; +X{ +X register node *n; +X n = s->s_top->s_parent; +X assert(!s_empty(s)); +X if (addchild(n, type, (char *)NULL, lineno) == NULL) { +X fprintf(stderr, "push: no mem in addchild\n"); +X return -1; +X } +X s->s_top->s_state = newstate; +X return s_push(s, d, CHILD(n, NCH(n)-1)); +X} +X +X +X/* PARSER PROPER */ +X +Xstatic int classify PROTO((grammar *, int, char *)); +X +Xstatic int +Xclassify(g, type, str) +X grammar *g; +X register int type; +X char *str; +X{ +X register int n = g->g_ll.ll_nlabels; +X +X if (type == NAME) { +X register char *s = str; +X register label *l = g->g_ll.ll_label; +X register int i; +X for (i = n; i > 0; i--, l++) { +X if (l->lb_type == NAME && l->lb_str != NULL && +X l->lb_str[0] == s[0] && +X strcmp(l->lb_str, s) == 0) { +X D(printf("It's a keyword\n")); +X return n - i; +X } +X } +X } +X +X { +X register label *l = g->g_ll.ll_label; +X register int i; +X for (i = n; i > 0; i--, l++) { +X if (l->lb_type == type && l->lb_str == NULL) { +X D(printf("It's a token we know\n")); +X return n - i; +X } +X } +X } +X +X D(printf("Illegal token\n")); +X return -1; +X} +X +Xint +Xaddtoken(ps, type, str, lineno) +X register parser_state *ps; +X register int type; +X char *str; +X int lineno; +X{ +X register int ilabel; +X +X D(printf("Token %s/'%s' ... ", tok_name[type], str)); +X +X /* Find out which label this token is */ +X ilabel = classify(ps->p_grammar, type, str); +X if (ilabel < 0) +X return E_SYNTAX; +X +X /* Loop until the token is shifted or an error occurred */ +X for (;;) { +X /* Fetch the current dfa and state */ +X register dfa *d = ps->p_stack.s_top->s_dfa; +X register state *s = &d->d_state[ps->p_stack.s_top->s_state]; +X +X D(printf(" DFA '%s', state %d:", +X d->d_name, ps->p_stack.s_top->s_state)); +X +X /* Check accelerator */ +X if (s->s_lower <= ilabel && ilabel < s->s_upper) { +X register int x = s->s_accel[ilabel - s->s_lower]; +X if (x != -1) { +X if (x & (1<<7)) { +X /* Push non-terminal */ +X int nt = (x >> 8) + NT_OFFSET; +X int arrow = x & ((1<<7)-1); +X dfa *d1 = finddfa(ps->p_grammar, nt); +X if (push(&ps->p_stack, nt, d1, +X arrow, lineno) < 0) { +X D(printf(" MemError: push.\n")); +X return E_NOMEM; +X } +X D(printf(" Push ...\n")); +X continue; +X } +X +X /* Shift the token */ +X if (shift(&ps->p_stack, type, str, +X x, lineno) < 0) { +X D(printf(" MemError: shift.\n")); +X return E_NOMEM; +X } +X D(printf(" Shift.\n")); +X /* Pop while we are in an accept-only state */ +X while (s = &d->d_state +X [ps->p_stack.s_top->s_state], +X s->s_accept && s->s_narcs == 1) { +X D(printf(" Direct pop.\n")); +X s_pop(&ps->p_stack); +X if (s_empty(&ps->p_stack)) { +X D(printf(" ACCEPT.\n")); +X return E_DONE; +X } +X d = ps->p_stack.s_top->s_dfa; +X } +X return E_OK; +X } +X } +X +X if (s->s_accept) { +X /* Pop this dfa and try again */ +X s_pop(&ps->p_stack); +X D(printf(" Pop ...\n")); +X if (s_empty(&ps->p_stack)) { +X D(printf(" Error: bottom of stack.\n")); +X return E_SYNTAX; +X } +X continue; +X } +X +X /* Stuck, report syntax error */ +X D(printf(" Error.\n")); +X return E_SYNTAX; +X } +X} +X +X +X#ifdef DEBUG +X +X/* DEBUG OUTPUT */ +X +Xvoid +Xdumptree(g, n) +X grammar *g; +X node *n; +X{ +X int i; +X +X if (n == NULL) +X printf("NIL"); +X else { +X label l; +X l.lb_type = TYPE(n); +X l.lb_str = TYPE(str); +X printf("%s", labelrepr(&l)); +X if (ISNONTERMINAL(TYPE(n))) { +X printf("("); +X for (i = 0; i < NCH(n); i++) { +X if (i > 0) +X printf(","); +X dumptree(g, CHILD(n, i)); +X } +X printf(")"); +X } +X } +X} +X +Xvoid +Xshowtree(g, n) +X grammar *g; +X node *n; +X{ +X int i; +X +X if (n == NULL) +X return; +X if (ISNONTERMINAL(TYPE(n))) { +X for (i = 0; i < NCH(n); i++) +X showtree(g, CHILD(n, i)); +X } +X else if (ISTERMINAL(TYPE(n))) { +X printf("%s", tok_name[TYPE(n)]); +X if (TYPE(n) == NUMBER || TYPE(n) == NAME) +X printf("(%s)", STR(n)); +X printf(" "); +X } +X else +X printf("? "); +X} +X +Xvoid +Xprinttree(ps) +X parser_state *ps; +X{ +X if (debugging) { +X printf("Parse tree:\n"); +X dumptree(ps->p_grammar, ps->p_tree); +X printf("\n"); +X printf("Tokens:\n"); +X showtree(ps->p_grammar, ps->p_tree); +X printf("\n"); +X } +X printf("Listing:\n"); +X listtree(ps->p_tree); +X printf("\n"); +X} +X +X#endif /* DEBUG */ +X +X/* +X +XDescription +X----------- +X +XThe parser's interface is different than usual: the function addtoken() +Xmust be called for each token in the input. This makes it possible to +Xturn it into an incremental parsing system later. The parsing system +Xconstructs a parse tree as it goes. +X +XA parsing rule is represented as a Deterministic Finite-state Automaton +X(DFA). A node in a DFA represents a state of the parser; an arc represents +Xa transition. Transitions are either labeled with terminal symbols or +Xwith non-terminals. When the parser decides to follow an arc labeled +Xwith a non-terminal, it is invoked recursively with the DFA representing +Xthe parsing rule for that as its initial state; when that DFA accepts, +Xthe parser that invoked it continues. The parse tree constructed by the +Xrecursively called parser is inserted as a child in the current parse tree. +X +XThe DFA's can be constructed automatically from a more conventional +Xlanguage description. An extended LL(1) grammar (ELL(1)) is suitable. +XCertain restrictions make the parser's life easier: rules that can produce +Xthe empty string should be outlawed (there are other ways to put loops +Xor optional parts in the language). To avoid the need to construct +XFIRST sets, we can require that all but the last alternative of a rule +X(really: arc going out of a DFA's state) must begin with a terminal +Xsymbol. +X +XAs an example, consider this grammar: +X +Xexpr: term (OP term)* +Xterm: CONSTANT | '(' expr ')' +X +XThe DFA corresponding to the rule for expr is: +X +X------->.---term-->.-------> +X ^ | +X | | +X \----OP----/ +X +XThe parse tree generated for the input a+b is: +X +X(expr: (term: (NAME: a)), (OP: +), (term: (NAME: b))) +X +X*/ +EOF +fi +if test -s 'src/patchlevel.h' +then echo '*** I will not over-write existing file src/patchlevel.h' +else +echo 'x - src/patchlevel.h' +sed 's/^X//' > 'src/patchlevel.h' << 'EOF' +X1 +EOF +fi +if test -s 'src/posixmodule.c' +then echo '*** I will not over-write existing file src/posixmodule.c' +else +echo 'x - src/posixmodule.c' +sed 's/^X//' > 'src/posixmodule.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* POSIX module implementation */ +X +X#include <signal.h> +X#include <string.h> +X#include <setjmp.h> +X#include <sys/types.h> +X#include <sys/stat.h> +X#include <sys/time.h> +X#ifdef SYSV +X#include <dirent.h> +X#define direct dirent +X#else +X#include <sys/dir.h> +X#endif +X +X#include "allobjects.h" +X#include "modsupport.h" +X +Xextern char *strerror PROTO((int)); +X +X#ifdef AMOEBA +X#define NO_LSTAT +X#endif +X +X +X/* Return a dictionary corresponding to the POSIX environment table */ +X +Xextern char **environ; +X +Xstatic object * +Xconvertenviron() +X{ +X object *d; +X char **e; +X d = newdictobject(); +X if (d == NULL) +X return NULL; +X if (environ == NULL) +X return d; +X /* XXX This part ignores errors */ +X for (e = environ; *e != NULL; e++) { +X object *v; +X char *p = strchr(*e, '='); +X if (p == NULL) +X continue; +X v = newstringobject(p+1); +X if (v == NULL) +X continue; +X *p = '\0'; +X (void) dictinsert(d, *e, v); +X *p = '='; +X DECREF(v); +X } +X return d; +X} +X +X +Xstatic object *PosixError; /* Exception posix.error */ +X +X/* Set a POSIX-specific error from errno, and return NULL */ +X +Xstatic object * +Xposix_error() +X{ +X return err_errno(PosixError); +X} +X +X +X/* POSIX generic methods */ +X +Xstatic object * +Xposix_1str(args, func) +X object *args; +X int (*func) FPROTO((const char *)); +X{ +X object *path1; +X if (!getstrarg(args, &path1)) +X return NULL; +X if ((*func)(getstringvalue(path1)) < 0) +X return posix_error(); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xposix_2str(args, func) +X object *args; +X int (*func) FPROTO((const char *, const char *)); +X{ +X object *path1, *path2; +X if (!getstrstrarg(args, &path1, &path2)) +X return NULL; +X if ((*func)(getstringvalue(path1), getstringvalue(path2)) < 0) +X return posix_error(); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xposix_strint(args, func) +X object *args; +X int (*func) FPROTO((const char *, int)); +X{ +X object *path1; +X int i; +X if (!getstrintarg(args, &path1, &i)) +X return NULL; +X if ((*func)(getstringvalue(path1), i) < 0) +X return posix_error(); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xposix_do_stat(self, args, statfunc) +X object *self; +X object *args; +X int (*statfunc) FPROTO((const char *, struct stat *)); +X{ +X struct stat st; +X object *path; +X object *v; +X if (!getstrarg(args, &path)) +X return NULL; +X if ((*statfunc)(getstringvalue(path), &st) != 0) +X return posix_error(); +X v = newtupleobject(10); +X if (v == NULL) +X return NULL; +X#define SET(i, st_member) settupleitem(v, i, newintobject((long)st.st_member)) +X SET(0, st_mode); +X SET(1, st_ino); +X SET(2, st_dev); +X SET(3, st_nlink); +X SET(4, st_uid); +X SET(5, st_gid); +X SET(6, st_size); +X SET(7, st_atime); +X SET(8, st_mtime); +X SET(9, st_ctime); +X#undef SET +X if (err_occurred()) { +X DECREF(v); +X return NULL; +X } +X return v; +X} +X +X +X/* POSIX methods */ +X +Xstatic object * +Xposix_chdir(self, args) +X object *self; +X object *args; +X{ +X extern int chdir PROTO((const char *)); +X return posix_1str(args, chdir); +X} +X +Xstatic object * +Xposix_chmod(self, args) +X object *self; +X object *args; +X{ +X extern int chmod PROTO((const char *, mode_t)); +X return posix_strint(args, chmod); +X} +X +Xstatic object * +Xposix_getcwd(self, args) +X object *self; +X object *args; +X{ +X char buf[1026]; +X extern char *getcwd PROTO((char *, int)); +X if (!getnoarg(args)) +X return NULL; +X if (getcwd(buf, sizeof buf) == NULL) +X return posix_error(); +X return newstringobject(buf); +X} +X +Xstatic object * +Xposix_link(self, args) +X object *self; +X object *args; +X{ +X extern int link PROTO((const char *, const char *)); +X return posix_2str(args, link); +X} +X +Xstatic object * +Xposix_listdir(self, args) +X object *self; +X object *args; +X{ +X object *name, *d, *v; +X DIR *dirp; +X struct direct *ep; +X if (!getstrarg(args, &name)) +X return NULL; +X if ((dirp = opendir(getstringvalue(name))) == NULL) +X return posix_error(); +X if ((d = newlistobject(0)) == NULL) { +X closedir(dirp); +X return NULL; +X } +X while ((ep = readdir(dirp)) != NULL) { +X v = newstringobject(ep->d_name); +X if (v == NULL) { +X DECREF(d); +X d = NULL; +X break; +X } +X if (addlistitem(d, v) != 0) { +X DECREF(v); +X DECREF(d); +X d = NULL; +X break; +X } +X DECREF(v); +X } +X closedir(dirp); +X return d; +X} +X +Xstatic object * +Xposix_mkdir(self, args) +X object *self; +X object *args; +X{ +X extern int mkdir PROTO((const char *, mode_t)); +X return posix_strint(args, mkdir); +X} +X +Xstatic object * +Xposix_rename(self, args) +X object *self; +X object *args; +X{ +X extern int rename PROTO((const char *, const char *)); +X return posix_2str(args, rename); +X} +X +Xstatic object * +Xposix_rmdir(self, args) +X object *self; +X object *args; +X{ +X extern int rmdir PROTO((const char *)); +X return posix_1str(args, rmdir); +X} +X +Xstatic object * +Xposix_stat(self, args) +X object *self; +X object *args; +X{ +X extern int stat PROTO((const char *, struct stat *)); +X return posix_do_stat(self, args, stat); +X} +X +Xstatic object * +Xposix_system(self, args) +X object *self; +X object *args; +X{ +X object *command; +X int sts; +X if (!getstrarg(args, &command)) +X return NULL; +X sts = system(getstringvalue(command)); +X return newintobject((long)sts); +X} +X +Xstatic object * +Xposix_umask(self, args) +X object *self; +X object *args; +X{ +X int i; +X if (!getintarg(args, &i)) +X return NULL; +X i = umask(i); +X if (i < 0) +X return posix_error(); +X return newintobject((long)i); +X} +X +Xstatic object * +Xposix_unlink(self, args) +X object *self; +X object *args; +X{ +X extern int unlink PROTO((const char *)); +X return posix_1str(args, unlink); +X} +X +Xstatic object * +Xposix_utimes(self, args) +X object *self; +X object *args; +X{ +X object *path; +X struct timeval tv[2]; +X if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2) { +X err_badarg(); +X return NULL; +X } +X if (!getstrarg(gettupleitem(args, 0), &path) || +X !getlonglongargs(gettupleitem(args, 1), +X &tv[0].tv_sec, &tv[1].tv_sec)) +X return NULL; +X tv[0].tv_usec = tv[1].tv_usec = 0; +X if (utimes(getstringvalue(path), tv) < 0) +X return posix_error(); +X INCREF(None); +X return None; +X} +X +X +X#ifndef NO_LSTAT +X +Xstatic object * +Xposix_lstat(self, args) +X object *self; +X object *args; +X{ +X extern int lstat PROTO((const char *, struct stat *)); +X return posix_do_stat(self, args, lstat); +X} +X +Xstatic object * +Xposix_readlink(self, args) +X object *self; +X object *args; +X{ +X char buf[1024]; /* XXX Should use MAXPATHLEN */ +X object *path; +X int n; +X if (!getstrarg(args, &path)) +X return NULL; +X n = readlink(getstringvalue(path), buf, sizeof buf); +X if (n < 0) +X return posix_error(); +X return newsizedstringobject(buf, n); +X} +X +Xstatic object * +Xposix_symlink(self, args) +X object *self; +X object *args; +X{ +X extern int symlink PROTO((const char *, const char *)); +X return posix_2str(args, symlink); +X} +X +X#endif /* NO_LSTAT */ +X +X +Xstatic struct methodlist posix_methods[] = { +X {"chdir", posix_chdir}, +X {"chmod", posix_chmod}, +X {"getcwd", posix_getcwd}, +X {"link", posix_link}, +X {"listdir", posix_listdir}, +X {"mkdir", posix_mkdir}, +X {"rename", posix_rename}, +X {"rmdir", posix_rmdir}, +X {"stat", posix_stat}, +X {"system", posix_system}, +X {"umask", posix_umask}, +X {"unlink", posix_unlink}, +X {"utimes", posix_utimes}, +X#ifndef NO_LSTAT +X {"lstat", posix_lstat}, +X {"readlink", posix_readlink}, +X {"symlink", posix_symlink}, +X#endif +X {NULL, NULL} /* Sentinel */ +X}; +X +X +Xvoid +Xinitposix() +X{ +X object *m, *d, *v; +X +X m = initmodule("posix", posix_methods); +X d = getmoduledict(m); +X +X /* Initialize posix.environ dictionary */ +X v = convertenviron(); +X if (v == NULL || dictinsert(d, "environ", v) != 0) +X fatal("can't define posix.environ"); +X DECREF(v); +X +X /* Initialize posix.error exception */ +X PosixError = newstringobject("posix.error"); +X if (PosixError == NULL || dictinsert(d, "error", PosixError) != 0) +X fatal("can't define posix.error"); +X} +EOF +fi +echo 'Part 11 out of 21 of pack.out complete.' +exit 0 diff --git a/shar/python-0.9.1-12-21.shar b/shar/python-0.9.1-12-21.shar new file mode 100644 index 0000000..adb9780 --- /dev/null +++ b/shar/python-0.9.1-12-21.shar @@ -0,0 +1,2833 @@ +: This is a shell archive. +: Extract with 'sh this_file'. +: +: Extract part 01 first since it makes all directories +echo 'Start of pack.out, part 12 out of 21:' +if test -s 'demo/sgi/gl_panel/flying/flying.py' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/flying/flying.py' +else +echo 'x - demo/sgi/gl_panel/flying/flying.py' +sed 's/^X//' > 'demo/sgi/gl_panel/flying/flying.py' << 'EOF' +X#! /ufs/guido/bin/sgi/python +X +Xfrom gl import * +Xfrom objdict import * +Xfrom GL import * +Ximport DEVICE, time +Ximport objectdef, light, panel, material +X +Xdef fixmatact (p) : +X p.diffR.fixact () +X p.diffG.fixact () +X p.diffB.fixact () +X p.specR.fixact () +X p.specG.fixact () +X p.specB.fixact () +X p.shine.fixact () +X +Xdef fixlichtact (p) : +X p.R.fixact () +X p.G.fixact () +X p.B.fixact () +X p.X.fixact () +X p.Y.fixact () +X p.Z.fixact () +X p.local.fixact () +X +Xdef cbsetlight (a) : +X p = a.back +X setlight (p, a.label) +X +Xdef cbsetmaterial (a) : +X p = a.back +X setmaterial (p, a.label) +X +Xmater = [0] +Xlicht = [0] +X +Xdef setmaterial (p, mname) : +X # +X mater [0:1] = [material.materdict [mname]] +X # +X p.diffR.val = mater [0][1] +X p.diffG.val = mater [0][2] +X p.diffB.val = mater [0][3] +X # +X p.specR.val = mater [0][5] +X p.specG.val = mater [0][6] +X p.specB.val = mater [0][7] +X # +X p.shine.val = mater [0][9] / 128.0 +X fixmatact (p) +X +Xdef setlight (p, mname) : +X # +X licht [0:1] = [material.lichtdict [mname]] +X # +X p.R.val = licht [0][1] +X p.G.val = licht [0][2] +X p.B.val = licht [0][3] +X # +X p.X.val = (licht [0][5] + 10.0) / 20.0 +X p.Y.val = (licht [0][6] + 10.0) / 20.0 +X p.Z.val = (licht [0][7] + 10.0) / 20.0 +X # +X p.local.val = licht [0][8] +X # +X fixlichtact (p) +X +Xdef cbmaterial (a) : +X # +X if mater[0] = 0 : return +X # +X p = a.back +X mater [0][5:8] = [p.diffR.val, p.diffG.val, p.diffB.val] +X mater [0][1:4] = [p.specR.val, p.specG.val, p.specB.val] +X mater [0][9:10] = [128.0 * p.shine.val] +X light.bindlight (0) +X +Xdef cblight (a) : +X # +X if licht[0] = 0 : return +X # +X p = a.back +X licht [0][1:4] = [p.R.val, p.G.val, p.B.val] +X licht [0][5:8] = [20.0 * p.X.val - 10.0, 20.0 * p.Y.val - 10.0, 20.0 * p.Z.val - 10.0] +X if p.local.val = 0.0 : +X licht [0][8:9] = [0.0] +X else: +X licht [0][8:9] = [1.0] +X # +X light.bindlight (0) +X +X# +X# initgl : initialize window, pipeline, light, viewing +X# +Xdef initgl () : +X # +X # init window +X # +X foreground () +X keepaspect (1, 1) +X prefposition (100, 500, 100, 500) +X w = winopen ('flying objects') +X keepaspect (1, 1) +X winconstraints () +X # +X # configure pipline +X # +X doublebuffer () +X shademodel (GOURAUD) +X zbuffer (1) +X RGBmode () +X gconfig () +X # +X # init lighting +X # +X light.bindlight (1) +X # +X # set viewing +X # +X lookat (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0) +X # +X +X# +X# drawit : draws the object with the given attributes. +X# +X# rfac : the rotation factor. +X# mat : the material identification +X# attr : a list of attributes : +X# +X# [[rotate vector ], [tranlate vector], [scale vector]] +X# i.e : +X# [[rX, rY, rZ], [tX, tY, tZ], [sX, sY, sZ]] +X# +Xdef drawit(object, rfac, attr, mat) : +X pushmatrix() +X rot (attr[0][0] * float (rfac), 'X') +X rot (attr[0][1] * float (rfac), 'Y') +X rot (attr[0][2] * float (rfac), 'Z') +X translate(attr[1][0], attr[1][1], attr[1][2]) +X scale(attr[2][0], attr[2][1], attr[2][2]) +X lmbind(MATERIAL, mat) +X objectdef.drawobject(object) +X popmatrix() +X +Xdef callbacksphere (a) : +X putDict (objects, 'sphere', int (a.val)) +X +Xdef callbackcylinder (a) : +X putDict (objects, 'cylinder', int (a.val)) +X +Xdef callbackcube (a) : +X putDict (objects, 'cube', int (a.val)) +X +Xdef callbackicecream (a) : +X putDict (objects, 'icecream', int (a.val)) +X +Xdef callbackdisk (a) : +X putDict (objects, 'disk', int (a.val)) +X +Xdef callbackdiamond (a) : +X putDict (objects, 'diamond', int (a.val)) +X +Xdef callbackglass (a) : +X putDict (objects, 'glass', int (a.val)) +X +Xdef callbackpyramid (a) : +X putDict (objects, 'pyramid', int (a.val)) +X +Xdef callbacktable (a) : +X putDict (objects, 'table', int (a.val)) +X +Xdef callbackflat (a) : +X shademodel(FLAT) +X +Xdef callbackgouraud (a) : +X shademodel(GOURAUD) +X +Xdef callbackwire (a) : +X objectdef.putFunc ([bgnclosedline, endclosedline]) +X +Xdef callbackfilled (a) : +X objectdef.putFunc ([bgnpolygon, endpolygon]) +X +Xdef callbackquit (a) : +X import sys +X sys.exit (-1) +X +Xdef allObjects(p, val) : +X p.sphere.val = val +X p.sphere.fixact () +X p.cube.val = val +X p.cube.fixact () +X p.cylinder.val = val +X p.cylinder.fixact () +X p.pyramid.val = val +X p.pyramid.fixact () +X p.disk.val = val +X p.disk.fixact () +X p.diamond.val = val +X p.diamond.fixact () +X p.icecream.val = val +X p.icecream.fixact () +X p.table.val = val +X p.table.fixact () +X p.fixpanel() +X +X +Xdef callbackshowall (a) : +X #print objects +X for key in objects.keys () : +X #print key +X putDict (objects, key, 1) +X allObjects (a.back, 1.0) +X +Xdef callbackshownone (a) : +X for key in objects.keys () : +X putDict (objects, key, 0) +X allObjects (a.back, 0.0) +X +X# +X# main : makeobjects, initialze graphics, and loop continuously. +X# +Xdef main () : +X # +X # iter keeps track of the iterations. It is used as the +X # (x, y, z) rotation increments to which the objects rotate. +X iter = 0 +X # +X # make the objects. the objects are put in the odict dictionary +X # +X od = objectdef.makeobjects () +X # +X # initialize gl +X # +X initgl () +X # +X # initialize time and iterations per second +X # +X time0 = time.time () # epoch-time of previous second +X fps = 0 # frames per second +X # +X # initialize panels +X # +X panel.needredraw() +X panels = panel.defpanellist('flying.s') #XXX +X p = panels[0] +X p.sphere.upfunc = callbacksphere +X p.cylinder.upfunc = callbackcylinder +X p.cube.upfunc = callbackcube +X p.icecream.upfunc = callbackicecream +X p.disk.upfunc = callbackdisk +X p.diamond.upfunc = callbackdiamond +X # NOT YET IMPLEMENTED p.glass.upfunc = callbackglass +X p.pyramid.upfunc = callbackpyramid +X p.table.upfunc = callbacktable +X p.wire.upfunc = callbackwire +X p.filled.upfunc = callbackfilled +X p.flat.upfunc = callbackflat +X p.gouraud.upfunc = callbackgouraud +X p.quit.upfunc = callbackquit +X p.showall.upfunc = callbackshowall +X p.shownone.upfunc = callbackshownone +X p.showall.back = p +X p.shownone.back = p +X # +X qanels = panel.defpanellist('freeze.s') #XXX +X q = qanels[0] +X # +X ranels = panel.defpanellist('materials.s') #XXX +X r = ranels[0] +X r.m9.upfunc = cbsetmaterial +X r.m8.upfunc = cbsetmaterial +X r.m7.upfunc = cbsetmaterial +X r.m6.upfunc = cbsetmaterial +X r.m5.upfunc = cbsetmaterial +X r.m4.upfunc = cbsetmaterial +X r.m3.upfunc = cbsetmaterial +X r.m2.upfunc = cbsetmaterial +X r.m1.upfunc = cbsetmaterial +X r.specR.activefunc = cbmaterial +X r.specG.activefunc = cbmaterial +X r.specB.activefunc = cbmaterial +X r.diffR.activefunc = cbmaterial +X r.diffG.activefunc = cbmaterial +X r.diffB.activefunc = cbmaterial +X r.shine.activefunc = cbmaterial +X r.m9.back = r +X r.m8.back = r +X r.m7.back = r +X r.m6.back = r +X r.m5.back = r +X r.m4.back = r +X r.m3.back = r +X r.m2.back = r +X r.m1.back = r +X r.diffR.back = r +X r.diffG.back = r +X r.diffB.back = r +X r.specR.back = r +X r.specG.back = r +X r.specB.back = r +X r.shine.back = r +X # +X sanels = panel.defpanellist('light.s') #XXX +X s = sanels[0] +X s.X.back = s +X s.Y.back = s +X s.Z.back = s +X s.R.back = s +X s.G.back = s +X s.B.back = s +X s.light1.back = s +X s.light2.back = s +X s.local.back = s +X s.light1.upfunc = cbsetlight +X s.light2.upfunc = cbsetlight +X s.R.activefunc = cblight +X s.G.activefunc = cblight +X s.B.activefunc = cblight +X s.X.activefunc = cblight +X s.Y.activefunc = cblight +X s.Z.activefunc = cblight +X # +X while 1 : +X # +X act = panel.dopanel() +X # +X wid = panel.userredraw () +X if wid : +X winset (wid) +X reshapeviewport() +X # +X # increment iter +X # +X if int (q.freeze.val) = 0 : +X iter = iter + 1 +X fps = fps + 1 +X if time.time() - time0 >= 1 : +X f = float(fps)/float(time.time()-time0) +X q.mystrip.val = f +X q.mystrip.fixact () +X q.fixpanel() +X time0 = time.time() +X fps = 0 +X # +X # clear the zbuffer and make the background light blue +X # +X zclear() +X c3i (LightBlue) +X clear() +X # +X # for each object in the objects dictionary +X # +X for key in objects.keys() : +X # +X # if the object should be displayed +X # +X if getDict (objects, key, 0) = ONE : +X loo = getDict (objects, key, 1) +X for o in loo : +X # +X # get attributes and materail +X # +X attr = o [1] +X mat = o [2] +X # +X # display the object +X # +X drawit(od[o[0]],iter,attr,mat) +X # +X swapbuffers() +X # +X +Xmain() +EOF +chmod +x 'demo/sgi/gl_panel/flying/flying.py' +fi +if test -s 'lib/adv.py' +then echo '*** I will not over-write existing file lib/adv.py' +else +echo 'x - lib/adv.py' +sed 's/^X//' > 'lib/adv.py' << 'EOF' +X#! /ufs/guido/bin/sgi/python +X +X# Module 'adv' -- text-oriented adventure game. +X +X +X# Name a constant that may once appear in the language... +X +Xdef return_nil(): return +Xnil = return_nil() +X +X +X# Copy of string.split() (to avoid loading all of string.py) +X +Xwhitespace = ' \t\n' +Xdef split(s): +X res = [] +X i, n = 0, len(s) +X while i < n: +X while i < n and s[i] in whitespace: i = i+1 +X if i = n: break +X j = i +X while j < n and s[j] not in whitespace: j = j+1 +X res.append(s[i:j]) +X i = j +X return res +X +X +X# Constants to name directions +X +XN = 'north' +XS = 'south' +XW = 'west' +XE = 'east' +XU = 'up' +XD = 'down' +XNW = 'nw' +XNE = 'ne' +XSW = 'sw' +XSE = 'se' +X +X +X# Constants to name other commands +X +XINVENT = 'invent' +XLOOK = 'look' +XBACK = 'back' +XHELP = 'help' +XGET = 'get' +XPUT = 'put' +X +X +X# Aliases recognized by the parser +X +Xalias = {} +Xalias['n'] = N +Xalias['s'] = S +Xalias['e'] = E +Xalias['w'] = W +Xalias['u'] = U +Xalias['d'] = D +Xalias['i'] = INVENT +Xalias['l'] = LOOK +Xalias['b'] = BACK +Xalias['take'] = GET +Xalias['drop'] = PUT +X +X +X# Normalize a command, in place: truncate words to 6 chars, and expand aliases. +X +Xdef normalize(cmd): +X for i in range(len(cmd)): +X word = cmd[i][:6] +X if alias.has_key(word): +X word = alias[word] +X cmd[i] = word +X +X +X# The Object class describes objects that the player can carry around. +X +Xclass Object(): +X def init(this, name): +X this.name = name +X return this +X def describe(this): +X print 'A', this.name + '.' +X def get(this, (player, room)): +X del room.objects[this.name] +X player.objects[this.name] = this +X def put(this, (player, room)): +X del player.objects[this.name] +X room.objects[this.name] = this +X +X +X# The Player class embodies first person control. +X +Xclass Player(): +X # Set initial state, except current room. +X def init(self, initial_room): +X self.blind = 0 +X self.here = initial_room +X self.prev = nil +X self.objects = {} +X return self +X # Read and execute commands forever. +X def play(self): +X self.here.casualdescribe() +X while 1: +X self.move() +X # Read and execute one command. +X def move(self): +X next = self.here.parser() +X if next and next <> self.here: +X self.prev = self.here +X self.here = next +X if not self.blind: +X self.here.casualdescribe() +X # Print inventory. +X def inventory(self): +X if not self.objects: +X print 'You aren\'t carrying anything.' +X return +X print 'You are carrying:' +X for key in self.objects.keys(): +X self.objects[key].describe() +X # Go back to previous room. +X def back(self): +X if self.prev: return self.prev +X print 'You can\'t go back now.' +X # Get an object from the room. +X def get(self, name): +X if self.here.objects.has_key(name): +X self.here.objects[name].get(self, self.here) +X else: +X print 'I see no', name, 'here.' +X # Put an object in the room. +X def put(self, name): +X if self.objects.has_key(name): +X self.objects[name].put(self, self.here) +X else: +X print 'You have no', name, 'with you.' +X +X +X# The Room class describes a generic room. +X# Rooms with special properties are defined by derived classes +X# that override certain operations. +X +Xclass Room(): +X # Initialize a featureless room. +X def init(here, name): +X here.seen = 0 +X here.name = name +X here.exits = {} +X here.objects = {} +X here.description = [] +X return here +X # Add an object to the room. Used during initialization. +X def add(here, obj): +X here.objects[obj.name] = obj +X # Print a casual description. +X def casualdescribe(here): +X if here.seen: +X print here.name + '.' +X here.listobjects() +X return +X here.seen = 1 +X here.describe() +X # Print a full description, including all exits and objects seen. +X def describe(here): +X if not here.description: +X print here.name + '.' +X here.listexits() +X else: +X for line in here.description: print line +X here.listobjects() +X # List exits. +X def listexits(here): +X there = here.exits.keys() +X if there: +X if len(there) = 1: +X print 'There is an exit leading', +X else: +X print 'There are exits leading', +X for name in there[:-2]: +X print name + ',', +X print there[len(there)-2], 'and', +X print there[len(there)-1] + '.' +X # List objects +X def listobjects(here): +X if here.objects: +X print 'I see:' +X for key in here.objects.keys(): +X here.objects[key].describe() +X # Default parser. Returns next room (possibly the same) or nil. +X def parser(here): +X cmd = here.getcmd(here.prompt()) +X return here.decide(cmd) +X # Return default prompt string. +X def prompt(here): return '> ' +X # Default input routine. Returns a non-empty list of words. +X def getcmd(here, prompt): +X # Loop until non-empty command gotten +X # EOFError and KeyboardInterrupt may be caught elsewhere +X while 1: +X line = raw_input(prompt) +X cmd = split(line) +X if cmd: +X normalize(cmd) +X return cmd +X # Default decision routine. Override for room-specific commands. +X def decide(here, cmd): +X key, args = cmd[0], cmd[1:] +X if not args: +X if key = N: return here.north() +X if key = S: return here.south() +X if key = E: return here.east() +X if key = W: return here.west() +X if key = U: return here.up() +X if key = D: return here.down() +X if key = NW: return here.nw() +X if key = NE: return here.ne() +X if key = SW: return here.sw() +X if key = SE: return here.se() +X if key = LOOK: return here.look() +X if key = INVENT: return here.inventory() +X if key = BACK: return here.back() +X if here.objects.has_key(key): +X print 'What do you want to do with the', key+'?' +X else: +X print 'Huh?' +X return +X if key = GET: +X for arg in args: +X player.get(arg) +X return +X if key = PUT: +X for arg in args: +X player.put(arg) +X # Standard commands. +X def look(here): +X here.describe() +X def inventory(here): +X player.inventory() +X def back(here): +X return player.back() +X # Standard exits. +X def north(here): return here.take_exit(N) +X def south(here): return here.take_exit(S) +X def west(here): return here.take_exit(W) +X def east(here): return here.take_exit(E) +X def up(here): return here.take_exit(U) +X def down(here): return here.take_exit(D) +X def nw(here): return here.take_exit(NW) +X def ne(here): return here.take_exit(NE) +X def sw(here): return here.take_exit(SW) +X def se(here): return here.take_exit(SE) +X # Subroutine for standard exits. +X def take_exit(here, key): +X if here.exits.has_key(key): +X return here.exits[key] +X print 'You cannot go in that direction.' +X return here +X +X +X# Create the objects we know about. +X# Object names begin with 'o_'. +X +Xo_lamp = Object().init('lamp') +Xo_python = Object().init('python') +X +X +X# Subroutine to connect two rooms. +X +Xdef connect(rm1, rm2, dir1, dir2): +X if dir1: +X rm1.exits[dir1] = rm2 +X if dir2: +X rm2.exits[dir2] = rm1 +X +X +X# Create the rooms and connect them together. +X# Room names begin with 'r_'. +X +Xr_front = Room().init('Front of building') +Xr_initial = r_front +Xr_front.description = [ \ +X 'You are standing in front of a large, desolate building.', \ +X 'Huge neon letters spell "CWI". The "I" is blinking.', \ +X 'There are entrances north and west from where you are standing.', \ +X ] +X +Xr_entrance = Room().init('Entrance') +Xr_entrance.description = [ \ +X 'You are standing in a small entrance room.', \ +X 'On the east side is a window to a reception room.', \ +X 'South is a door leading outside the building.', \ +X 'North is a large hall.' \ +X ] +X +Xr_hall_s = Room().init('South of hall') +Xr_hall_s.description = [ \ +X 'You are standing at the south side of a very large hall.', \ +X 'There are doors leading west, southwest, south and southeast,', \ +X 'and a corridor leads east.', \ +X 'The hall continues to the north.' \ +X ] +X +Xr_hall_n = Room().init('North of hall') +Xr_hall_n.description = [ \ +X 'You are stanting at the north side of a very large hall.', \ +X 'There are corridors leading west, northwest, northeast,', \ +X 'an elevator door north, and a door leading outside east.', \ +X 'There are stairs leading up, and the hall continues to the south.' \ +X ] +X +Xr_reception = Room().init('Reception') +X +Xr_mail = Room().init('Mail room') +X +Xconnect(r_front, r_entrance, N, S) +Xconnect(r_entrance, r_hall_s, N, SW) +Xconnect(r_hall_s, r_hall_n, N, S) +Xconnect(r_hall_s, r_reception, S, N) +Xconnect(r_hall_s, r_mail, SE, N) +Xconnect(r_reception, r_mail, E, W) +X +Xr_aud_front = Room().init('Front of Auditorium') +Xr_aud_back = Room().init('Back of Auditorium') +Xr_aud_tech = Room().init('Technician\'s room in Auditorium') +Xr_aud_proj = Room().init('Projection room in Auditorium') +X +Xconnect(r_aud_front, r_hall_s, E, W) +Xconnect(r_aud_front, r_aud_back, S, N) +Xconnect(r_aud_back, r_aud_proj, SE, N) +Xconnect(r_aud_front, r_aud_tech, W, E) +X +Xr_floor1 = Room().init('First floor') +Xr_floor2 = Room().init('Second floor') +Xr_floor3 = Room().init('Third floor') +X +Xconnect(r_hall_n, r_floor1, U, D) +Xconnect(r_floor1, r_floor2, U, D) +Xconnect(r_floor2, r_floor3, U, D) +X +X +X# Drop objects here and there +X +Xr_aud_proj.add(o_python) +Xr_reception.add(o_lamp) +X +X# Create an uninitialized player object. +X# It is initialized by main(), but must be created here (as global) +X# since some Room methods reference it. (Though maybe they shouldn't?) +X +Xplayer = Player() +X +X +X# Play the game from the beginning. +X +Xdef main(): +X x = player.init(r_initial) +X try: +X player.play() +X except (EOFError, KeyboardInterrupt): +X pass +X +Xmain() +EOF +fi +if test -s 'lib/cmpcache.py' +then echo '*** I will not over-write existing file lib/cmpcache.py' +else +echo 'x - lib/cmpcache.py' +sed 's/^X//' > 'lib/cmpcache.py' << 'EOF' +X# Module 'cmpcache' +X# +X# Efficiently compare files, boolean outcome only (equal / not equal). +X# +X# Tricks (used in this order): +X# - Use the statcache module to avoid statting files more than once +X# - Files with identical type, size & mtime are assumed to be clones +X# - Files with different type or size cannot be identical +X# - We keep a cache of outcomes of earlier comparisons +X# - We don't fork a process to run 'cmp' but read the files ourselves +X +Ximport posix +Xfrom stat import * +Ximport statcache +X +X +X# The cache. +X# +Xcache = {} +X +X +X# Compare two files, use the cache if possible. +X# May raise posix.error if a stat or open of either fails. +X# +Xdef cmp(f1, f2): +X # Return 1 for identical files, 0 for different. +X # Raise exceptions if either file could not be statted, read, etc. +X s1, s2 = sig(statcache.stat(f1)), sig(statcache.stat(f2)) +X if not S_ISREG(s1[0]) or not S_ISREG(s2[0]): +X # Either is a not a plain file -- always report as different +X return 0 +X if s1 = s2: +X # type, size & mtime match -- report same +X return 1 +X if s1[:2] <> s2[:2]: # Types or sizes differ, don't bother +X # types or sizes differ -- report different +X return 0 +X # same type and size -- look in the cache +X key = f1 + ' ' + f2 +X if cache.has_key(key): +X cs1, cs2, outcome = cache[key] +X # cache hit +X if s1 = cs1 and s2 = cs2: +X # cached signatures match +X return outcome +X # stale cached signature(s) +X # really compare +X outcome = do_cmp(f1, f2) +X cache[key] = s1, s2, outcome +X return outcome +X +X# Return signature (i.e., type, size, mtime) from raw stat data. +X# +Xdef sig(st): +X return S_IFMT(st[ST_MODE]), st[ST_SIZE], st[ST_MTIME] +X +X# Compare two files, really. +X# +Xdef do_cmp(f1, f2): +X #print ' cmp', f1, f2 # XXX remove when debugged +X bufsize = 8096 # Could be tuned +X fp1 = open(f1, 'r') +X fp2 = open(f2, 'r') +X while 1: +X b1 = fp1.read(bufsize) +X b2 = fp2.read(bufsize) +X if b1 <> b2: return 0 +X if not b1: return 1 +EOF +fi +if test -s 'lib/macshell.py' +then echo '*** I will not over-write existing file lib/macshell.py' +else +echo 'x - lib/macshell.py' +sed 's/^X//' > 'lib/macshell.py' << 'EOF' +X# Macintosh 'shell' +X# vi:set tabsize=4: +X +X# XXX string quoting in arguments +X# XXX directory stack +X# XXX $macros? +X# XXX ^C during any command +X# XXX 'sh' builtin command? +X# XXX why does open require absolute path? (need to fix chdir.c) +X +X +Ximport mac +X +Ximport macpath +Ximport string +Ximport glob +Xfrom macpath import isfile, isdir, exists +Ximport TclUtil # For splitting/quoting mechanisms +X +Xclass Struct(): pass +XG = Struct() +X +Xdef reset(): +X G.debug = 0 +X G.ps1 = '$ ' +X G.homedir = mac.getcwd() +X G.commands = mkcmdtab() +X G.aliases = {} +X +Xdef mkcmdtab(): +X tab = {} +X tab['alias'] = do_alias +X tab['cd'] = do_cd +X tab['debug'] = do_debug +X tab['grep'] = do_grep +X tab['help'] = do_help +X tab['ls'] = do_ls +X tab['mkdir'] = do_mkdir +X tab['mv'] = do_mv +X tab['page'] = do_page +X tab['pwd'] = do_pwd +X tab['reset'] = do_reset +X tab['rm'] = do_rm +X tab['rmdir'] = do_rmdir +X tab['sync'] = do_sync +X tab['unalias'] = do_unalias +X return tab +X +Xdef main(): +X while 1: +X try: +X line = raw_input(G.ps1) +X except EOFError: +X print '[EOF]' +X break +X except KeyboardInterrupt: +X print '[Intr]' +X line = '' +X if G.debug: +X print 'line:', `line` +X words = TclUtil.SplitList(line) +X if G.debug: +X print 'words:', words +X if words and words[0][0] <> '#': +X run(words) +X +Xdef run(words): +X expandaliases(words) +X cmd = words[0] +X args = words[1:] +X if G.commands.has_key(cmd): +X if args: +X try: +X args = expandgloblist(args) +X except glob_error, msg: +X print cmd, ': glob error :', msg +X return +X G.commands[cmd](args) +X return +X if hasglobchar(cmd): +X if args: +X print cmd, ': cannot glob pattern with arguments' +X return +X try: +X words = expandglobword(cmd) +X except glob_error, msg: +X print cmd, ': glob error :', msg +X return +X if len(words) > 1: +X columnize(words) +X return +X cmd = words[0] +X print cmd +X if isfile(cmd): +X if args: +X print cmd, ': file command expects no arguments' +X return +X do_page([cmd]) +X elif isdir(cmd): +X if args: +X print cmd, ': directory command expects no arguments' +X return +X do_cd([cmd]) +X else: +X print cmd, ': no such command, file or directory' +X +Xglob_error = 'glob error' +X +Xdef expandgloblist(words): +X res = [] +X for word in words: +X if hasglobchar(word): +X res = res + expandglobword(word) +X else: +X res.append(word) +X return res +X +Xdef expandglobword(word): +X names = glob.globlist(mac.listdir(':'), word) +X if not names: raise glob_error, 'no match for pattern ' + word +X return names +X +Xdef hasglobchar(word): +X return '*' in word or '?' in word +X +Xdef expandaliases(words): +X seen = [] +X cmd = words[0] +X while cmd not in seen and G.aliases.has_key(cmd): +X seen.append(cmd) +X words[:1] = G.aliases[cmd] +X cmd = words[0] +X +Xdef do_alias(args): +X if not args: +X listaliases() +X elif len(args) = 1: +X listalias(args[0]) +X else: +X defalias(args[0], args[1:]) +X +Xdef listaliases(): +X names = G.aliases.keys() +X names.sort() +X for name in names: listalias(name) +X +Xdef listalias(name): +X if not G.aliases.has_key(name): +X print name, ': no such alias' +X return +X print 'alias', name, +X printlist(G.aliases[name]) +X print +X +Xdef defalias(name, expansion): +X G.aliases[name] = expansion +X +Xdef do_cd(args): +X if len(args) > 1: +X print 'usage: cd [dirname]' +X elif args: +X chdirto(args[0]) +X else: +X chdirto(G.homedir) +X +Xdef chdirto(dirname): +X try: +X mac.chdir(dirname) +X except mac.error, msg: +X print dirname, ':', msg +X return +X +Xdef do_debug(args): +X G.debug = (not G.debug) +X +Xdef do_grep(args): +X if len(args) < 2: +X print 'usage: grep regexp file ...' +X return +X import regexp +X try: +X prog = regexp.compile(args[0]) +X except regexp.error, msg: +X print 'regexp.compile error for', args[0], ':', msg +X return +X for file in args[1:]: +X grepfile(prog, file) +X +Xdef grepfile(prog, file): +X try: +X fp = open(file, 'r') +X except RuntimeError, msg: +X print file, ': cannot open :', msg +X return +X lineno = 0 +X while 1: +X line = fp.readline() +X if not line: break +X lineno = lineno+1 +X if prog.exec(line): +X print file+'('+`lineno`+'):', line, +X +Xdef do_help(args): +X if args: +X print 'usage: help' +X return +X names = G.commands.keys() +X names.sort() +X columnize(names) +X +Xdef do_ls(args): +X if not args: +X lsdir(':') +X else: +X for dirname in args: +X lsdir(dirname) +X +Xdef lsdir(dirname): +X if not isdir(dirname): +X print dirname, ': no such directory' +X return +X names = mac.listdir(dirname) +X lsfiles(names, dirname) +X +Xdef lsfiles(names, dirname): +X names = names[:] # Make a copy so we can modify it +X for i in range(len(names)): +X name = names[i] +X if G.debug: print i, name +X if isdir(macpath.cat(dirname, name)): +X names[i] = ':' + name + ':' +X columnize(names) +X +Xdef columnize(list): +X COLUMNS = 80-1 +X n = len(list) +X colwidth = maxwidth(list) +X ncols = (COLUMNS + 1) / (colwidth + 1) +X if ncols < 1: ncols = 1 +X nrows = (n + ncols - 1) / ncols +X for irow in range(nrows): +X line = '' +X for icol in range(ncols): +X i = irow + nrows*icol +X if 0 <= i < n: +X word = list[i] +X if i+nrows < n: +X word = string.ljust(word, colwidth) +X if icol > 0: +X word = ' ' + word +X line = line + word +X print line +X +Xdef maxwidth(list): +X width = 0 +X for word in list: +X if len(word) > width: +X width = len(word) +X return width +X +Xdef do_mv(args): +X if len(args) <> 2: +X print 'usage: mv src dst' +X return +X src, dst = args[0], args[1] +X if not exists(src): +X print src, ': source does not exist' +X return +X if exists(dst): +X print src, ': destination already exists' +X return +X try: +X mac.rename(src, dst) +X except mac.error, msg: +X print src, dst, ': rename failed:', msg +X +Xdef do_mkdir(args): +X if not args: +X print 'usage: mkdir name ...' +X return +X for name in args: +X makedir(name) +X +Xdef makedir(name): +X if exists(name): +X print name, ': already exists' +X return +X try: +X mac.mkdir(name, 0777) +X except mac.error, msg: +X print name, ': mkdir failed:', msg +X +Xdef do_page(args): +X if not args: +X print 'usage: page file ...' +X return +X for name in args: +X pagefile(name) +X +Xdef pagefile(name): +X if not isfile(name): +X print name, ': no such file' +X return +X LINES = 24 - 1 +X # For THINK C 3.0, make the path absolute: +X # if not macpath.isabs(name): +X # name = macpath.cat(mac.getcwd(), name) +X try: +X fp = open(name, 'r') +X except: +X print name, ': cannot open' +X return +X line = fp.readline() +X while line: +X for i in range(LINES): +X print line, +X line = fp.readline() +X if not line: break +X if line: +X try: +X more = raw_input('[more]') +X except (EOFError, KeyboardInterrupt): +X print +X break +X if string.strip(more)[:1] in ('q', 'Q'): +X break +X +Xdef do_pwd(args): +X if args: +X print 'usage: pwd' +X else: +X print mac.getcwd() +X +Xdef do_reset(args): +X if args: +X print 'usage: reset' +X else: +X reset() +X +Xdef do_rm(args): +X if not args: +X print 'usage: rm file ...' +X return +X for name in args: +X remove(name) +X +Xdef remove(name): +X if not isfile(name): +X print name, ': no such file' +X return +X try: +X mac.unlink(name) +X except mac.error, msg: +X print name, ': unlink failed:', msg +X +Xdef do_rmdir(args): +X if not args: +X print 'usage: rmdir dir ...' +X return +X for name in args: +X rmdir(name) +X +Xdef rmdir(name): +X if not isdir(name): +X print name, ': no such directory' +X return +X try: +X mac.rmdir(name) +X except mac.error, msg: +X print name, ': rmdir failed:', msg +X +Xdef do_sync(args): +X if args: +X print 'usage: sync' +X return +X try: +X mac.sync() +X except mac.error, msg: +X print 'sync failed:', msg +X +Xdef do_unalias(args): +X if not args: +X print 'usage: unalias name ...' +X return +X for name in args: +X unalias(name) +X +Xdef unalias(name): +X if not G.aliases.has_key(name): +X print name, ': no such alias' +X return +X del G.aliases[name] +X +Xdef printlist(list): +X for word in list: +X print word, +X +Xreset() +Xmain() +EOF +fi +if test -s 'src/cgensupport.c' +then echo '*** I will not over-write existing file src/cgensupport.c' +else +echo 'x - src/cgensupport.c' +sed 's/^X//' > 'src/cgensupport.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Functions used by cgen output */ +X +X#include <stdio.h> +X +X#include "PROTO.h" +X#include "object.h" +X#include "intobject.h" +X#include "floatobject.h" +X#include "stringobject.h" +X#include "tupleobject.h" +X#include "listobject.h" +X#include "methodobject.h" +X#include "moduleobject.h" +X#include "modsupport.h" +X#include "import.h" +X#include "cgensupport.h" +X#include "errors.h" +X +X +X/* Functions to construct return values */ +X +Xobject * +Xmknewcharobject(c) +X int c; +X{ +X char ch[1]; +X ch[0] = c; +X return newsizedstringobject(ch, 1); +X} +X +X/* Functions to extract arguments. +X These needs to know the total number of arguments supplied, +X since the argument list is a tuple only of there is more than +X one argument. */ +X +Xint +Xgetiobjectarg(args, nargs, i, p_arg) +X register object *args; +X int nargs, i; +X object **p_arg; +X{ +X if (nargs != 1) { +X if (args == NULL || !is_tupleobject(args) || +X nargs != gettuplesize(args) || +X i < 0 || i >= nargs) { +X return err_badarg(); +X } +X else { +X args = gettupleitem(args, i); +X } +X } +X if (args == NULL) { +X return err_badarg(); +X } +X *p_arg = args; +X return 1; +X} +X +Xint +Xgetilongarg(args, nargs, i, p_arg) +X register object *args; +X int nargs, i; +X long *p_arg; +X{ +X if (nargs != 1) { +X if (args == NULL || !is_tupleobject(args) || +X nargs != gettuplesize(args) || +X i < 0 || i >= nargs) { +X return err_badarg(); +X } +X args = gettupleitem(args, i); +X } +X if (args == NULL || !is_intobject(args)) { +X return err_badarg(); +X } +X *p_arg = getintvalue(args); +X return 1; +X} +X +Xint +Xgetishortarg(args, nargs, i, p_arg) +X register object *args; +X int nargs, i; +X short *p_arg; +X{ +X long x; +X if (!getilongarg(args, nargs, i, &x)) +X return 0; +X *p_arg = x; +X return 1; +X} +X +Xstatic int +Xextractdouble(v, p_arg) +X register object *v; +X double *p_arg; +X{ +X if (v == NULL) { +X /* Fall through to error return at end of function */ +X } +X else if (is_floatobject(v)) { +X *p_arg = GETFLOATVALUE((floatobject *)v); +X return 1; +X } +X else if (is_intobject(v)) { +X *p_arg = GETINTVALUE((intobject *)v); +X return 1; +X } +X return err_badarg(); +X} +X +Xstatic int +Xextractfloat(v, p_arg) +X register object *v; +X float *p_arg; +X{ +X if (v == NULL) { +X /* Fall through to error return at end of function */ +X } +X else if (is_floatobject(v)) { +X *p_arg = GETFLOATVALUE((floatobject *)v); +X return 1; +X } +X else if (is_intobject(v)) { +X *p_arg = GETINTVALUE((intobject *)v); +X return 1; +X } +X return err_badarg(); +X} +X +Xint +Xgetifloatarg(args, nargs, i, p_arg) +X register object *args; +X int nargs, i; +X float *p_arg; +X{ +X object *v; +X float x; +X if (!getiobjectarg(args, nargs, i, &v)) +X return 0; +X if (!extractfloat(v, &x)) +X return 0; +X *p_arg = x; +X return 1; +X} +X +Xint +Xgetistringarg(args, nargs, i, p_arg) +X object *args; +X int nargs, i; +X string *p_arg; +X{ +X object *v; +X if (!getiobjectarg(args, nargs, i, &v)) +X return NULL; +X if (!is_stringobject(v)) { +X return err_badarg(); +X } +X *p_arg = getstringvalue(v); +X return 1; +X} +X +Xint +Xgetichararg(args, nargs, i, p_arg) +X object *args; +X int nargs, i; +X char *p_arg; +X{ +X string x; +X if (!getistringarg(args, nargs, i, &x)) +X return 0; +X if (x[0] == '\0' || x[1] != '\0') { +X /* Not exactly one char */ +X return err_badarg(); +X } +X *p_arg = x[0]; +X return 1; +X} +X +Xint +Xgetilongarraysize(args, nargs, i, p_arg) +X object *args; +X int nargs, i; +X long *p_arg; +X{ +X object *v; +X if (!getiobjectarg(args, nargs, i, &v)) +X return 0; +X if (is_tupleobject(v)) { +X *p_arg = gettuplesize(v); +X return 1; +X } +X if (is_listobject(v)) { +X *p_arg = getlistsize(v); +X return 1; +X } +X return err_badarg(); +X} +X +Xint +Xgetishortarraysize(args, nargs, i, p_arg) +X object *args; +X int nargs, i; +X short *p_arg; +X{ +X long x; +X if (!getilongarraysize(args, nargs, i, &x)) +X return 0; +X *p_arg = x; +X return 1; +X} +X +X/* XXX The following four are too similar. Should share more code. */ +X +Xint +Xgetilongarray(args, nargs, i, n, p_arg) +X object *args; +X int nargs, i; +X int n; +X long *p_arg; /* [n] */ +X{ +X object *v, *w; +X if (!getiobjectarg(args, nargs, i, &v)) +X return 0; +X if (is_tupleobject(v)) { +X if (gettuplesize(v) != n) { +X return err_badarg(); +X } +X for (i = 0; i < n; i++) { +X w = gettupleitem(v, i); +X if (!is_intobject(w)) { +X return err_badarg(); +X } +X p_arg[i] = getintvalue(w); +X } +X return 1; +X } +X else if (is_listobject(v)) { +X if (getlistsize(v) != n) { +X return err_badarg(); +X } +X for (i = 0; i < n; i++) { +X w = getlistitem(v, i); +X if (!is_intobject(w)) { +X return err_badarg(); +X } +X p_arg[i] = getintvalue(w); +X } +X return 1; +X } +X else { +X return err_badarg(); +X } +X} +X +Xint +Xgetishortarray(args, nargs, i, n, p_arg) +X object *args; +X int nargs, i; +X int n; +X short *p_arg; /* [n] */ +X{ +X object *v, *w; +X if (!getiobjectarg(args, nargs, i, &v)) +X return 0; +X if (is_tupleobject(v)) { +X if (gettuplesize(v) != n) { +X return err_badarg(); +X } +X for (i = 0; i < n; i++) { +X w = gettupleitem(v, i); +X if (!is_intobject(w)) { +X return err_badarg(); +X } +X p_arg[i] = getintvalue(w); +X } +X return 1; +X } +X else if (is_listobject(v)) { +X if (getlistsize(v) != n) { +X return err_badarg(); +X } +X for (i = 0; i < n; i++) { +X w = getlistitem(v, i); +X if (!is_intobject(w)) { +X return err_badarg(); +X } +X p_arg[i] = getintvalue(w); +X } +X return 1; +X } +X else { +X return err_badarg(); +X } +X} +X +Xint +Xgetidoublearray(args, nargs, i, n, p_arg) +X object *args; +X int nargs, i; +X int n; +X double *p_arg; /* [n] */ +X{ +X object *v, *w; +X if (!getiobjectarg(args, nargs, i, &v)) +X return 0; +X if (is_tupleobject(v)) { +X if (gettuplesize(v) != n) { +X return err_badarg(); +X } +X for (i = 0; i < n; i++) { +X w = gettupleitem(v, i); +X if (!extractdouble(w, &p_arg[i])) +X return 0; +X } +X return 1; +X } +X else if (is_listobject(v)) { +X if (getlistsize(v) != n) { +X return err_badarg(); +X } +X for (i = 0; i < n; i++) { +X w = getlistitem(v, i); +X if (!extractdouble(w, &p_arg[i])) +X return 0; +X } +X return 1; +X } +X else { +X return err_badarg(); +X } +X} +X +Xint +Xgetifloatarray(args, nargs, i, n, p_arg) +X object *args; +X int nargs, i; +X int n; +X float *p_arg; /* [n] */ +X{ +X object *v, *w; +X if (!getiobjectarg(args, nargs, i, &v)) +X return 0; +X if (is_tupleobject(v)) { +X if (gettuplesize(v) != n) { +X return err_badarg(); +X } +X for (i = 0; i < n; i++) { +X w = gettupleitem(v, i); +X if (!extractfloat(w, &p_arg[i])) +X return 0; +X } +X return 1; +X } +X else if (is_listobject(v)) { +X if (getlistsize(v) != n) { +X return err_badarg(); +X } +X for (i = 0; i < n; i++) { +X w = getlistitem(v, i); +X if (!extractfloat(w, &p_arg[i])) +X return 0; +X } +X return 1; +X } +X else { +X return err_badarg(); +X } +X} +EOF +fi +if test -s 'src/modsupport.c' +then echo '*** I will not over-write existing file src/modsupport.c' +else +echo 'x - src/modsupport.c' +sed 's/^X//' > 'src/modsupport.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Module support implementation */ +X +X#include "allobjects.h" +X#include "modsupport.h" +X#include "import.h" +X +X +Xobject * +Xinitmodule(name, methods) +X char *name; +X struct methodlist *methods; +X{ +X object *m, *d, *v; +X struct methodlist *ml; +X char namebuf[256]; +X if ((m = add_module(name)) == NULL) { +X fprintf(stderr, "initializing module: %s\n", name); +X fatal("can't create a module"); +X } +X d = getmoduledict(m); +X for (ml = methods; ml->ml_name != NULL; ml++) { +X sprintf(namebuf, "%s.%s", name, ml->ml_name); +X v = newmethodobject(strdup(namebuf), ml->ml_meth, +X (object *)NULL); +X /* XXX The strdup'ed memory is never freed */ +X if (v == NULL || dictinsert(d, ml->ml_name, v) != 0) { +X fprintf(stderr, "initializing module: %s\n", name); +X fatal("can't initialize module"); +X } +X DECREF(v); +X } +X return m; +X} +X +X +X/* Argument list handling tools. +X All return 1 for success, or call err_set*() and return 0 for failure */ +X +Xint +Xgetnoarg(v) +X object *v; +X{ +X if (v != NULL) { +X return err_badarg(); +X } +X return 1; +X} +X +Xint +Xgetintarg(v, a) +X object *v; +X int *a; +X{ +X if (v == NULL || !is_intobject(v)) { +X return err_badarg(); +X } +X *a = getintvalue(v); +X return 1; +X} +X +Xint +Xgetintintarg(v, a, b) +X object *v; +X int *a; +X int *b; +X{ +X if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { +X return err_badarg(); +X } +X return getintarg(gettupleitem(v, 0), a) && +X getintarg(gettupleitem(v, 1), b); +X} +X +Xint +Xgetlongarg(v, a) +X object *v; +X long *a; +X{ +X if (v == NULL || !is_intobject(v)) { +X return err_badarg(); +X } +X *a = getintvalue(v); +X return 1; +X} +X +Xint +Xgetlonglongargs(v, a, b) +X object *v; +X long *a, *b; +X{ +X if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { +X return err_badarg(); +X } +X return getlongarg(gettupleitem(v, 0), a) && +X getlongarg(gettupleitem(v, 1), b); +X} +X +Xint +Xgetlonglongobjectargs(v, a, b, c) +X object *v; +X long *a, *b; +X object **c; +X{ +X if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 3) { +X return err_badarg(); +X } +X if (getlongarg(gettupleitem(v, 0), a) && +X getlongarg(gettupleitem(v, 1), b)) { +X *c = gettupleitem(v, 2); +X return 1; +X } +X else { +X return err_badarg(); +X } +X} +X +Xint +Xgetstrarg(v, a) +X object *v; +X object **a; +X{ +X if (v == NULL || !is_stringobject(v)) { +X return err_badarg(); +X } +X *a = v; +X return 1; +X} +X +Xint +Xgetstrstrarg(v, a, b) +X object *v; +X object **a; +X object **b; +X{ +X if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { +X return err_badarg(); +X } +X return getstrarg(gettupleitem(v, 0), a) && +X getstrarg(gettupleitem(v, 1), b); +X} +X +Xint +Xgetstrstrintarg(v, a, b, c) +X object *v; +X object **a; +X object **b; +X int *c; +X{ +X if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 3) { +X return err_badarg(); +X } +X return getstrarg(gettupleitem(v, 0), a) && +X getstrarg(gettupleitem(v, 1), b) && +X getintarg(gettupleitem(v, 2), c); +X} +X +Xint +Xgetstrintarg(v, a, b) +X object *v; +X object **a; +X int *b; +X{ +X if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { +X return err_badarg(); +X } +X return getstrarg(gettupleitem(v, 0), a) && +X getintarg(gettupleitem(v, 1), b); +X} +X +Xint +Xgetintstrarg(v, a, b) +X object *v; +X int *a; +X object **b; +X{ +X if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { +X return err_badarg(); +X } +X return getintarg(gettupleitem(v, 0), a) && +X getstrarg(gettupleitem(v, 1), b); +X} +X +Xint +Xgetpointarg(v, a) +X object *v; +X int *a; /* [2] */ +X{ +X return getintintarg(v, a, a+1); +X} +X +Xint +Xget3pointarg(v, a) +X object *v; +X int *a; /* [6] */ +X{ +X if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 3) { +X return err_badarg(); +X } +X return getpointarg(gettupleitem(v, 0), a) && +X getpointarg(gettupleitem(v, 1), a+2) && +X getpointarg(gettupleitem(v, 2), a+4); +X} +X +Xint +Xgetrectarg(v, a) +X object *v; +X int *a; /* [2+2] */ +X{ +X if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { +X return err_badarg(); +X } +X return getpointarg(gettupleitem(v, 0), a) && +X getpointarg(gettupleitem(v, 1), a+2); +X} +X +Xint +Xgetrectintarg(v, a) +X object *v; +X int *a; /* [4+1] */ +X{ +X if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { +X return err_badarg(); +X } +X return getrectarg(gettupleitem(v, 0), a) && +X getintarg(gettupleitem(v, 1), a+4); +X} +X +Xint +Xgetpointintarg(v, a) +X object *v; +X int *a; /* [2+1] */ +X{ +X if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { +X return err_badarg(); +X } +X return getpointarg(gettupleitem(v, 0), a) && +X getintarg(gettupleitem(v, 1), a+2); +X} +X +Xint +Xgetpointstrarg(v, a, b) +X object *v; +X int *a; /* [2] */ +X object **b; +X{ +X if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { +X return err_badarg(); +X } +X return getpointarg(gettupleitem(v, 0), a) && +X getstrarg(gettupleitem(v, 1), b); +X} +X +Xint +Xgetstrintintarg(v, a, b, c) +X object *v; +X object *a; +X int *b, *c; +X{ +X if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 3) { +X return err_badarg(); +X } +X return getstrarg(gettupleitem(v, 0), a) && +X getintarg(gettupleitem(v, 1), b) && +X getintarg(gettupleitem(v, 2), c); +X} +X +Xint +Xgetrectpointarg(v, a) +X object *v; +X int *a; /* [4+2] */ +X{ +X if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { +X return err_badarg(); +X } +X return getrectarg(gettupleitem(v, 0), a) && +X getpointarg(gettupleitem(v, 1), a+4); +X} +X +Xint +Xgetlongtuplearg(args, a, n) +X object *args; +X long *a; /* [n] */ +X int n; +X{ +X int i; +X if (!is_tupleobject(args) || gettuplesize(args) != n) { +X return err_badarg(); +X } +X for (i = 0; i < n; i++) { +X object *v = gettupleitem(args, i); +X if (!is_intobject(v)) { +X return err_badarg(); +X } +X a[i] = getintvalue(v); +X } +X return 1; +X} +X +Xint +Xgetshorttuplearg(args, a, n) +X object *args; +X short *a; /* [n] */ +X int n; +X{ +X int i; +X if (!is_tupleobject(args) || gettuplesize(args) != n) { +X return err_badarg(); +X } +X for (i = 0; i < n; i++) { +X object *v = gettupleitem(args, i); +X if (!is_intobject(v)) { +X return err_badarg(); +X } +X a[i] = getintvalue(v); +X } +X return 1; +X} +X +Xint +Xgetlonglistarg(args, a, n) +X object *args; +X long *a; /* [n] */ +X int n; +X{ +X int i; +X if (!is_listobject(args) || getlistsize(args) != n) { +X return err_badarg(); +X } +X for (i = 0; i < n; i++) { +X object *v = getlistitem(args, i); +X if (!is_intobject(v)) { +X return err_badarg(); +X } +X a[i] = getintvalue(v); +X } +X return 1; +X} +X +Xint +Xgetshortlistarg(args, a, n) +X object *args; +X short *a; /* [n] */ +X int n; +X{ +X int i; +X if (!is_listobject(args) || getlistsize(args) != n) { +X return err_badarg(); +X } +X for (i = 0; i < n; i++) { +X object *v = getlistitem(args, i); +X if (!is_intobject(v)) { +X return err_badarg(); +X } +X a[i] = getintvalue(v); +X } +X return 1; +X} +EOF +fi +if test -s 'src/pythonmain.c' +then echo '*** I will not over-write existing file src/pythonmain.c' +else +echo 'x - src/pythonmain.c' +sed 's/^X//' > 'src/pythonmain.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Python interpreter main program */ +X +X#include "patchlevel.h" +X +X#include "allobjects.h" +X +X#include "grammar.h" +X#include "node.h" +X#include "parsetok.h" +X#include "graminit.h" +X#include "errcode.h" +X#include "sysmodule.h" +X#include "compile.h" +X#include "ceval.h" +X#include "pythonrun.h" +X#include "import.h" +X +Xextern char *getpythonpath(); +X +Xextern grammar gram; /* From graminit.c */ +X +X#ifdef DEBUG +Xint debugging; /* Needed by parser.c */ +X#endif +X +Xmain(argc, argv) +X int argc; +X char **argv; +X{ +X char *filename = NULL; +X FILE *fp = stdin; +X +X initargs(&argc, &argv); +X +X if (argc > 1 && strcmp(argv[1], "-") != 0) +X filename = argv[1]; +X +X if (filename != NULL) { +X if ((fp = fopen(filename, "r")) == NULL) { +X fprintf(stderr, "python: can't open file '%s'\n", +X filename); +X exit(2); +X } +X } +X +X initall(); +X +X setpythonpath(getpythonpath()); +X setpythonargv(argc-1, argv+1); +X +X goaway(run(fp, filename == NULL ? "<stdin>" : filename)); +X /*NOTREACHED*/ +X} +X +X/* Initialize all */ +X +Xvoid +Xinitall() +X{ +X static int inited; +X +X if (inited) +X return; +X inited = 1; +X +X initimport(); +X +X /* Modules 'builtin' and 'sys' are initialized here, +X they are needed by random bits of the interpreter. +X All other modules are optional and should be initialized +X by the initcalls() of a specific configuration. */ +X +X initbuiltin(); /* Also initializes builtin exceptions */ +X initsys(); +X +X initcalls(); /* Configuration-dependent initializations */ +X +X initintr(); /* For intrcheck() */ +X} +X +X/* Parse input from a file and execute it */ +X +Xint +Xrun(fp, filename) +X FILE *fp; +X char *filename; +X{ +X if (filename == NULL) +X filename = "???"; +X if (isatty(fileno(fp))) +X return run_tty_loop(fp, filename); +X else +X return run_script(fp, filename); +X} +X +Xint +Xrun_tty_loop(fp, filename) +X FILE *fp; +X char *filename; +X{ +X object *v; +X int ret; +X v = sysget("ps1"); +X if (v == NULL) { +X sysset("ps1", v = newstringobject(">>> ")); +X XDECREF(v); +X } +X v = sysget("ps2"); +X if (v == NULL) { +X sysset("ps2", v = newstringobject("... ")); +X XDECREF(v); +X } +X for (;;) { +X ret = run_tty_1(fp, filename); +X#ifdef REF_DEBUG +X fprintf(stderr, "[%ld refs]\n", ref_total); +X#endif +X if (ret == E_EOF) +X return 0; +X /* +X if (ret == E_NOMEM) +X return -1; +X */ +X } +X} +X +Xint +Xrun_tty_1(fp, filename) +X FILE *fp; +X char *filename; +X{ +X object *m, *d, *v, *w; +X node *n; +X char *ps1, *ps2; +X int err; +X v = sysget("ps1"); +X w = sysget("ps2"); +X if (v != NULL && is_stringobject(v)) { +X INCREF(v); +X ps1 = getstringvalue(v); +X } +X else { +X v = NULL; +X ps1 = ""; +X } +X if (w != NULL && is_stringobject(w)) { +X INCREF(w); +X ps2 = getstringvalue(w); +X } +X else { +X w = NULL; +X ps2 = ""; +X } +X err = parsefile(fp, filename, &gram, single_input, ps1, ps2, &n); +X XDECREF(v); +X XDECREF(w); +X if (err == E_EOF) +X return E_EOF; +X if (err != E_DONE) { +X err_input(err); +X print_error(); +X return err; +X } +X m = add_module("__main__"); +X if (m == NULL) +X return -1; +X d = getmoduledict(m); +X v = run_node(n, filename, d, d); +X flushline(); +X if (v == NULL) { +X print_error(); +X return -1; +X } +X DECREF(v); +X return 0; +X} +X +Xint +Xrun_script(fp, filename) +X FILE *fp; +X char *filename; +X{ +X object *m, *d, *v; +X m = add_module("__main__"); +X if (m == NULL) +X return -1; +X d = getmoduledict(m); +X v = run_file(fp, filename, file_input, d, d); +X flushline(); +X if (v == NULL) { +X print_error(); +X return -1; +X } +X DECREF(v); +X return 0; +X} +X +Xvoid +Xprint_error() +X{ +X object *exception, *v; +X err_get(&exception, &v); +X fprintf(stderr, "Unhandled exception: "); +X printobject(exception, stderr, PRINT_RAW); +X if (v != NULL && v != None) { +X fprintf(stderr, ": "); +X printobject(v, stderr, PRINT_RAW); +X } +X fprintf(stderr, "\n"); +X XDECREF(exception); +X XDECREF(v); +X printtraceback(stderr); +X} +X +Xobject * +Xrun_string(str, start, globals, locals) +X char *str; +X int start; +X /*dict*/object *globals, *locals; +X{ +X node *n; +X int err; +X err = parse_string(str, start, &n); +X return run_err_node(err, n, "<string>", globals, locals); +X} +X +Xobject * +Xrun_file(fp, filename, start, globals, locals) +X FILE *fp; +X char *filename; +X int start; +X /*dict*/object *globals, *locals; +X{ +X node *n; +X int err; +X err = parse_file(fp, filename, start, &n); +X return run_err_node(err, n, filename, globals, locals); +X} +X +Xobject * +Xrun_err_node(err, n, filename, globals, locals) +X int err; +X node *n; +X char *filename; +X /*dict*/object *globals, *locals; +X{ +X if (err != E_DONE) { +X err_input(err); +X return NULL; +X } +X return run_node(n, filename, globals, locals); +X} +X +Xobject * +Xrun_node(n, filename, globals, locals) +X node *n; +X char *filename; +X /*dict*/object *globals, *locals; +X{ +X if (globals == NULL) { +X globals = getglobals(); +X if (locals == NULL) +X locals = getlocals(); +X } +X else { +X if (locals == NULL) +X locals = globals; +X } +X return eval_node(n, filename, globals, locals); +X} +X +Xobject * +Xeval_node(n, filename, globals, locals) +X node *n; +X char *filename; +X object *globals; +X object *locals; +X{ +X codeobject *co; +X object *v; +X co = compile(n, filename); +X freetree(n); +X if (co == NULL) +X return NULL; +X v = eval_code(co, globals, locals, (object *)NULL); +X DECREF(co); +X return v; +X} +X +X/* Simplified interface to parsefile */ +X +Xint +Xparse_file(fp, filename, start, n_ret) +X FILE *fp; +X char *filename; +X int start; +X node **n_ret; +X{ +X return parsefile(fp, filename, &gram, start, +X (char *)0, (char *)0, n_ret); +X} +X +X/* Simplified interface to parsestring */ +X +Xint +Xparse_string(str, start, n_ret) +X char *str; +X int start; +X node **n_ret; +X{ +X int err = parsestring(str, &gram, start, n_ret); +X /* Don't confuse early end of string with early end of input */ +X if (err == E_EOF) +X err = E_SYNTAX; +X return err; +X} +X +X/* Print fatal error message and abort */ +X +Xvoid +Xfatal(msg) +X char *msg; +X{ +X fprintf(stderr, "Fatal error: %s\n", msg); +X abort(); +X} +X +X/* Clean up and exit */ +X +Xvoid +Xgoaway(sts) +X int sts; +X{ +X flushline(); +X +X /* XXX Call doneimport() before donecalls(), since donecalls() +X calls wdone(), and doneimport() may close windows */ +X doneimport(); +X donecalls(); +X +X err_clear(); +X +X#ifdef REF_DEBUG +X fprintf(stderr, "[%ld refs]\n", ref_total); +X#endif +X +X#ifdef THINK_C_3_0 +X if (sts == 0) +X Click_On(0); +X#endif +X +X#ifdef TRACE_REFS +X if (askyesno("Print left references?")) { +X#ifdef THINK_C_3_0 +X Click_On(1); +X#endif +X printrefs(stderr); +X } +X#endif /* TRACE_REFS */ +X +X exit(sts); +X /*NOTREACHED*/ +X} +X +Xstatic +Xfinaloutput() +X{ +X#ifdef TRACE_REFS +X if (!askyesno("Print left references?")) +X return; +X#ifdef THINK_C_3_0 +X Click_On(1); +X#endif +X printrefs(stderr); +X#endif /* TRACE_REFS */ +X} +X +X/* Ask a yes/no question */ +X +Xstatic int +Xaskyesno(prompt) +X char *prompt; +X{ +X char buf[256]; +X +X printf("%s [ny] ", prompt); +X if (fgets(buf, sizeof buf, stdin) == NULL) +X return 0; +X return buf[0] == 'y' || buf[0] == 'Y'; +X} +X +X#ifdef THINK_C_3_0 +X +X/* Check for file descriptor connected to interactive device. +X Pretend that stdin is always interactive, other files never. */ +X +Xint +Xisatty(fd) +X int fd; +X{ +X return fd == fileno(stdin); +X} +X +X#endif +X +X/* XXX WISH LIST +X +X - possible new types: +X - iterator (for range, keys, ...) +X - improve interpreter error handling, e.g., true tracebacks +X - save precompiled modules on file? +X - fork threads, locking +X - allow syntax extensions +X*/ +X +X/* "Floccinaucinihilipilification" */ +EOF +fi +if test -s 'src/stringobject.c' +then echo '*** I will not over-write existing file src/stringobject.c' +else +echo 'x - src/stringobject.c' +sed 's/^X//' > 'src/stringobject.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* String object implementation */ +X +X#include "allobjects.h" +X +Xobject * +Xnewsizedstringobject(str, size) +X char *str; +X int size; +X{ +X register stringobject *op = (stringobject *) +X malloc(sizeof(stringobject) + size * sizeof(char)); +X if (op == NULL) +X return err_nomem(); +X NEWREF(op); +X op->ob_type = &Stringtype; +X op->ob_size = size; +X if (str != NULL) +X memcpy(op->ob_sval, str, size); +X op->ob_sval[size] = '\0'; +X return (object *) op; +X} +X +Xobject * +Xnewstringobject(str) +X char *str; +X{ +X register unsigned int size = strlen(str); +X register stringobject *op = (stringobject *) +X malloc(sizeof(stringobject) + size * sizeof(char)); +X if (op == NULL) +X return err_nomem(); +X NEWREF(op); +X op->ob_type = &Stringtype; +X op->ob_size = size; +X strcpy(op->ob_sval, str); +X return (object *) op; +X} +X +Xunsigned int +Xgetstringsize(op) +X register object *op; +X{ +X if (!is_stringobject(op)) { +X err_badcall(); +X return -1; +X } +X return ((stringobject *)op) -> ob_size; +X} +X +X/*const*/ char * +Xgetstringvalue(op) +X register object *op; +X{ +X if (!is_stringobject(op)) { +X err_badcall(); +X return NULL; +X } +X return ((stringobject *)op) -> ob_sval; +X} +X +X/* Methods */ +X +Xstatic void +Xstringprint(op, fp, flags) +X stringobject *op; +X FILE *fp; +X int flags; +X{ +X int i; +X char c; +X if (flags & PRINT_RAW) { +X fwrite(op->ob_sval, 1, (int) op->ob_size, fp); +X return; +X } +X fprintf(fp, "'"); +X for (i = 0; i < op->ob_size; i++) { +X c = op->ob_sval[i]; +X if (c == '\'' || c == '\\') +X fprintf(fp, "\\%c", c); +X else if (c < ' ' || c >= 0177) +X fprintf(fp, "\\%03o", c&0377); +X else +X putc(c, fp); +X } +X fprintf(fp, "'"); +X} +X +Xstatic object * +Xstringrepr(op) +X register stringobject *op; +X{ +X /* XXX overflow? */ +X int newsize = 2 + 4 * op->ob_size * sizeof(char); +X object *v = newsizedstringobject((char *)NULL, newsize); +X if (v == NULL) { +X return err_nomem(); +X } +X else { +X register int i; +X register char c; +X register char *p; +X NEWREF(v); +X v->ob_type = &Stringtype; +X ((stringobject *)v)->ob_size = newsize; +X p = ((stringobject *)v)->ob_sval; +X *p++ = '\''; +X for (i = 0; i < op->ob_size; i++) { +X c = op->ob_sval[i]; +X if (c == '\'' || c == '\\') +X *p++ = '\\', *p++ = c; +X else if (c < ' ' || c >= 0177) { +X sprintf(p, "\\%03o", c&0377); +X while (*p != '\0') +X p++; +X +X } +X else +X *p++ = c; +X } +X *p++ = '\''; +X *p = '\0'; +X resizestring(&v, (int) (p - ((stringobject *)v)->ob_sval)); +X return v; +X } +X} +X +Xstatic int +Xstringlength(a) +X stringobject *a; +X{ +X return a->ob_size; +X} +X +Xstatic object * +Xstringconcat(a, bb) +X register stringobject *a; +X register object *bb; +X{ +X register unsigned int size; +X register stringobject *op; +X if (!is_stringobject(bb)) { +X err_badarg(); +X return NULL; +X } +X#define b ((stringobject *)bb) +X /* Optimize cases with empty left or right operand */ +X if (a->ob_size == 0) { +X INCREF(bb); +X return bb; +X } +X if (b->ob_size == 0) { +X INCREF(a); +X return (object *)a; +X } +X size = a->ob_size + b->ob_size; +X op = (stringobject *) +X malloc(sizeof(stringobject) + size * sizeof(char)); +X if (op == NULL) +X return err_nomem(); +X NEWREF(op); +X op->ob_type = &Stringtype; +X op->ob_size = size; +X memcpy(op->ob_sval, a->ob_sval, (int) a->ob_size); +X memcpy(op->ob_sval + a->ob_size, b->ob_sval, (int) b->ob_size); +X op->ob_sval[size] = '\0'; +X return (object *) op; +X#undef b +X} +X +Xstatic object * +Xstringrepeat(a, n) +X register stringobject *a; +X register int n; +X{ +X register int i; +X register unsigned int size; +X register stringobject *op; +X if (n < 0) +X n = 0; +X size = a->ob_size * n; +X if (size == a->ob_size) { +X INCREF(a); +X return (object *)a; +X } +X op = (stringobject *) +X malloc(sizeof(stringobject) + size * sizeof(char)); +X if (op == NULL) +X return err_nomem(); +X NEWREF(op); +X op->ob_type = &Stringtype; +X op->ob_size = size; +X for (i = 0; i < size; i += a->ob_size) +X memcpy(op->ob_sval+i, a->ob_sval, (int) a->ob_size); +X op->ob_sval[size] = '\0'; +X return (object *) op; +X} +X +X/* String slice a[i:j] consists of characters a[i] ... a[j-1] */ +X +Xstatic object * +Xstringslice(a, i, j) +X register stringobject *a; +X register int i, j; /* May be negative! */ +X{ +X if (i < 0) +X i = 0; +X if (j < 0) +X j = 0; /* Avoid signed/unsigned bug in next line */ +X if (j > a->ob_size) +X j = a->ob_size; +X if (i == 0 && j == a->ob_size) { /* It's the same as a */ +X INCREF(a); +X return (object *)a; +X } +X if (j < i) +X j = i; +X return newsizedstringobject(a->ob_sval + i, (int) (j-i)); +X} +X +Xstatic object * +Xstringitem(a, i) +X stringobject *a; +X register int i; +X{ +X if (i < 0 || i >= a->ob_size) { +X err_setstr(IndexError, "string index out of range"); +X return NULL; +X } +X return stringslice(a, i, i+1); +X} +X +Xstatic int +Xstringcompare(a, b) +X stringobject *a, *b; +X{ +X int len_a = a->ob_size, len_b = b->ob_size; +X int min_len = (len_a < len_b) ? len_a : len_b; +X int cmp = memcmp(a->ob_sval, b->ob_sval, min_len); +X if (cmp != 0) +X return cmp; +X return (len_a < len_b) ? -1 : (len_a > len_b) ? 1 : 0; +X} +X +Xstatic sequence_methods string_as_sequence = { +X stringlength, /*tp_length*/ +X stringconcat, /*tp_concat*/ +X stringrepeat, /*tp_repeat*/ +X stringitem, /*tp_item*/ +X stringslice, /*tp_slice*/ +X 0, /*tp_ass_item*/ +X 0, /*tp_ass_slice*/ +X}; +X +Xtypeobject Stringtype = { +X OB_HEAD_INIT(&Typetype) +X 0, +X "string", +X sizeof(stringobject), +X sizeof(char), +X free, /*tp_dealloc*/ +X stringprint, /*tp_print*/ +X 0, /*tp_getattr*/ +X 0, /*tp_setattr*/ +X stringcompare, /*tp_compare*/ +X stringrepr, /*tp_repr*/ +X 0, /*tp_as_number*/ +X &string_as_sequence, /*tp_as_sequence*/ +X 0, /*tp_as_mapping*/ +X}; +X +Xvoid +Xjoinstring(pv, w) +X register object **pv; +X register object *w; +X{ +X register object *v; +X if (*pv == NULL || w == NULL || !is_stringobject(*pv)) +X return; +X v = stringconcat((stringobject *) *pv, w); +X DECREF(*pv); +X *pv = v; +X} +X +X/* The following function breaks the notion that strings are immutable: +X it changes the size of a string. We get away with this only if there +X is only one module referencing the object. You can also think of it +X as creating a new string object and destroying the old one, only +X more efficiently. In any case, don't use this if the string may +X already be known to some other part of the code... */ +X +Xint +Xresizestring(pv, newsize) +X object **pv; +X int newsize; +X{ +X register object *v; +X register stringobject *sv; +X v = *pv; +X if (!is_stringobject(v) || v->ob_refcnt != 1) { +X *pv = 0; +X DECREF(v); +X err_badcall(); +X return -1; +X } +X /* XXX UNREF/NEWREF interface should be more symmetrical */ +X#ifdef REF_DEBUG +X --ref_total; +X#endif +X UNREF(v); +X *pv = (object *) +X realloc((char *)v, +X sizeof(stringobject) + newsize * sizeof(char)); +X if (*pv == NULL) { +X DEL(v); +X err_nomem(); +X return -1; +X } +X NEWREF(*pv); +X sv = (stringobject *) *pv; +X sv->ob_size = newsize; +X sv->ob_sval[newsize] = '\0'; +X return 0; +X} +EOF +fi +echo 'Part 12 out of 21 of pack.out complete.' +exit 0 diff --git a/shar/python-0.9.1-13-21.shar b/shar/python-0.9.1-13-21.shar new file mode 100644 index 0000000..1d0e2ec --- /dev/null +++ b/shar/python-0.9.1-13-21.shar @@ -0,0 +1,2811 @@ +: This is a shell archive. +: Extract with 'sh this_file'. +: +: Extract part 01 first since it makes all directories +echo 'Start of pack.out, part 13 out of 21:' +if test -s 'demo/sgi/audio_stdwin/jukebox.py' +then echo '*** I will not over-write existing file demo/sgi/audio_stdwin/jukebox.py' +else +echo 'x - demo/sgi/audio_stdwin/jukebox.py' +sed 's/^X//' > 'demo/sgi/audio_stdwin/jukebox.py' << 'EOF' +X#! /ufs/guido/bin/sgi/python +X +X# JUKEBOX: browse directories full of sampled sound files. +X# +X# One or more "list windows" display the files and subdirectories of +X# the arguments. Double-clicking on a subdirectory opens a new window +X# displaying its contents (and so on recursively). Double clicking +X# on a file plays it as a sound file (assuming it is one). +X# +X# Playing is asynchronous: the application keeps listening to events +X# while the sample is playing, so you can change the volume (gain) +X# during playing, cancel playing or start a new sample right away. +X# +X# The control window displays the current output gain and a primitive +X# "stop button" to cancel the current play request. +X# +X# Sound files must currently be in Dik Winter's compressed Mac format. +X# Since decompression is costly, decompressed samples are saved in +X# /usr/tmp/@j* until the application is left. The files are read +X# afresh each time, though. +X +Ximport audio +Ximport sunaudio +Ximport commands +Ximport getopt +Ximport path +Ximport posix +Ximport rand +Ximport stdwin +Xfrom stdwinevents import * +Ximport string +Ximport sys +X +Xfrom WindowParent import WindowParent +Xfrom HVSplit import VSplit +Xfrom Buttons import PushButton +Xfrom Sliders import ComplexSlider +X +X# Pathnames +X +XHOME_BIN_SGI = '/ufs/guido/bin/sgi/' # Directory where macsound2sgi lives +XDEF_DB = '/ufs/dik/sounds/Mac/HCOM' # Default directory of sounds +X +X +X# Global variables +X +Xclass struct(): pass # Class to define featureless structures +X +XG = struct() # Holds writable global variables +X +X +X# Main program +X +Xdef main(): +X G.synchronous = 0 # If set, use synchronous audio.write() +X G.debug = 0 # If set, print debug messages +X G.gain = 75 # Output gain +X G.rate = 3 # Sampling rate +X G.busy = 0 # Set while asynchronous playing is active +X G.windows = [] # List of open windows (except control) +X G.mode = 'mac' # Macintosh mode +X G.tempprefix = '/usr/tmp/@j' + `rand.rand()` + '-' +X # +X optlist, args = getopt.getopt(sys.argv[1:], 'dg:r:sSa') +X for optname, optarg in optlist: +X if optname = '-d': +X G.debug = 1 +X elif optname = '-g': +X G.gain = string.atoi(optarg) +X if not (0 < G.gain < 256): +X raise optarg.error, '-g gain out of range' +X elif optname = '-r': +X G.rate = string.atoi(optarg) +X if not (1 <= G.rate <= 3): +X raise optarg.error, '-r rate out of range' +X elif optname = '-s': +X G.synchronous = 1 +X elif optname = '-S': +X G.mode = 'sgi' +X elif optname = '-a': +X G.mode = 'sun' +X # +X if not args: +X args = [DEF_DB] +X # +X G.cw = opencontrolwindow() +X for dirname in args: +X G.windows.append(openlistwindow(dirname)) +X # +X # +X savegain = audio.getoutgain() +X try: +X # Initialize stdaudio +X audio.setoutgain(0) +X audio.start_playing('') +X dummy = audio.wait_playing() +X audio.setoutgain(0) +X maineventloop() +X finally: +X audio.setoutgain(savegain) +X audio.done() +X clearcache() +X +Xdef maineventloop(): +X mouse_events = WE_MOUSE_DOWN, WE_MOUSE_MOVE, WE_MOUSE_UP +X while G.windows: +X type, w, detail = event = stdwin.getevent() +X if w = G.cw.win: +X if type = WE_CLOSE: +X return +X G.cw.dispatch(event) +X else: +X if type = WE_DRAW: +X w.drawproc(w, detail) +X elif type in mouse_events: +X w.mouse(w, type, detail) +X elif type = WE_CLOSE: +X w.close(w) +X del w, event +X else: +X if G.debug: print type, w, detail +X +X# Control window -- to set gain and cancel play operations in progress +X +Xdef opencontrolwindow(): +X cw = WindowParent().create('Jukebox', (0, 0)) +X v = VSplit().create(cw) +X # +X gain = ComplexSlider().define(v) +X gain.setminvalmax(0, G.gain, 255) +X gain.settexts(' ', ' ') +X gain.sethook(gain_setval_hook) +X # +X stop = PushButton().definetext(v, 'Stop') +X stop.hook = stop_hook +X # +X cw.realize() +X return cw +X +Xdef gain_setval_hook(self): +X G.gain = self.val +X if G.busy: audio.setoutgain(G.gain) +X +Xdef stop_hook(self): +X if G.busy: +X audio.setoutgain(0) +X dummy = audio.stop_playing() +X G.busy = 0 +X +X +X# List windows -- to display list of files and subdirectories +X +Xdef openlistwindow(dirname): +X list = posix.listdir(dirname) +X list.sort() +X i = 0 +X while i < len(list): +X if list[i] = '.' or list[i] = '..': +X del list[i] +X else: +X i = i+1 +X for i in range(len(list)): +X name = list[i] +X if path.isdir(path.cat(dirname, name)): +X list[i] = list[i] + '/' +X width = maxwidth(list) +X width = width + stdwin.textwidth(' ') # XXX X11 stdwin bug workaround +X height = len(list) * stdwin.lineheight() +X stdwin.setdefwinsize(width, min(height, 500)) +X w = stdwin.open(dirname) +X stdwin.setdefwinsize(0, 0) +X w.setdocsize(width, height) +X w.drawproc = drawlistwindow +X w.mouse = mouselistwindow +X w.close = closelistwindow +X w.dirname = dirname +X w.list = list +X w.selected = -1 +X return w +X +Xdef maxwidth(list): +X width = 1 +X for name in list: +X w = stdwin.textwidth(name) +X if w > width: width = w +X return width +X +Xdef drawlistwindow(w, area): +X d = w.begindrawing() +X d.erase((0, 0), (1000, 10000)) +X lh = d.lineheight() +X h, v = 0, 0 +X for name in w.list: +X d.text((h, v), name) +X v = v + lh +X showselection(w, d) +X +Xdef hideselection(w, d): +X if w.selected >= 0: +X invertselection(w, d) +X +Xdef showselection(w, d): +X if w.selected >= 0: +X invertselection(w, d) +X +Xdef invertselection(w, d): +X lh = d.lineheight() +X h1, v1 = p1 = 0, w.selected*lh +X h2, v2 = p2 = 1000, v1 + lh +X d.invert(p1, p2) +X +Xdef mouselistwindow(w, type, detail): +X (h, v), clicks, button = detail[:3] +X d = w.begindrawing() +X lh = d.lineheight() +X if 0 <= v < lh*len(w.list): +X i = v / lh +X else: +X i = -1 +X if w.selected <> i: +X hideselection(w, d) +X w.selected = i +X showselection(w, d) +X if type = WE_MOUSE_DOWN and clicks >= 2 and i >= 0: +X name = path.cat(w.dirname, w.list[i]) +X if name[-1:] = '/': +X if clicks = 2: +X G.windows.append(openlistwindow(name[:-1])) +X else: +X playfile(name) +X +Xdef closelistwindow(w): +X remove(G.windows, w) +X +Xdef remove(list, item): +X for i in range(len(list)): +X if list[i] = item: +X del list[i] +X break +X +X +X# Playing tools +X +Xcache = {} +X +Xdef clearcache(): +X for x in cache.keys(): +X try: +X sts = posix.system('rm -f ' + cache[x]) +X if sts: +X print cmd +X print 'Exit status', sts +X except: +X print cmd +X print 'Exception?!' +X del cache[x] +X +Xdef playfile(name): +X if G.mode <> 'mac': +X tempname = name +X elif cache.has_key(name): +X tempname = cache[name] +X else: +X tempname = G.tempprefix + `rand.rand()` +X cmd = HOME_BIN_SGI + 'macsound2sgi' +X cmd = cmd + ' ' + commands.mkarg(name) +X cmd = cmd + ' >' + tempname +X if G.debug: print cmd +X sts = posix.system(cmd) +X if sts: +X print cmd +X print 'Exit status', sts +X stdwin.fleep() +X return +X cache[name] = tempname +X fp = open(tempname, 'r') +X try: +X hdr = sunaudio.gethdr(fp) +X except sunaudio.error, msg: +X hdr = () +X if hdr: +X data_size = hdr[0] +X data = fp.read(data_size) +X # XXX this doesn't work yet, need to convert from uLAW!!! +X del fp +X else: +X del fp +X data = readfile(tempname) +X if G.debug: print len(data), 'bytes read from', tempname +X if G.busy: +X G.busy = 0 +X dummy = audio.stop_playing() +X # +X # Completely reset the audio device +X audio.setrate(G.rate) +X audio.setduration(0) +X audio.setoutgain(G.gain) +X # +X if G.synchronous: +X audio.write(data) +X audio.setoutgain(0) +X else: +X try: +X audio.start_playing(data) +X G.busy = 1 +X except: +X stdwin.fleep() +X del data +X +Xdef readfile(filename): +X return readfp(open(filename, 'r')) +X +Xdef readfp(fp): +X data = '' +X while 1: +X buf = fp.read(102400) # Reads most samples in one fell swoop +X if not buf: +X return data +X data = data + buf +X +Xmain() +EOF +chmod +x 'demo/sgi/audio_stdwin/jukebox.py' +fi +if test -s 'demo/sgi/gl_panel/twoview/twoview.py' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/twoview/twoview.py' +else +echo 'x - demo/sgi/gl_panel/twoview/twoview.py' +sed 's/^X//' > 'demo/sgi/gl_panel/twoview/twoview.py' << 'EOF' +X#! /ufs/guido/bin/sgi/python +X +X# A demo of GL's viewing transformations, showing two views on one scene. +X# Requires the NASA AMES Panel Library. Requires Z buffer. +X +Xfrom gl import * +Xfrom GL import * +Ximport panel +Xfrom math import sin, cos, pi +X +Xinf = 1000000.0 +Xfar = 1000.0 +Xnear = 100.0 +X +Xdef main(): +X foreground() +X # +X keepaspect(1, 1) +X prefposition(10, 610, 10, 610) +X obswid = winopen('Observer View') +X doublebuffer() +X RGBmode() +X gconfig() +X # +X keepaspect(1, 1) +X prefposition(10, 310, 650, 950) +X topwid = winopen('Top View') +X doublebuffer() +X RGBmode() +X gconfig() +X # +X panels = panel.defpanellist('observer.s') +X panels = panels + panel.defpanellist('camera.s') +X panels = panels + panel.defpanellist('topview.s') +X # +X p = panels[0] +X q = panels[1] +X r = panels[2] +X # +X p.farclip = q.farclip +X p.nearclip = q.nearclip +X p.zoom = q.zoom +X p.quitbutton = q.quitbutton +X # +X p.xpos = r.xpos +X p.zpos = r.zpos +X p.direction = r.direction +X # +X p.direction.winds = 1.0 # allow full rotation +X # +X def quit(act): +X import sys +X sys.exit(0) +X p.quitbutton.downfunc = quit +X # +X p.left.back = p +X p.fast_left.back = p +X p.right.back = p +X p.fast_right.back = p +X p.forward.back = p +X p.fast_forward.back = p +X p.reverse.back = p +X p.fast_reverse.back = p +X p.up.back = p +X p.down.back = p +X # +X p.left.activefunc = left +X p.fast_left.activefunc = fast_left +X p.right.activefunc = right +X p.fast_right.activefunc = fast_right +X p.forward.activefunc = forward +X p.fast_forward.activefunc = fast_forward +X p.reverse.activefunc = reverse +X p.fast_reverse.activefunc = fast_reverse +X p.up.activefunc = up +X p.down.activefunc = down +X # +X makeobjects() +X # +X drawall(p, obswid, topwid) +X panel.needredraw() +X while 1: +X act = panel.dopanel() +X if panel.userredraw() or act: +X drawall(p, obswid, topwid) +X +Xdef left(a): +X doturn(a.back, 0.01) +X +Xdef fast_left(a): +X doturn(a.back, 0.1) +X +Xdef right(a): +X doturn(a.back, -0.01) +X +Xdef fast_right(a): +X doturn(a.back, -0.1) +X +Xdef doturn(p, angle): +X alpha = lookangle(p) + angle +X # Reverse the following assignment: +X # alpha = pi*1.5 - p.direction.val*2.0*pi +X val = (pi*1.5 - alpha) / 2.0 / pi +X while val < 0.0: val = val + 1.0 +X while val > 1.0: val = val - 1.0 +X p.direction.val = val +X p.direction.fixact() +X +Xdef forward(a): +X dostep(a.back, 1.0) +X +Xdef fast_forward(a): +X dostep(a.back, 10.0) +X +Xdef reverse(a): +X dostep(a.back, -1.0) +X +Xdef fast_reverse(a): +X dostep(a.back, -10.0) +X +Xdef dostep(p, step): +X x, y, z = observerpos(p) +X alpha = lookangle(p) +X x = x + step*cos(alpha) +X z = z - step*sin(alpha) +X # Reverse the following assignments: +X # x = 2.0 * p.xpos.val * near - near +X # z = near - 2.0 * p.zpos.val * near +X p.xpos.val = (x + near) / 2.0 / near +X p.zpos.val = - (z - near) / 2.0 / near +X p.xpos.fixact() +X p.zpos.fixact() +X +Xdef up(a): +X doup(a.back, 0.2) +X +Xdef down(a): +X doup(a.back, -0.2) +X +Xdef doup(p, step): +X x, y, z = observerpos(p) +X y = y + step +X # Reverse: +X # y = p.ypos.val * near +X p.ypos.val = y/near +X p.ypos.fixact() +X +Xdef drawall(p, obswid, topwid): +X # +X winset(obswid) +X obsview(p) +X drawscene() +X swapbuffers() +X # +X winset(topwid) +X topview(p) +X drawscene() +X drawobserver(p) +X swapbuffers() +X +Xdef drawobserver(p): +X x, y, z = observerpos(p) +X alpha = lookangle(p) +X fov = 2.0 + 1798.0 * p.zoom.val +X beta = fov*pi/3600.0 # Half fov, expressed in radians +X # +X c3i(0, 255, 0) +X # +X move(x, y, z) +X x1 = x + inf*cos(alpha+beta) +X y1 = y +X z1 = z - inf*sin(alpha+beta) +X draw(x1, y1, z1) +X # +X move(x, y, z) +X x1 = x + inf*cos(alpha-beta) +X y1 = y +X z1 = z - inf*sin(alpha-beta) +X draw(x1, y1, z1) +X +Xdef observerlookat(p): +X x, y, z = observerpos(p) +X alpha = lookangle(p) +X return x, y, z, x+near*cos(alpha), y, z-near*sin(alpha), 0 +X +Xdef observerpos(p): +X x = 2.0 * p.xpos.val * near - near +X y = p.ypos.val * near +X z = near - 2.0 * p.zpos.val * near +X return x, y, z +X +Xdef lookangle(p): +X return pi*1.5 - p.direction.val*2.0*pi +X +Xidmat = 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 +X +Xdef topview(p): +X mmode(MVIEWING) +X ortho(-far, far, -far, far, far, -far) +X loadmatrix(idmat) +X rotate(900, 'x') +X +Xdef obsview(p): +X fov = 2.0 + 1798.0 * p.zoom.val +X nearclip = p.nearclip.val * 10.0 +X farclip = p.farclip.val * 10.0*far +X aspectratio = 1.0 +X mmode(MVIEWING) +X perspective(int(fov), aspectratio, nearclip, farclip) +X loadmatrix(idmat) +X lookat(observerlookat(p)) +X +Xdef drawscene(): +X # +X # clear window +X # +X c3i(0, 0, 0) +X clear() +X # +X # turn on z buffering and clear it +X # +X zbuffer(TRUE) +X zclear() +X # +X # dark blue sky (depending on your gamma value!) +X # +X c3i(0, 0, 150) +X callobj(41) +X # +X # bright red near and far units circle +X # (use rotate since circ() always draws in x-y plane) +X # +X c3i(255, 0, 0) +X pushmatrix() +X rotate(900, 'x') +X circ(0.0, 0.0, near) +X circ(0.0, 0.0, far) +X popmatrix() +X # +X # bright white striping +X # +X c3i(255, 255, 200) +X callobj(42) +X # +X # building (does its own colors) +X # +X building() +X # +X # some other objects +X # +X dice() +X +Xdef makeobjects(): +X # +X # sky object +X # +X makeobj(41) +X pmv(-inf, 0.0, -far) +X pdr(inf, 0.0, -far) +X pdr(inf, inf, -far) +X pdr(-inf, inf, -far) +X pclos() +X closeobj() +X # +X # road stripes object +X # +X makeobj(42) +X stripes() +X closeobj() +X # +X # lighting model definitions +X # +X deflight() +X +Xdef stripes(): +X # +X # left line +X # +X botrect(-11, -10, far, -far) +X # +X # right line +X # +X botrect(10, 11, far, -far) +X # +X # center lines +X # +X z = far +X while z > -far: +X botrect(-0.5, 0.5, z, z - 4.0) +X z = z - 10.0 +X +Xdef dice(): +X from block import block +X uselight() +X pushmatrix() +X translate(0.0, 1.0, -20.0) +X rotate(200, 'y') +X block(1, 0, 0, 0, 0, 0) +X translate(1.0, 0.0, 3.0) +X rotate(500, 'y') +X block(2, 0, 0, 0, 0, 0) +X popmatrix() +X +Xdef deflight(): +X # Material for first die (red) +X lmdef(DEFMATERIAL, 1, (DIFFUSE, 1.0, 0.0, 0.0)) +X # Material for second die (green) +X lmdef(DEFMATERIAL, 2, (DIFFUSE, 0.0, 1.0, 0.0)) +X # First light source (default: white, from front) +X lmdef(DEFLIGHT, 1, ()) +X # Second light source (red, from back) +X lmdef(DEFLIGHT, 2, (POSITION, 0.0, 1.0, -1.0, 0.0)) +X lmdef(DEFLIGHT, 2, (LCOLOR, 1.0, 0.0, 0.0)) +X # Lighting model +X lmdef(DEFLMODEL, 1, (AMBIENT, 0.0, 0.0, 1.0)) +X +Xdef uselight(): +X lmbind(LIGHT0, 1) +X lmbind(LIGHT1, 2) +X lmbind(LMODEL, 1) +X # (materials are bound later) +X +Xdef building(): +X # +X c3i(0, 255, 255) +X # +X # house bounding coordinates +X # +X x1 = 20.0 +X x1a = 25.0 +X x2 = 30.0 +X y1 = 0.0 +X y2 = 15.0 +X y2a = 20.0 +X z1 = -40.0 +X z2 = -55.0 +X # +X # door y and z coordinates +X # +X dy1 = 0.0 +X dy2 = 4.0 +X dz1 = -45.0 +X dz2 = -47.0 +X # +X # front side (seen from origin) +X # +X A1 = (x1, y1, z1) +X B1 = (x2, y1, z1) +X C1 = (x2, y2, z1) +X D1 = (x1a, y2a, z1) +X E1 = (x1, y2, z1) +X # +X # back size +X # +X A2 = (x1, y1, z2) +X B2 = (x2, y1, z2) +X C2 = (x2, y2, z2) +X D2 = (x1a, y2a, z2) +X E2 = (x1, y2, z2) +X # +X # door in the left side +X # +X P = x1, dy1, dz2 +X Q = x1, dy2, dz2 +X R = x1, dy2, dz1 +X S = x1, dy1, dz1 +X # +X # draw it +X # +X concave(TRUE) +X c3i(255, 0, 0) +X face(A1, B1, C1, D1, E1) +X c3i(127, 127, 0) +X face(A1, E1, E2, A2, P, Q, R, S) +X c3i(0, 255, 0) +X face(E1, D1, D2, E2) +X c3i(0, 127, 127) +X face(D1, C1, C2, D2) +X c3i(0, 0, 255) +X face(C1, B1, B2, C2) +X c3i(127, 0, 127) +X face(E2, D2, C2, B2, A2) +X concave(FALSE) +X +Xdef face(points): +X bgnpolygon() +X varray(points) +X endpolygon() +X +X# draw a rectangle at y=0.0 +X# +Xdef botrect(x1, x2, z1, z2): +X polf(x1, 0.0, z1, x2, 0.0, z1, x2, 0.0, z2, x1, 0.0, z2) +X +Xmain() +EOF +chmod +x 'demo/sgi/gl_panel/twoview/twoview.py' +fi +if test -s 'lib/DEVICE.py' +then echo '*** I will not over-write existing file lib/DEVICE.py' +else +echo 'x - lib/DEVICE.py' +sed 's/^X//' > 'lib/DEVICE.py' << 'EOF' +X#/************************************************************************** +X# * * +X# * Copyright (C) 1984, Silicon Graphics, Inc. * +X# * * +X# * These coded instructions, statements, and computer programs contain * +X# * unpublished proprietary information of Silicon Graphics, Inc., and * +X# * are protected by Federal copyright law. They may not be disclosed * +X# * to third parties or copied or duplicated in any form, in whole or * +X# * in part, without the prior written consent of Silicon Graphics, Inc. * +X# * * +X# **************************************************************************/ +X#/* file with device definitions (see /usr/include/device.h) */ +X +XNULLDEV = 0 +XBUTOFFSET = 1 +XVALOFFSET = 256 +XTIMOFFSET = 515 +XXKBDOFFSET = 143 +XINOFFSET = 1024 +XOUTOFFSET = 1033 +XBUTCOUNT = 190 +XVALCOUNT = 27 +XTIMCOUNT = 4 +XXKBDCOUNT = 28 +XINCOUNT = 8 +XOUTCOUNT = 8 +X# +X# +X# +X# +XBUT0 = 1 +XBUT1 = 2 +XBUT2 = 3 +XBUT3 = 4 +XBUT4 = 5 +XBUT5 = 6 +XBUT6 = 7 +XBUT7 = 8 +XBUT8 = 9 +XBUT9 = 10 +XBUT10 = 11 +XBUT11 = 12 +XBUT12 = 13 +XBUT13 = 14 +XBUT14 = 15 +XBUT15 = 16 +XBUT16 = 17 +XBUT17 = 18 +XBUT18 = 19 +XBUT19 = 20 +XBUT20 = 21 +XBUT21 = 22 +XBUT22 = 23 +XBUT23 = 24 +XBUT24 = 25 +XBUT25 = 26 +XBUT26 = 27 +XBUT27 = 28 +XBUT28 = 29 +XBUT29 = 30 +XBUT30 = 31 +XBUT31 = 32 +XBUT32 = 33 +XBUT33 = 34 +XBUT34 = 35 +XBUT35 = 36 +XBUT36 = 37 +XBUT37 = 38 +XBUT38 = 39 +XBUT39 = 40 +XBUT40 = 41 +XBUT41 = 42 +XBUT42 = 43 +XBUT43 = 44 +XBUT44 = 45 +XBUT45 = 46 +XBUT46 = 47 +XBUT47 = 48 +XBUT48 = 49 +XBUT49 = 50 +XBUT50 = 51 +XBUT51 = 52 +XBUT52 = 53 +XBUT53 = 54 +XBUT54 = 55 +XBUT55 = 56 +XBUT56 = 57 +XBUT57 = 58 +XBUT58 = 59 +XBUT59 = 60 +XBUT60 = 61 +XBUT61 = 62 +XBUT62 = 63 +XBUT63 = 64 +XBUT64 = 65 +XBUT65 = 66 +XBUT66 = 67 +XBUT67 = 68 +XBUT68 = 69 +XBUT69 = 70 +XBUT70 = 71 +XBUT71 = 72 +XBUT72 = 73 +XBUT73 = 74 +XBUT74 = 75 +XBUT75 = 76 +XBUT76 = 77 +XBUT77 = 78 +XBUT78 = 79 +XBUT79 = 80 +XBUT80 = 81 +XBUT81 = 82 +XBUT82 = 83 +XMAXKBDBUT = 83 +XBUT100 = 101 +XBUT101 = 102 +XBUT102 = 103 +XBUT110 = 111 +XBUT111 = 112 +XBUT112 = 113 +XBUT113 = 114 +XBUT114 = 115 +XBUT115 = 116 +XBUT116 = 117 +XBUT117 = 118 +XBUT118 = 119 +XBUT119 = 120 +XBUT120 = 121 +XBUT121 = 122 +XBUT122 = 123 +XBUT123 = 124 +XBUT124 = 125 +XBUT125 = 126 +XBUT126 = 127 +XBUT127 = 128 +XBUT128 = 129 +XBUT129 = 130 +XBUT130 = 131 +XBUT131 = 132 +XBUT132 = 133 +XBUT133 = 134 +XBUT134 = 135 +XBUT135 = 136 +XBUT136 = 137 +XBUT137 = 138 +XBUT138 = 139 +XBUT139 = 140 +XBUT140 = 141 +XBUT141 = 142 +XBUT142 = 143 +XBUT143 = 144 +XBUT144 = 145 +XBUT145 = 146 +XBUT146 = 147 +XBUT147 = 148 +XBUT148 = 149 +XBUT149 = 150 +XBUT150 = 151 +XBUT151 = 152 +XBUT152 = 153 +XBUT153 = 154 +XBUT154 = 155 +XBUT155 = 156 +XBUT156 = 157 +XBUT157 = 158 +XBUT158 = 159 +XBUT159 = 160 +XBUT160 = 161 +XBUT161 = 162 +XBUT162 = 163 +XBUT163 = 164 +XBUT164 = 165 +XBUT165 = 166 +XBUT166 = 167 +XBUT167 = 168 +XBUT168 = 169 +XBUT181 = 182 +XBUT182 = 183 +XBUT183 = 184 +XBUT184 = 185 +XBUT185 = 186 +XBUT186 = 187 +XBUT187 = 188 +XBUT188 = 189 +XBUT189 = 190 +XMOUSE1 = 101 +XMOUSE2 = 102 +XMOUSE3 = 103 +XLEFTMOUSE = 103 +XMIDDLEMOUSE = 102 +XRIGHTMOUSE = 101 +XLPENBUT = 104 +XBPAD0 = 105 +XBPAD1 = 106 +XBPAD2 = 107 +XBPAD3 = 108 +XLPENVALID = 109 +XSWBASE = 111 +XSW0 = 111 +XSW1 = 112 +XSW2 = 113 +XSW3 = 114 +XSW4 = 115 +XSW5 = 116 +XSW6 = 117 +XSW7 = 118 +XSW8 = 119 +XSW9 = 120 +XSW10 = 121 +XSW11 = 122 +XSW12 = 123 +XSW13 = 124 +XSW14 = 125 +XSW15 = 126 +XSW16 = 127 +XSW17 = 128 +XSW18 = 129 +XSW19 = 130 +XSW20 = 131 +XSW21 = 132 +XSW22 = 133 +XSW23 = 134 +XSW24 = 135 +XSW25 = 136 +XSW26 = 137 +XSW27 = 138 +XSW28 = 139 +XSW29 = 140 +XSW30 = 141 +XSW31 = 142 +XSBBASE = 182 +XSBPICK = 182 +XSBBUT1 = 183 +XSBBUT2 = 184 +XSBBUT3 = 185 +XSBBUT4 = 186 +XSBBUT5 = 187 +XSBBUT6 = 188 +XSBBUT7 = 189 +XSBBUT8 = 190 +XAKEY = 11 +XBKEY = 36 +XCKEY = 28 +XDKEY = 18 +XEKEY = 17 +XFKEY = 19 +XGKEY = 26 +XHKEY = 27 +XIKEY = 40 +XJKEY = 34 +XKKEY = 35 +XLKEY = 42 +XMKEY = 44 +XNKEY = 37 +XOKEY = 41 +XPKEY = 48 +XQKEY = 10 +XRKEY = 24 +XSKEY = 12 +XTKEY = 25 +XUKEY = 33 +XVKEY = 29 +XWKEY = 16 +XXKEY = 21 +XYKEY = 32 +XZKEY = 20 +XZEROKEY = 46 +XONEKEY = 8 +XTWOKEY = 14 +XTHREEKEY = 15 +XFOURKEY = 22 +XFIVEKEY = 23 +XSIXKEY = 30 +XSEVENKEY = 31 +XEIGHTKEY = 38 +XNINEKEY = 39 +XBREAKKEY = 1 +XSETUPKEY = 2 +XCTRLKEY = 3 +XLEFTCTRLKEY = CTRLKEY +XCAPSLOCKKEY = 4 +XRIGHTSHIFTKEY = 5 +XLEFTSHIFTKEY = 6 +XNOSCRLKEY = 13 +XESCKEY = 7 +XTABKEY = 9 +XRETKEY = 51 +XSPACEKEY = 83 +XLINEFEEDKEY = 60 +XBACKSPACEKEY = 61 +XDELKEY = 62 +XSEMICOLONKEY = 43 +XPERIODKEY = 52 +XCOMMAKEY = 45 +XQUOTEKEY = 50 +XACCENTGRAVEKEY = 55 +XMINUSKEY = 47 +XVIRGULEKEY = 53 +XBACKSLASHKEY = 57 +XEQUALKEY = 54 +XLEFTBRACKETKEY = 49 +XRIGHTBRACKETKEY = 56 +XLEFTARROWKEY = 73 +XDOWNARROWKEY = 74 +XRIGHTARROWKEY = 80 +XUPARROWKEY = 81 +XPAD0 = 59 +XPAD1 = 58 +XPAD2 = 64 +XPAD3 = 65 +XPAD4 = 63 +XPAD5 = 69 +XPAD6 = 70 +XPAD7 = 67 +XPAD8 = 68 +XPAD9 = 75 +XPADPF1 = 72 +XPADPF2 = 71 +XPADPF3 = 79 +XPADPF4 = 78 +XPADPERIOD = 66 +XPADMINUS = 76 +XPADCOMMA = 77 +XPADENTER = 82 +XLEFTALTKEY = 143 +XRIGHTALTKEY = 144 +XRIGHTCTRLKEY = 145 +XF1KEY = 146 +XF2KEY = 147 +XF3KEY = 148 +XF4KEY = 149 +XF5KEY = 150 +XF6KEY = 151 +XF7KEY = 152 +XF8KEY = 153 +XF9KEY = 154 +XF10KEY = 155 +XF11KEY = 156 +XF12KEY = 157 +XPRINTSCREENKEY = 158 +XSCROLLLOCKKEY = 159 +XPAUSEKEY = 160 +XINSERTKEY = 161 +XHOMEKEY = 162 +XPAGEUPKEY = 163 +XENDKEY = 164 +XPAGEDOWNKEY = 165 +XNUMLOCKKEY = 166 +XPADVIRGULEKEY = 167 +XPADASTERKEY = 168 +XPADPLUSKEY = 169 +XSGIRESERVED = 256 +XDIAL0 = 257 +XDIAL1 = 258 +XDIAL2 = 259 +XDIAL3 = 260 +XDIAL4 = 261 +XDIAL5 = 262 +XDIAL6 = 263 +XDIAL7 = 264 +XDIAL8 = 265 +XMOUSEX = 266 +XMOUSEY = 267 +XLPENX = 268 +XLPENY = 269 +XBPADX = 270 +XBPADY = 271 +XCURSORX = 272 +XCURSORY = 273 +XGHOSTX = 274 +XGHOSTY = 275 +XSBTX = 276 +XSBTY = 277 +XSBTZ = 278 +XSBRX = 279 +XSBRY = 280 +XSBRZ = 281 +XSBPERIOD = 282 +XTIMER0 = 515 +XTIMER1 = 516 +XTIMER2 = 517 +XTIMER3 = 518 +XKEYBD = 513 +XRAWKEYBD = 514 +XVALMARK = 523 +XGERROR = 524 +XREDRAW = 528 +XWMSEND = 529 +XWMREPLY = 530 +XWMGFCLOSE = 531 +XWMTXCLOSE = 532 +XMODECHANGE = 533 +XINPUTCHANGE = 534 +XQFULL = 535 +XPIECECHANGE = 536 +XWINCLOSE = 537 +XQREADERROR = 538 +XWINFREEZE = 539 +XWINTHAW = 540 +XREDRAWICONIC = 541 +XWINQUIT = 542 +XDEPTHCHANGE = 543 +XKEYBDFNAMES = 544 +XKEYBDFSTRINGS = 545 +XWINSHUT = 546 +XINPUT0 = 1024 +XINPUT1 = 1025 +XINPUT2 = 1026 +XINPUT3 = 1027 +XINPUT4 = 1028 +XINPUT5 = 1029 +XINPUT6 = 1030 +XINPUT7 = 1032 +XOUTPUT0 = 1033 +XOUTPUT1 = 1034 +XOUTPUT2 = 1035 +XOUTPUT3 = 1036 +XOUTPUT4 = 1037 +XOUTPUT5 = 1038 +XOUTPUT6 = 1039 +XOUTPUT7 = 1040 +XMAXSGIDEVICE = 20000 +XMENUBUTTON = RIGHTMOUSE +EOF +fi +if test -s 'lib/GL.py' +then echo '*** I will not over-write existing file lib/GL.py' +else +echo 'x - lib/GL.py' +sed 's/^X//' > 'lib/GL.py' << 'EOF' +X# Constants defined in <gl.h> +X +X#************************************************************************** +X#* * +X#* Copyright (C) 1984, Silicon Graphics, Inc. * +X#* * +X#* These coded instructions, statements, and computer programs contain * +X#* unpublished proprietary information of Silicon Graphics, Inc., and * +X#* are protected by Federal copyright law. They may not be disclosed * +X#* to third parties or copied or duplicated in any form, in whole or * +X#* in part, without the prior written consent of Silicon Graphics, Inc. * +X#* * +X#************************************************************************** +X +X# Graphics Libary constants +X +X# Booleans +XTRUE = 1 +XFALSE = 0 +X +X# maximum X and Y screen coordinates +XXMAXSCREEN = 1279 +XYMAXSCREEN = 1023 +XXMAXMEDIUM = 1023 # max for medium res monitor +XYMAXMEDIUM = 767 +XXMAX170 = 645 # max for RS-170 +XYMAX170 = 484 +XXMAXPAL = 779 # max for PAL +XYMAXPAL = 574 +X +X# various hardware/software limits +XATTRIBSTACKDEPTH = 10 +XVPSTACKDEPTH = 8 +XMATRIXSTACKDEPTH = 32 +XNAMESTACKDEPTH = 1025 +XSTARTTAG = -2 +XENDTAG = -3 +XCPOSX_INVALID = -(2*XMAXSCREEN) +X +X# names for colors in color map loaded by greset +XBLACK = 0 +XRED = 1 +XGREEN = 2 +XYELLOW = 3 +XBLUE = 4 +XMAGENTA = 5 +XCYAN = 6 +XWHITE = 7 +X +X# popup colors +XPUP_CLEAR = 0 +XPUP_COLOR = 1 +XPUP_BLACK = 2 +XPUP_WHITE = 3 +X +X# defines for drawmode +XNORMALDRAW = 0 +XPUPDRAW = 1 +XOVERDRAW = 2 +XUNDERDRAW = 3 +XCURSORDRAW = 4 +X +X# defines for defpattern +XPATTERN_16 = 16 +XPATTERN_32 = 32 +XPATTERN_64 = 64 +X +XPATTERN_16_SIZE = 16 +XPATTERN_32_SIZE = 64 +XPATTERN_64_SIZE = 256 +X +X# defines for readsource +XSRC_AUTO = 0 +XSRC_FRONT = 1 +XSRC_BACK = 2 +XSRC_ZBUFFER = 3 +XSRC_PUP = 4 +XSRC_OVER = 5 +XSRC_UNDER = 6 +XSRC_FRAMEGRABBER = 7 +X +X# defines for blendfunction +XBF_ZERO = 0 +XBF_ONE = 1 +XBF_DC = 2 +XBF_SC = 2 +XBF_MDC = 3 +XBF_MSC = 3 +XBF_SA = 4 +XBF_MSA = 5 +XBF_DA = 6 +XBF_MDA = 7 +X +X# defines for zfunction +XZF_NEVER = 0 +XZF_LESS = 1 +XZF_EQUAL = 2 +XZF_LEQUAL = 3 +XZF_GREATER = 4 +XZF_NOTEQUAL = 5 +XZF_GEQUAL = 6 +XZF_ALWAYS = 7 +X +X# defines for zsource +XZSRC_DEPTH = 0 +XZSRC_COLOR = 1 +X +X# defines for pntsmooth +XSMP_OFF = 0 +XSMP_ON = 1 +X +X# defines for linesmooth +XSML_OFF = 0 +XSML_ON = 1 +X +X# defines for setpup +XPUP_NONE = 0 +XPUP_GREY = 1 +X +X# defines for glcompat +XGLC_OLDPOLYGON = 0 +XGLC_ZRANGEMAP = 1 +X +X# defines for curstype +XC16X1 = 0 +XC16X2 = 1 +XC32X1 = 2 +XC32X2 = 3 +XCCROSS = 4 +X +X# defines for shademodel +XFLAT = 0 +XGOURAUD = 1 +X +X# defines for logicop +X### LO_ZERO = 0x0 +X### LO_AND = 0x1 +X### LO_ANDR = 0x2 +X### LO_SRC = 0x3 +X### LO_ANDI = 0x4 +X### LO_DST = 0x5 +X### LO_XOR = 0x6 +X### LO_OR = 0x7 +X### LO_NOR = 0x8 +X### LO_XNOR = 0x9 +X### LO_NDST = 0xa +X### LO_ORR = 0xb +X### LO_NSRC = 0xc +X### LO_ORI = 0xd +X### LO_NAND = 0xe +X### LO_ONE = 0xf +X +X +X# +X# START defines for getgdesc +X# +X +XGD_XPMAX = 0 +XGD_YPMAX = 1 +XGD_XMMAX = 2 +XGD_YMMAX = 3 +XGD_ZMIN = 4 +XGD_ZMAX = 5 +XGD_BITS_NORM_SNG_RED = 6 +XGD_BITS_NORM_SNG_GREEN = 7 +XGD_BITS_NORM_SNG_BLUE = 8 +XGD_BITS_NORM_DBL_RED = 9 +XGD_BITS_NORM_DBL_GREEN = 10 +XGD_BITS_NORM_DBL_BLUE = 11 +XGD_BITS_NORM_SNG_CMODE = 12 +XGD_BITS_NORM_DBL_CMODE = 13 +XGD_BITS_NORM_SNG_MMAP = 14 +XGD_BITS_NORM_DBL_MMAP = 15 +XGD_BITS_NORM_ZBUFFER = 16 +XGD_BITS_OVER_SNG_CMODE = 17 +XGD_BITS_UNDR_SNG_CMODE = 18 +XGD_BITS_PUP_SNG_CMODE = 19 +XGD_BITS_NORM_SNG_ALPHA = 21 +XGD_BITS_NORM_DBL_ALPHA = 22 +XGD_BITS_CURSOR = 23 +XGD_OVERUNDER_SHARED = 24 +XGD_BLEND = 25 +XGD_CIFRACT = 26 +XGD_CROSSHAIR_CINDEX = 27 +XGD_DITHER = 28 +XGD_LINESMOOTH_CMODE = 30 +XGD_LINESMOOTH_RGB = 31 +XGD_LOGICOP = 33 +XGD_NSCRNS = 35 +XGD_NURBS_ORDER = 36 +XGD_NBLINKS = 37 +XGD_NVERTEX_POLY = 39 +XGD_PATSIZE_64 = 40 +XGD_PNTSMOOTH_CMODE = 41 +XGD_PNTSMOOTH_RGB = 42 +XGD_PUP_TO_OVERUNDER = 43 +XGD_READSOURCE = 44 +XGD_READSOURCE_ZBUFFER = 48 +XGD_STEREO = 50 +XGD_SUBPIXEL_LINE = 51 +XGD_SUBPIXEL_PNT = 52 +XGD_SUBPIXEL_POLY = 53 +XGD_TRIMCURVE_ORDER = 54 +XGD_WSYS = 55 +XGD_ZDRAW_GEOM = 57 +XGD_ZDRAW_PIXELS = 58 +XGD_SCRNTYPE = 61 +XGD_TEXTPORT = 62 +XGD_NMMAPS = 63 +XGD_FRAMEGRABBER = 64 +XGD_TIMERHZ = 66 +XGD_DBBOX = 67 +XGD_AFUNCTION = 68 +XGD_ALPHA_OVERUNDER = 69 +XGD_BITS_ACBUF = 70 +XGD_BITS_ACBUF_HW = 71 +XGD_BITS_STENCIL = 72 +XGD_CLIPPLANES = 73 +XGD_FOGVERTEX = 74 +XGD_LIGHTING_TWOSIDE = 76 +XGD_POLYMODE = 77 +XGD_POLYSMOOTH = 78 +XGD_SCRBOX = 79 +XGD_TEXTURE = 80 +X +X# return value for inquiries when there is no limit +XGD_NOLIMIT = 2 +X +X# return values for GD_WSYS +XGD_WSYS_NONE = 0 +XGD_WSYS_4S = 1 +X +X# return values for GD_SCRNTYPE +XGD_SCRNTYPE_WM = 0 +XGD_SCRNTYPE_NOWM = 1 +X +X# +X# END defines for getgdesc +X# +X +X +X# +X# START NURBS interface definitions +X# +X +X# NURBS Rendering Properties +XN_PIXEL_TOLERANCE = 1 +XN_CULLING = 2 +XN_DISPLAY = 3 +XN_ERRORCHECKING = 4 +XN_SUBDIVISIONS = 5 +XN_S_STEPS = 6 +XN_T_STEPS = 7 +XN_TILES = 8 +X +XN_SHADED = 1.0 +X +X# --------------------------------------------------------------------------- +X# FLAGS FOR NURBS SURFACES AND CURVES +X# +X# Bit: 9876 5432 1 0 +X# |tttt|nnnn|f|r| : r - 1 bit = 1 if rational coordinate exists +X# : f - 1 bit = 1 if rational coordinate is before rest +X# : = 0 if rational coordinate is after rest +X# : nnnn - 4 bits for number of coordinates +X# : tttt - 4 bits for type of data (color, position, etc.) +X# +X# NURBS data type +X# N_T_ST 0 parametric space data +X# N_T_XYZ 1 model space data +X# +X# rational or non-rational data and position in memory +X# N_NONRATIONAL 0 non-rational data +X# N_RATAFTER 1 rational data with rat coord after rest +X# N_RATBEFORE 3 rational data with rat coord before rest +X# +X# N_MKFLAG(a,b,c) ((a<<6) | (b<<2) | c) +X# +X# --------------------------------------------------------------------------- +X# +XN_ST = 0x8 # N_MKFLAG( N_T_ST, 2, N_NONRATIONAL ) +XN_STW = 0xd # N_MKFLAG( N_T_ST, 3, N_RATAFTER ) +XN_WST = 0xf # N_MKFLAG( N_T_ST, 3, N_RATBEFORE ) +XN_XYZ = 0x4c # N_MKFLAG( N_T_XYZ, 3, N_NONRATIONAL ) +XN_XYZW = 0x51 # N_MKFLAG( N_T_XYZ, 4, N_RATAFTER ) +XN_WXYZ = 0x53 # N_MKFLAG( N_T_XYZ, 4, N_RATBEFORE ) +X +X# +X# END NURBS interface definitions +X# +X +X +X# +X# START lighting model defines +X# +X +XLMNULL = 0.0 +X +X# MATRIX modes +XMSINGLE = 0 +XMPROJECTION = 1 +XMVIEWING = 2 +X +X# LIGHT constants +XMAXLIGHTS = 8 +XMAXRESTRICTIONS = 4 +X +X# MATERIAL properties +XDEFMATERIAL = 0 +XEMISSION = 1 +XAMBIENT = 2 +XDIFFUSE = 3 +XSPECULAR = 4 +XSHININESS = 5 +XCOLORINDEXES = 6 +XALPHA = 7 +X +X# LIGHT properties +XDEFLIGHT = 100 +XLCOLOR = 101 +XPOSITION = 102 +X +X# LIGHTINGMODEL properties +XDEFLMODEL = 200 +XLOCALVIEWER = 201 +XATTENUATION = 202 +X +X# TARGET constants +XMATERIAL = 1000 +XLIGHT0 = 1100 +XLIGHT1 = 1101 +XLIGHT2 = 1102 +XLIGHT3 = 1103 +XLIGHT4 = 1104 +XLIGHT5 = 1105 +XLIGHT6 = 1106 +XLIGHT7 = 1107 +XLMODEL = 1200 +X +X# lmcolor modes +XLMC_COLOR = 0 +XLMC_EMISSION = 1 +XLMC_AMBIENT = 2 +XLMC_DIFFUSE = 3 +XLMC_SPECULAR = 4 +XLMC_AD = 5 +XLMC_NULL = 6 +X +X# +X# END lighting model defines +X# +X +X +X# +X# START distributed graphics library defines +X# +X +XDGLSINK = 0 # sink connection +XDGLLOCAL = 1 # local connection +XDGLTSOCKET = 2 # tcp socket connection +XDGL4DDN = 3 # 4DDN (DECnet) +X +X# +X# END distributed graphics library defines +X# +EOF +fi +if test -s 'lib/calendar.py' +then echo '*** I will not over-write existing file lib/calendar.py' +else +echo 'x - lib/calendar.py' +sed 's/^X//' > 'lib/calendar.py' << 'EOF' +X# module calendar +X +X############################## +X# Calendar support functions # +X############################## +X +X# This is based on UNIX ctime() et al. (also Standard C and POSIX) +X# Subtle but crucial differences: +X# - the order of the elements of a 'struct tm' differs, to ease sorting +X# - months numbers are 1-12, not 0-11; month arrays have a dummy element 0 +X# - Monday is the first day of the week (numbered 0) +X +X# These are really parameters of the 'time' module: +Xepoch = 1970 # Time began on January 1 of this year (00:00:00 UCT) +Xday_0 = 3 # The epoch begins on a Thursday (Monday = 0) +X +X# Return 1 for leap years, 0 for non-leap years +Xdef isleap(year): +X return year % 4 = 0 and (year % 100 <> 0 or year % 400 = 0) +X +X# Constants for months referenced later +XJanuary = 1 +XFebruary = 2 +X +X# Number of days per month (except for February in leap years) +Xmdays = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) +X +X# Exception raised for bad input (with string parameter for details) +Xerror = 'calendar error' +X +X# Turn seconds since epoch into calendar time +Xdef gmtime(secs): +X if secs < 0: raise error, 'negative input to gmtime()' +X mins, secs = divmod(secs, 60) +X hours, mins = divmod(mins, 60) +X days, hours = divmod(hours, 24) +X wday = (days + day_0) % 7 +X year = epoch +X # XXX Most of the following loop can be replaced by one division +X while 1: +X yd = 365 + isleap(year) +X if days < yd: break +X days = days - yd +X year = year + 1 +X yday = days +X month = January +X while 1: +X md = mdays[month] + (month = February and isleap(year)) +X if days < md: break +X days = days - md +X month = month + 1 +X return year, month, days + 1, hours, mins, secs, yday, wday +X # XXX Week number also? +X +X# Return number of leap years in range [y1, y2) +X# Assume y1 <= y2 and no funny (non-leap century) years +Xdef leapdays(y1, y2): +X return (y2+3)/4 - (y1+3)/4 +X +X# Inverse of gmtime(): +X# Turn UCT calendar time (less yday, wday) into seconds since epoch +Xdef mktime(year, month, day, hours, mins, secs): +X days = day - 1 +X for m in range(January, month): days = days + mdays[m] +X if isleap(year) and month > February: days = days+1 +X days = days + (year-epoch)*365 + leapdays(epoch, year) +X return ((days*24 + hours)*60 + mins)*60 + secs +X +X# Full and abbreviated names of weekdays +Xday_name = ('Monday', 'Tuesday', 'Wednesday', 'Thursday') +Xday_name = day_name + ('Friday', 'Saturday', 'Sunday') +Xday_abbr = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun') +X +X# Full and abbreviated of months (1-based arrays!!!) +Xmonth_name = ('', 'January', 'February', 'March', 'April') +Xmonth_name = month_name + ('May', 'June', 'July', 'August') +Xmonth_name = month_name + ('September', 'October', 'November', 'December') +Xmonth_abbr = (' ', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun') +Xmonth_abbr = month_abbr + ('Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec') +X +X# Zero-fill string to two positions (helper for asctime()) +Xdef dd(s): +X while len(s) < 2: s = '0' + s +X return s +X +X# Blank-fill string to two positions (helper for asctime()) +Xdef zd(s): +X while len(s) < 2: s = ' ' + s +X return s +X +X# Turn calendar time as returned by gmtime() into a string +X# (the yday parameter is for compatibility with gmtime()) +Xdef asctime(year, month, day, hours, mins, secs, yday, wday): +X s = day_abbr[wday] + ' ' + month_abbr[month] + ' ' + zd(`day`) +X s = s + ' ' + dd(`hours`) + ':' + dd(`mins`) + ':' + dd(`secs`) +X return s + ' ' + `year` +X +X# Localization: Minutes West from Greenwich +X# timezone = -2*60 # Middle-European time with DST on +Xtimezone = 5*60 # EST (sigh -- THINK time() doesn't return UCT) +X +X# Local time ignores DST issues for now -- adjust 'timezone' to fake it +Xdef localtime(secs): +X return gmtime(secs - timezone*60) +X +X# UNIX-style ctime (except it doesn't append '\n'!) +Xdef ctime(secs): +X return asctime(localtime(secs)) +X +X###################### +X# Non-UNIX additions # +X###################### +X +X# Calendar printing etc. +X +X# Return weekday (0-6 ~ Mon-Sun) for year (1970-...), month (1-12), day (1-31) +Xdef weekday(year, month, day): +X secs = mktime(year, month, day, 0, 0, 0) +X days = secs / (24*60*60) +X return (days + day_0) % 7 +X +X# Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for year, month +Xdef monthrange(year, month): +X day1 = weekday(year, month, 1) +X ndays = mdays[month] + (month = February and isleap(year)) +X return day1, ndays +X +X# Return a matrix representing a month's calendar +X# Each row represents a week; days outside this month are zero +Xdef _monthcalendar(year, month): +X day1, ndays = monthrange(year, month) +X rows = [] +X r7 = range(7) +X day = 1 - day1 +X while day <= ndays: +X row = [0, 0, 0, 0, 0, 0, 0] +X for i in r7: +X if 1 <= day <= ndays: row[i] = day +X day = day + 1 +X rows.append(row) +X return rows +X +X# Caching interface to _monthcalendar +Xmc_cache = {} +Xdef monthcalendar(year, month): +X key = `year` + month_abbr[month] +X try: +X return mc_cache[key] +X except RuntimeError: +X mc_cache[key] = ret = _monthcalendar(year, month) +X return ret +X +X# Center a string in a field +Xdef center(str, width): +X n = width - len(str) +X if n < 0: return str +X return ' '*(n/2) + str + ' '*(n-n/2) +X +X# XXX The following code knows that print separates items with space! +X +X# Print a single week (no newline) +Xdef prweek(week, width): +X for day in week: +X if day = 0: print ' '*width, +X else: +X if width > 2: print ' '*(width-3), +X if day < 10: print '', +X print day, +X +X# Return a header for a week +Xdef weekheader(width): +X str = '' +X for i in range(7): +X if str: str = str + ' ' +X str = str + day_abbr[i%7][:width] +X return str +X +X# Print a month's calendar +Xdef prmonth(year, month): +X print weekheader(3) +X for week in monthcalendar(year, month): +X prweek(week, 3) +X print +X +X# Spacing between month columns +Xspacing = ' ' +X +X# 3-column formatting for year calendars +Xdef format3c(a, b, c): +X print center(a, 20), spacing, center(b, 20), spacing, center(c, 20) +X +X# Print a year's calendar +Xdef prcal(year): +X header = weekheader(2) +X format3c('', `year`, '') +X for q in range(January, January+12, 3): +X print +X format3c(month_name[q], month_name[q+1], month_name[q+2]) +X format3c(header, header, header) +X data = [] +X height = 0 +X for month in range(q, q+3): +X cal = monthcalendar(year, month) +X if len(cal) > height: height = len(cal) +X data.append(cal) +X for i in range(height): +X for cal in data: +X if i >= len(cal): +X print ' '*20, +X else: +X prweek(cal[i], 2) +X print spacing, +X print +EOF +fi +if test -s 'lib/panel.py' +then echo '*** I will not over-write existing file lib/panel.py' +else +echo 'x - lib/panel.py' +sed 's/^X//' > 'lib/panel.py' << 'EOF' +X# Module 'panel' +X# +X# Support for the Panel library. +X# Uses built-in module 'pnl'. +X# Applciations should use 'panel.function' instead of 'pnl.function'; +X# most 'pnl' functions are transparently exported by 'panel', +X# but dopanel() is overridden and you have to use this version +X# if you want to use callbacks. +X +X +Ximport pnl +X +X +Xdebug = 0 +X +X +X# Test if an object is a list. +X# +Xdef is_list(x): +X return type(x) = type([]) +X +X +X# Reverse a list. +X# +Xdef reverse(list): +X res = [] +X for item in list: +X res.insert(0, item) +X return res +X +X +X# Get an attribute of a list, which may itself be another list. +X# Don't use 'prop' for name. +X# +Xdef getattrlist(list, name): +X for item in list: +X if item and is_list(item) and item[0] = name: +X return item[1:] +X return [] +X +X +X# Get a property of a list, which may itself be another list. +X# +Xdef getproplist(list, name): +X for item in list: +X if item and is_list(item) and item[0] = 'prop': +X if len(item) > 1 and item[1] = name: +X return item[2:] +X return [] +X +X +X# Test if an actuator description contains the property 'end-of-group' +X# +Xdef is_endgroup(list): +X x = getproplist(list, 'end-of-group') +X return (x and x[0] = '#t') +X +X +X# Neatly display an actuator definition given as S-expression +X# the prefix string is printed before each line. +X# +Xdef show_actuator(prefix, a): +X for item in a: +X if not is_list(item): +X print prefix, item +X elif item and item[0] = 'al': +X print prefix, 'Subactuator list:' +X for a in item[1:]: +X show_actuator(prefix + ' ', a) +X elif len(item) = 2: +X print prefix, item[0], '=>', item[1] +X elif len(item) = 3 and item[0] = 'prop': +X print prefix, 'Prop', item[1], '=>', +X print item[2] +X else: +X print prefix, '?', item +X +X +X# Neatly display a panel. +X# +Xdef show_panel(prefix, p): +X for item in p: +X if not is_list(item): +X print prefix, item +X elif item and item[0] = 'al': +X print prefix, 'Actuator list:' +X for a in item[1:]: +X show_actuator(prefix + ' ', a) +X elif len(item) = 2: +X print prefix, item[0], '=>', item[1] +X elif len(item) = 3 and item[0] = 'prop': +X print prefix, 'Prop', item[1], '=>', +X print item[2] +X else: +X print prefix, '?', item +X +X +X# Exception raised by build_actuator or build_panel. +X# +Xpanel_error = 'panel error' +X +X +X# Dummy callback used to initialize the callbacks. +X# +Xdef dummy_callback(arg): +X pass +X +X +X# Assign attributes to members of the target. +X# Attribute names in exclist are ignored. +X# The member name is the attribute name prefixed with the prefix. +X# +Xdef assign_members(target, attrlist, exclist, prefix): +X for item in attrlist: +X if is_list(item) and len(item) = 2 and item[0] not in exclist: +X name, value = item[0], item[1] +X ok = 1 +X if value[0] in '-0123456789': +X value = eval(value) +X elif value[0] = '"': +X value = value[1:-1] +X elif value = 'move-then-resize': +X # Strange default set by Panel Editor... +X ok = 0 +X else: +X print 'unknown value', value, 'for', name +X ok = 0 +X if ok: +X lhs = 'target.' + prefix + name +X stmt = lhs + '=' + `value` +X if debug: print 'exec', stmt +X try: +X exec(stmt + '\n') +X except KeyboardInterrupt: # Don't catch this! +X raise KeyboardInterrupt +X except: +X print 'assign failed:', stmt +X +X +X# Build a real actuator from an actuator descriptior. +X# Return a pair (actuator, name). +X# +Xdef build_actuator(descr): +X namelist = getattrlist(descr, 'name') +X if namelist: +X # Assume it is a string +X actuatorname = namelist[0][1:-1] +X else: +X actuatorname = '' +X type = descr[0] +X if type[:4] = 'pnl_': type = type[4:] +X act = pnl.mkact(type) +X act.downfunc = act.activefunc = act.upfunc = dummy_callback +X # +X assign_members(act, descr[1:], ['al', 'data', 'name'], '') +X # +X # Treat actuator-specific data +X # +X datalist = getattrlist(descr, 'data') +X prefix = '' +X if type[-4:] = 'puck': +X prefix = 'puck_' +X elif type = 'mouse': +X prefix = 'mouse_' +X assign_members(act, datalist, [], prefix) +X # +X return act, actuatorname +X +X +X# Build all sub-actuators and add them to the super-actuator. +X# The super-actuator must already have been added to the panel. +X# Sub-actuators with defined names are added as members to the panel +X# so they can be referenced as p.name. +X# +X# Note: I have no idea how panel.endgroup() works when applied +X# to a sub-actuator. +X# +Xdef build_subactuators(panel, super_act, al): +X # +X # This is nearly the same loop as below in build_panel(), +X # except a call is made to addsubact() instead of addact(). +X # +X for a in al: +X act, name = build_actuator(a) +X act.addsubact(super_act) +X if name: +X stmt = 'panel.' + name + ' = act' +X if debug: print 'exec', stmt +X exec(stmt + '\n') +X if is_endgroup(a): +X panel.endgroup() +X sub_al = getattrlist(a, 'al') +X if sub_al: +X build_subactuators(panel, act, sub_al) +X # +X # Fix the actuator to which whe just added subactuators. +X # This can't hurt (I hope) and is needed for the scroll actuator. +X # +X super_act.fixact() +X +X +X# Build a real panel from a panel definition. +X# Return a panel object p, where for each named actuator a, p.name is a +X# reference to a. +X# +Xdef build_panel(descr): +X # +X # Sanity check +X # +X if (not descr) or descr[0] <> 'panel': +X raise panel_error, 'panel description must start with "panel"' +X # +X if debug: show_panel('', descr) +X # +X # Create an empty panel +X # +X panel = pnl.mkpanel() +X # +X # Assign panel attributes +X # +X assign_members(panel, descr[1:], ['al'], '') +X # +X # Look for actuator list +X # +X al = getattrlist(descr, 'al') +X # +X # The order in which actuators are created is important +X # because of the endgroup() operator. +X # Unfortunately the Panel Editor outputs the actuator list +X # in reverse order, so we reverse it here. +X # +X al = reverse(al) +X # +X for a in al: +X act, name = build_actuator(a) +X act.addact(panel) +X if name: +X stmt = 'panel.' + name + ' = act' +X exec(stmt + '\n') +X if is_endgroup(a): +X panel.endgroup() +X sub_al = getattrlist(a, 'al') +X if sub_al: +X build_subactuators(panel, act, sub_al) +X # +X return panel +X +X +X# Wrapper around pnl.dopanel() which calls call-back functions. +X# +Xdef my_dopanel(): +X # Extract only the first 4 elements to allow for future expansion +X a, down, active, up = pnl.dopanel()[:4] +X if down: +X down.downfunc(down) +X if active: +X active.activefunc(active) +X if up: +X up.upfunc(up) +X return a +X +X +X# Create one or more panels from a description file (S-expressions) +X# generated by the Panel Editor. +X# +Xdef defpanellist(file): +X import panelparser +X descrlist = panelparser.parse_file(open(file, 'r')) +X panellist = [] +X for descr in descrlist: +X panellist.append(build_panel(descr)) +X return panellist +X +X +X# Import everything from built-in method pnl, so the user can always +X# use panel.foo() instead of pnl.foo(). +X# This gives *no* performance penalty once this module is imported. +X# +Xfrom pnl import * # for export +X +Xdopanel = my_dopanel # override pnl.dopanel +EOF +fi +if test -s 'src/acceler.c' +then echo '*** I will not over-write existing file src/acceler.c' +else +echo 'x - src/acceler.c' +sed 's/^X//' > 'src/acceler.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Parser accelerator module */ +X +X/* The parser as originally conceived had disappointing performance. +X This module does some precomputation that speeds up the selection +X of a DFA based upon a token, turning a search through an array +X into a simple indexing operation. The parser now cannot work +X without the accelerators installed. Note that the accelerators +X are installed dynamically when the parser is initialized, they +X are not part of the static data structure written on graminit.[ch] +X by the parser generator. */ +X +X#include "pgenheaders.h" +X#include "grammar.h" +X#include "token.h" +X#include "parser.h" +X +X/* Forward references */ +Xstatic void fixdfa PROTO((grammar *, dfa *)); +Xstatic void fixstate PROTO((grammar *, dfa *, state *)); +X +Xvoid +Xaddaccelerators(g) +X grammar *g; +X{ +X dfa *d; +X int i; +X#ifdef DEBUG +X printf("Adding parser accellerators ...\n"); +X#endif +X d = g->g_dfa; +X for (i = g->g_ndfas; --i >= 0; d++) +X fixdfa(g, d); +X g->g_accel = 1; +X#ifdef DEBUG +X printf("Done.\n"); +X#endif +X} +X +Xstatic void +Xfixdfa(g, d) +X grammar *g; +X dfa *d; +X{ +X state *s; +X int j; +X s = d->d_state; +X for (j = 0; j < d->d_nstates; j++, s++) +X fixstate(g, d, s); +X} +X +Xstatic void +Xfixstate(g, d, s) +X grammar *g; +X dfa *d; +X state *s; +X{ +X arc *a; +X int k; +X int *accel; +X int nl = g->g_ll.ll_nlabels; +X s->s_accept = 0; +X accel = NEW(int, nl); +X for (k = 0; k < nl; k++) +X accel[k] = -1; +X a = s->s_arc; +X for (k = s->s_narcs; --k >= 0; a++) { +X int lbl = a->a_lbl; +X label *l = &g->g_ll.ll_label[lbl]; +X int type = l->lb_type; +X if (a->a_arrow >= (1 << 7)) { +X printf("XXX too many states!\n"); +X continue; +X } +X if (ISNONTERMINAL(type)) { +X dfa *d1 = finddfa(g, type); +X int ibit; +X if (type - NT_OFFSET >= (1 << 7)) { +X printf("XXX too high nonterminal number!\n"); +X continue; +X } +X for (ibit = 0; ibit < g->g_ll.ll_nlabels; ibit++) { +X if (testbit(d1->d_first, ibit)) { +X if (accel[ibit] != -1) +X printf("XXX ambiguity!\n"); +X accel[ibit] = a->a_arrow | (1 << 7) | +X ((type - NT_OFFSET) << 8); +X } +X } +X } +X else if (lbl == EMPTY) +X s->s_accept = 1; +X else if (lbl >= 0 && lbl < nl) +X accel[lbl] = a->a_arrow; +X } +X while (nl > 0 && accel[nl-1] == -1) +X nl--; +X for (k = 0; k < nl && accel[k] == -1;) +X k++; +X if (k < nl) { +X int i; +X s->s_accel = NEW(int, nl-k); +X if (s->s_accel == NULL) { +X fprintf(stderr, "no mem to add parser accelerators\n"); +X exit(1); +X } +X s->s_lower = k; +X s->s_upper = nl; +X for (i = 0; k < nl; i++, k++) +X s->s_accel[i] = accel[k]; +X } +X DEL(accel); +X} +EOF +fi +if test -s 'src/classobject.c' +then echo '*** I will not over-write existing file src/classobject.c' +else +echo 'x - src/classobject.c' +sed 's/^X//' > 'src/classobject.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Class object implementation */ +X +X#include "allobjects.h" +X +X#include "structmember.h" +X +Xtypedef struct { +X OB_HEAD +X object *cl_bases; /* A tuple */ +X object *cl_methods; /* A dictionary */ +X} classobject; +X +Xobject * +Xnewclassobject(bases, methods) +X object *bases; /* NULL or tuple of classobjects! */ +X object *methods; +X{ +X classobject *op; +X op = NEWOBJ(classobject, &Classtype); +X if (op == NULL) +X return NULL; +X if (bases != NULL) +X INCREF(bases); +X op->cl_bases = bases; +X INCREF(methods); +X op->cl_methods = methods; +X return (object *) op; +X} +X +X/* Class methods */ +X +Xstatic void +Xclass_dealloc(op) +X classobject *op; +X{ +X int i; +X if (op->cl_bases != NULL) +X DECREF(op->cl_bases); +X DECREF(op->cl_methods); +X free((ANY *)op); +X} +X +Xstatic object * +Xclass_getattr(op, name) +X register classobject *op; +X register char *name; +X{ +X register object *v; +X v = dictlookup(op->cl_methods, name); +X if (v != NULL) { +X INCREF(v); +X return v; +X } +X if (op->cl_bases != NULL) { +X int n = gettuplesize(op->cl_bases); +X int i; +X for (i = 0; i < n; i++) { +X v = class_getattr(gettupleitem(op->cl_bases, i), name); +X if (v != NULL) +X return v; +X err_clear(); +X } +X } +X err_setstr(NameError, name); +X return NULL; +X} +X +Xtypeobject Classtype = { +X OB_HEAD_INIT(&Typetype) +X 0, +X "class", +X sizeof(classobject), +X 0, +X class_dealloc, /*tp_dealloc*/ +X 0, /*tp_print*/ +X class_getattr, /*tp_getattr*/ +X 0, /*tp_setattr*/ +X 0, /*tp_compare*/ +X 0, /*tp_repr*/ +X 0, /*tp_as_number*/ +X 0, /*tp_as_sequence*/ +X 0, /*tp_as_mapping*/ +X}; +X +X +X/* We're not done yet: next, we define class member objects... */ +X +Xtypedef struct { +X OB_HEAD +X classobject *cm_class; /* The class object */ +X object *cm_attr; /* A dictionary */ +X} classmemberobject; +X +Xobject * +Xnewclassmemberobject(class) +X register object *class; +X{ +X register classmemberobject *cm; +X if (!is_classobject(class)) { +X err_badcall(); +X return NULL; +X } +X cm = NEWOBJ(classmemberobject, &Classmembertype); +X if (cm == NULL) +X return NULL; +X INCREF(class); +X cm->cm_class = (classobject *)class; +X cm->cm_attr = newdictobject(); +X if (cm->cm_attr == NULL) { +X DECREF(cm); +X return NULL; +X } +X return (object *)cm; +X} +X +X/* Class member methods */ +X +Xstatic void +Xclassmember_dealloc(cm) +X register classmemberobject *cm; +X{ +X DECREF(cm->cm_class); +X if (cm->cm_attr != NULL) +X DECREF(cm->cm_attr); +X free((ANY *)cm); +X} +X +Xstatic object * +Xclassmember_getattr(cm, name) +X register classmemberobject *cm; +X register char *name; +X{ +X register object *v = dictlookup(cm->cm_attr, name); +X if (v != NULL) { +X INCREF(v); +X return v; +X } +X v = class_getattr(cm->cm_class, name); +X if (v == NULL) +X return v; /* class_getattr() has set the error */ +X if (is_funcobject(v)) { +X object *w = newclassmethodobject(v, (object *)cm); +X DECREF(v); +X return w; +X } +X DECREF(v); +X err_setstr(NameError, name); +X return NULL; +X} +X +Xstatic int +Xclassmember_setattr(cm, name, v) +X classmemberobject *cm; +X char *name; +X object *v; +X{ +X if (v == NULL) +X return dictremove(cm->cm_attr, name); +X else +X return dictinsert(cm->cm_attr, name, v); +X} +X +Xtypeobject Classmembertype = { +X OB_HEAD_INIT(&Typetype) +X 0, +X "class member", +X sizeof(classmemberobject), +X 0, +X classmember_dealloc, /*tp_dealloc*/ +X 0, /*tp_print*/ +X classmember_getattr, /*tp_getattr*/ +X classmember_setattr, /*tp_setattr*/ +X 0, /*tp_compare*/ +X 0, /*tp_repr*/ +X 0, /*tp_as_number*/ +X 0, /*tp_as_sequence*/ +X 0, /*tp_as_mapping*/ +X}; +X +X +X/* And finally, here are class method objects */ +X/* (Really methods of class members) */ +X +Xtypedef struct { +X OB_HEAD +X object *cm_func; /* The method function */ +X object *cm_self; /* The object to which this applies */ +X} classmethodobject; +X +Xobject * +Xnewclassmethodobject(func, self) +X object *func; +X object *self; +X{ +X register classmethodobject *cm; +X if (!is_funcobject(func)) { +X err_badcall(); +X return NULL; +X } +X cm = NEWOBJ(classmethodobject, &Classmethodtype); +X if (cm == NULL) +X return NULL; +X INCREF(func); +X cm->cm_func = func; +X INCREF(self); +X cm->cm_self = self; +X return (object *)cm; +X} +X +Xobject * +Xclassmethodgetfunc(cm) +X register object *cm; +X{ +X if (!is_classmethodobject(cm)) { +X err_badcall(); +X return NULL; +X } +X return ((classmethodobject *)cm)->cm_func; +X} +X +Xobject * +Xclassmethodgetself(cm) +X register object *cm; +X{ +X if (!is_classmethodobject(cm)) { +X err_badcall(); +X return NULL; +X } +X return ((classmethodobject *)cm)->cm_self; +X} +X +X/* Class method methods */ +X +X#define OFF(x) offsetof(classmethodobject, x) +X +Xstatic struct memberlist classmethod_memberlist[] = { +X {"cm_func", T_OBJECT, OFF(cm_func)}, +X {"cm_self", T_OBJECT, OFF(cm_self)}, +X {NULL} /* Sentinel */ +X}; +X +Xstatic object * +Xclassmethod_getattr(cm, name) +X register classmethodobject *cm; +X char *name; +X{ +X return getmember((char *)cm, classmethod_memberlist, name); +X} +X +Xstatic void +Xclassmethod_dealloc(cm) +X register classmethodobject *cm; +X{ +X DECREF(cm->cm_func); +X DECREF(cm->cm_self); +X free((ANY *)cm); +X} +X +Xtypeobject Classmethodtype = { +X OB_HEAD_INIT(&Typetype) +X 0, +X "class method", +X sizeof(classmethodobject), +X 0, +X classmethod_dealloc, /*tp_dealloc*/ +X 0, /*tp_print*/ +X classmethod_getattr, /*tp_getattr*/ +X 0, /*tp_setattr*/ +X 0, /*tp_compare*/ +X 0, /*tp_repr*/ +X 0, /*tp_as_number*/ +X 0, /*tp_as_sequence*/ +X 0, /*tp_as_mapping*/ +X}; +EOF +fi +if test -s 'src/intobject.c' +then echo '*** I will not over-write existing file src/intobject.c' +else +echo 'x - src/intobject.c' +sed 's/^X//' > 'src/intobject.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Integer object implementation */ +X +X#include "allobjects.h" +X +X/* Standard Booleans */ +X +Xintobject FalseObject = { +X OB_HEAD_INIT(&Inttype) +X 0 +X}; +X +Xintobject TrueObject = { +X OB_HEAD_INIT(&Inttype) +X 1 +X}; +X +Xstatic object * +Xerr_ovf() +X{ +X err_setstr(OverflowError, "integer overflow"); +X return NULL; +X} +X +Xstatic object * +Xerr_zdiv() +X{ +X err_setstr(ZeroDivisionError, "integer division by zero"); +X return NULL; +X} +X +X/* Integers are quite normal objects, to make object handling uniform. +X (Using odd pointers to represent integers would save much space +X but require extra checks for this special case throughout the code.) +X Since, a typical Python program spends much of its time allocating +X and deallocating integers, these operations should be very fast. +X Therefore we use a dedicated allocation scheme with a much lower +X overhead (in space and time) than straight malloc(): a simple +X dedicated free list, filled when necessary with memory from malloc(). +X*/ +X +X#define BLOCK_SIZE 1000 /* 1K less typical malloc overhead */ +X#define N_INTOBJECTS (BLOCK_SIZE / sizeof(intobject)) +X +Xstatic intobject * +Xfill_free_list() +X{ +X intobject *p, *q; +X p = NEW(intobject, N_INTOBJECTS); +X if (p == NULL) +X return (intobject *)err_nomem(); +X q = p + N_INTOBJECTS; +X while (--q > p) +X *(intobject **)q = q-1; +X *(intobject **)q = NULL; +X return p + N_INTOBJECTS - 1; +X} +X +Xstatic intobject *free_list = NULL; +X +Xobject * +Xnewintobject(ival) +X long ival; +X{ +X register intobject *v; +X if (free_list == NULL) { +X if ((free_list = fill_free_list()) == NULL) +X return NULL; +X } +X v = free_list; +X free_list = *(intobject **)free_list; +X NEWREF(v); +X v->ob_type = &Inttype; +X v->ob_ival = ival; +X return (object *) v; +X} +X +Xstatic void +Xint_dealloc(v) +X intobject *v; +X{ +X *(intobject **)v = free_list; +X free_list = v; +X} +X +Xlong +Xgetintvalue(op) +X register object *op; +X{ +X if (!is_intobject(op)) { +X err_badcall(); +X return -1; +X } +X else +X return ((intobject *)op) -> ob_ival; +X} +X +X/* Methods */ +X +Xstatic void +Xint_print(v, fp, flags) +X intobject *v; +X FILE *fp; +X int flags; +X{ +X fprintf(fp, "%ld", v->ob_ival); +X} +X +Xstatic object * +Xint_repr(v) +X intobject *v; +X{ +X char buf[20]; +X sprintf(buf, "%ld", v->ob_ival); +X return newstringobject(buf); +X} +X +Xstatic int +Xint_compare(v, w) +X intobject *v, *w; +X{ +X register long i = v->ob_ival; +X register long j = w->ob_ival; +X return (i < j) ? -1 : (i > j) ? 1 : 0; +X} +X +Xstatic object * +Xint_add(v, w) +X intobject *v; +X register object *w; +X{ +X register long a, b, x; +X if (!is_intobject(w)) { +X err_badarg(); +X return NULL; +X } +X a = v->ob_ival; +X b = ((intobject *)w) -> ob_ival; +X x = a + b; +X if ((x^a) < 0 && (x^b) < 0) +X return err_ovf(); +X return newintobject(x); +X} +X +Xstatic object * +Xint_sub(v, w) +X intobject *v; +X register object *w; +X{ +X register long a, b, x; +X if (!is_intobject(w)) { +X err_badarg(); +X return NULL; +X } +X a = v->ob_ival; +X b = ((intobject *)w) -> ob_ival; +X x = a - b; +X if ((x^a) < 0 && (x^~b) < 0) +X return err_ovf(); +X return newintobject(x); +X} +X +Xstatic object * +Xint_mul(v, w) +X intobject *v; +X register object *w; +X{ +X register long a, b; +X double x; +X if (!is_intobject(w)) { +X err_badarg(); +X return NULL; +X } +X a = v->ob_ival; +X b = ((intobject *)w) -> ob_ival; +X x = (double)a * (double)b; +X if (x > 0x7fffffff || x < (double) (long) 0x80000000) +X return err_ovf(); +X return newintobject(a * b); +X} +X +Xstatic object * +Xint_div(v, w) +X intobject *v; +X register object *w; +X{ +X if (!is_intobject(w)) { +X err_badarg(); +X return NULL; +X } +X if (((intobject *)w) -> ob_ival == 0) +X return err_zdiv(); +X return newintobject(v->ob_ival / ((intobject *)w) -> ob_ival); +X} +X +Xstatic object * +Xint_rem(v, w) +X intobject *v; +X register object *w; +X{ +X if (!is_intobject(w)) { +X err_badarg(); +X return NULL; +X } +X if (((intobject *)w) -> ob_ival == 0) +X return err_zdiv(); +X return newintobject(v->ob_ival % ((intobject *)w) -> ob_ival); +X} +X +Xstatic object * +Xint_pow(v, w) +X intobject *v; +X register object *w; +X{ +X register long iv, iw, ix; +X register int neg; +X if (!is_intobject(w)) { +X err_badarg(); +X return NULL; +X } +X iv = v->ob_ival; +X iw = ((intobject *)w)->ob_ival; +X neg = 0; +X if (iw < 0) +X neg = 1, iw = -iw; +X ix = 1; +X for (; iw > 0; iw--) +X ix = ix * iv; +X if (neg) { +X if (ix == 0) +X return err_zdiv(); +X ix = 1/ix; +X } +X /* XXX How to check for overflow? */ +X return newintobject(ix); +X} +X +Xstatic object * +Xint_neg(v) +X intobject *v; +X{ +X register long a, x; +X a = v->ob_ival; +X x = -a; +X if (a < 0 && x < 0) +X return err_ovf(); +X return newintobject(x); +X} +X +Xstatic object * +Xint_pos(v) +X intobject *v; +X{ +X INCREF(v); +X return (object *)v; +X} +X +Xstatic number_methods int_as_number = { +X int_add, /*tp_add*/ +X int_sub, /*tp_subtract*/ +X int_mul, /*tp_multiply*/ +X int_div, /*tp_divide*/ +X int_rem, /*tp_remainder*/ +X int_pow, /*tp_power*/ +X int_neg, /*tp_negate*/ +X int_pos, /*tp_plus*/ +X}; +X +Xtypeobject Inttype = { +X OB_HEAD_INIT(&Typetype) +X 0, +X "int", +X sizeof(intobject), +X 0, +X int_dealloc, /*tp_dealloc*/ +X int_print, /*tp_print*/ +X 0, /*tp_getattr*/ +X 0, /*tp_setattr*/ +X int_compare, /*tp_compare*/ +X int_repr, /*tp_repr*/ +X &int_as_number, /*tp_as_number*/ +X 0, /*tp_as_sequence*/ +X 0, /*tp_as_mapping*/ +X}; +EOF +fi +echo 'Part 13 out of 21 of pack.out complete.' +exit 0 diff --git a/shar/python-0.9.1-14-21.shar b/shar/python-0.9.1-14-21.shar new file mode 100644 index 0000000..c819377 --- /dev/null +++ b/shar/python-0.9.1-14-21.shar @@ -0,0 +1,2720 @@ +: This is a shell archive. +: Extract with 'sh this_file'. +: +: Extract part 01 first since it makes all directories +echo 'Start of pack.out, part 14 out of 21:' +if test -s 'demo/sgi/audio_stdwin/rec.py' +then echo '*** I will not over-write existing file demo/sgi/audio_stdwin/rec.py' +else +echo 'x - demo/sgi/audio_stdwin/rec.py' +sed 's/^X//' > 'demo/sgi/audio_stdwin/rec.py' << 'EOF' +X#! /ufs/guido/bin/sgi/python +X +Ximport sys +Ximport audio +Ximport stdwin +X +Ximport string +Ximport getopt +X +Xfrom stdwinevents import * +Xfrom Buttons import * +Xfrom Sliders import * +X#from Soundogram import Soundogram +Xfrom VUMeter import VUMeter +Xfrom WindowParent import WindowParent +Xfrom HVSplit import HSplit, VSplit +X +Xclass TimeOutToggleButton() = ToggleButton(): +X def define(self, parent): +X self = ToggleButton.define(self, parent) +X self.parent.need_timer(self) +X self.timer_hook = 0 +X return self +X def timer(self): +X if self.timer_hook: +X self.timer_hook(self) +X +XK = 1024 +XBUFSIZE = 30*8*K +XRates = [0, 32*K, 16*K, 8*K] +XMagics = ['', '0032', '0016', '0008'] +X +Xclass Struct(): pass +XG = Struct() +X +Xdef main(): +X # +X # Set default state +X # +X G.gain = 60 +X G.rate = 3 +X G.nomuting = 0 +X G.savefile = '@rec' +X # +X # Set default values +X # +X G.data = '' +X G.playing = 0 +X G.recording = 0 +X G.sogram = 0 +X # +X # Parse options +X # +X optlist, args = getopt.getopt(sys.argv[1:], 'mdg:r:') +X # +X for optname, optarg in optlist: +X if 0: # (So all cases start with elif) +X pass +X elif optname = '-d': +X G.debug = 1 +X elif optname = '-g': +X G.gain = string.atoi(optarg) +X if not (0 < G.gain < 256): +X raise optarg.error, '-g gain out of range' +X elif optname = '-m': +X G.nomuting = (not G.nomuting) +X elif optname = '-r': +X G.rate = string.atoi(optarg) +X if not (1 <= G.rate <= 3): +X raise optarg.error, '-r rate out of range' +X # +X if args: +X G.savefile = args[0] +X # +X # Initialize the sound package +X # +X audio.setoutgain(G.nomuting * G.gain) # Silence the speaker +X audio.setrate(G.rate) +X # +X # Create the WindowParent and VSplit +X # +X G.window = WindowParent().create('Recorder', (0, 0)) +X w = G.vsplit = VSplit().create(G.window) +X # +X # VU-meter +X # +X G.vubtn = VUMeter().define(w) +X # +X # Radiobuttons for rates +X # +X r1btn = RadioButton().definetext(w, '32 K/sec') +X r1btn.on_hook = rate_hook +X r1btn.rate = 1 +X # +X r2btn = RadioButton().definetext(w, '16 K/sec') +X r2btn.on_hook = rate_hook +X r2btn.rate = 2 +X # +X r3btn = RadioButton().definetext(w, '8 K/sec') +X r3btn.on_hook = rate_hook +X r3btn.rate = 3 +X # +X radios = [r1btn, r2btn, r3btn] +X r1btn.group = r2btn.group = r3btn.group = radios +X for r in radios: +X if r.rate = G.rate: r.select(1) +X # +X # Other controls +X # +X G.recbtn = TimeOutToggleButton().definetext(w, 'Record') +X G.recbtn.on_hook = record_on_hook +X G.recbtn.timer_hook = record_timer_hook +X G.recbtn.off_hook = record_off_hook +X # +X G.mutebtn = CheckButton().definetext(w, 'Mute') +X G.mutebtn.select(not G.nomuting) +X G.mutebtn.hook = mute_hook +X # +X G.playbtn = TimeOutToggleButton().definetext(w, 'Playback') +X G.playbtn.on_hook = play_on_hook +X G.playbtn.timer_hook = play_timer_hook +X G.playbtn.off_hook = play_off_hook +X # +X G.gainbtn = ComplexSlider().define(w) +X G.gainbtn.settexts(' Volume: ', ' ') +X G.gainbtn.setminvalmax(0, G.gain, 255) +X G.gainbtn.sethook(gain_hook) +X # +X G.sizebtn = Label().definetext(w, `len(G.data)` + ' bytes') +X # +X #G.showbtn = PushButton().definetext(w, 'Sound-o-gram...') +X #G.showbtn.hook = show_hook +X # +X G.savebtn = PushButton().definetext(w, 'Save...') +X G.savebtn.hook = save_hook +X # +X G.quitbtn = PushButton().definetext(w, 'Quit') +X G.quitbtn.hook = quit_hook +X G.playbtn.enable(0) +X G.savebtn.enable(0) +X #G.showbtn.enable(0) +X start_vu() +X G.window.realize() +X # +X # Event loop +X # +X while 1: +X e = stdwin.getevent() +X G.window.dispatch(e) +X +X# XXX Disabled... +Xdef show_hook(self): +X savetext = self.text +X self.settext('Be patient...') +X close_sogram() +X stdwin.setdefwinsize(400, 300) +X win = stdwin.open('Sound-o-gram') +X G.sogram = Soundogram().define(win, G.data) +X win.buttons = [G.sogram] +X self.settext(savetext) +X +Xdef close_sogram(): +X if G.sogram: +X # Break circular references +X G.sogram.win.buttons[:] = [] +X del G.sogram.win +X G.sogram = 0 +X +Xdef mute_hook(self): +X G.nomuting = (not self.selected) +X audio.setoutgain(G.nomuting * G.gain) +X +Xdef rate_hook(self): +X G.rate = self.rate +X audio.setrate(G.rate) +X +Xdef record_on_hook(self): +X stop_vu() +X close_sogram() +X audio.setrate(G.rate) +X audio.setoutgain(G.nomuting * G.gain) +X audio.start_recording(BUFSIZE) +X G.recording = 1 +X G.playbtn.enable(0) +X G.window.settimer(10 * BUFSIZE / Rates[G.rate]) +X +Xdef record_timer_hook(self): +X if G.recording: +X if audio.poll_recording(): +X self.hilite(0) +X record_off_hook(self) +X else: +X self.parent.settimer(5) +X +Xdef record_off_hook(self): +X if not G.recording: +X return +X G.data = audio.stop_recording() +X G.recording = 0 +X G.sizebtn.settext(`len(G.data)` + ' bytes') +X audio.setoutgain(G.nomuting * G.gain) +X G.playbtn.enable((len(G.data) > 0)) +X G.savebtn.enable((len(G.data) > 0)) +X #G.showbtn.enable((len(G.data) > 0)) +X G.window.settimer(0) +X start_vu() +X +Xdef play_on_hook(self): +X stop_vu() +X audio.setrate(G.rate) +X audio.setoutgain(G.gain) +X audio.start_playing(G.data) +X G.playing = 1 +X G.recbtn.enable(0) +X G.window.settimer(max(10 * len(G.data) / Rates[G.rate], 1)) +X +Xdef play_timer_hook(self): +X if G.playing: +X if audio.poll_playing(): +X self.hilite(0) +X play_off_hook(self) +X else: +X self.parent.settimer(5) +X +Xdef play_off_hook(self): +X if not G.playing: +X return +X x = audio.stop_playing() +X G.playing = 0 +X audio.setoutgain(G.nomuting * G.gain) +X G.recbtn.enable(1) +X G.window.settimer(0) +X start_vu() +X +Xdef gain_hook(self): +X G.gain = self.val +X if G.playing or G.nomuting: audio.setoutgain(G.gain) +X +Xdef save_hook(self): +X if not G.data: +X stdwin.fleep() +X else: +X prompt = 'Store sampled data on file: ' +X try: +X G.savefile = stdwin.askfile(prompt, G.savefile, 1) +X except KeyboardInterrupt: +X return +X try: +X fp = open(G.savefile, 'w') +X fp.write(Magics[G.rate] + G.data) +X except: +X stdwin.message('Cannot create ' + file) +X +Xdef stop_vu(): +X G.vubtn.stop() +X +Xdef start_vu(): +X G.vubtn.start() +X +XExit = 'exit' # exception +X +Xdef quit_hook(self): +X raise Exit, 0 +X +Xtry: +X try: +X main() +X finally: +X audio.setoutgain(0) +Xexcept Exit, sts: +X sys.exit(sts) +EOF +chmod +x 'demo/sgi/audio_stdwin/rec.py' +fi +if test -s 'lib/TclShell.py' +then echo '*** I will not over-write existing file lib/TclShell.py' +else +echo 'x - lib/TclShell.py' +sed 's/^X//' > 'lib/TclShell.py' << 'EOF' +X# Tcl-based shell (for the Macintosh) +X +Ximport TclUtil +Ximport Tcl +Xfrom Tcl import Interpreter, TclRuntimeError +Ximport mac +Ximport macpath +Xfrom macpath import isfile, isdir, exists +X +XUsageError = TclRuntimeError +X +Xclass ShellInterpreter() = Interpreter(): +X # +X def ResetVariables(interp): +X interp.globals['ps1'] = '$ ' +X interp.globals['ps2'] = '> ' +X interp.globals['home'] = mac.getcwd() +X # +X def DefineCommands(interp): +X interp.commands['cd'] = interp.CdCmd +X interp.commands['grep'] = interp.GrepCmd +X interp.commands['ls'] = interp.LsCmd +X interp.commands['mkdir'] = interp.MkdirCmd +X interp.commands['mv'] = interp.MvCmd +X interp.commands['pg'] = interp.PgCmd +X interp.commands['pwd'] = interp.PwdCmd +X interp.commands['rm'] = interp.RmCmd +X interp.commands['rmdir'] = interp.RmdirCmd +X interp.commands['sync'] = interp.SyncCmd +X # +X def Reset(interp): +X interp.ResetVariables() +X interp.DefineCommands() +X # +X def Create(interp): +X interp = Interpreter.Create(interp) # initialize base class +X interp.Reset() +X return interp +X # +X # Command-implementing functions +X # +X def CdCmd(interp, argv): +X if len(argv) > 2: +X raise UsageError, 'usage: cd [dirname]' +X if len(argv) = 2: +X chdirto(argv[1]) +X else: +X chdirto(interp.globals['home']) +X return '' +X # +X def GrepCmd(interp, argv): +X if len(argv) < 3: +X raise UsageError, 'usage: grep regexp file ...' +X import regexp +X try: +X prog = regexp.compile(argv[1]) +X except regexp.error, msg: +X raise TclRuntimeError, \ +X ('grep', argv[1], ': bad regexp :', msg) +X for file in argv[2:]: +X grepfile(prog, file) +X return '' +X # +X def LsCmd(interp, argv): +X if len(argv) < 2: +X lsdir(':') +X else: +X for dirname in argv[1:]: +X lsdir(dirname) +X return '' +X # +X def MkdirCmd(interp, argv): +X if len(argv) < 2: +X raise UsageError, 'usage: mkdir name ...' +X for name in argv[1:]: +X makedir(name) +X return '' +X # +X def MvCmd(interp, argv): +X if len(argv) <> 3: +X raise UsageError, 'usage: mv src dst' +X src, dst = argv[1], argv[2] +X if not exists(src): +X raise TclRuntimeError, \ +X ('mv', src, dst, ': source does not exist') +X if exists(dst): +X raise TclRuntimeError, \ +X ('mv', src, dst, ': destination already exists') +X try: +X mac.rename(src, dst) +X except mac.error, msg: +X raise TclRuntimeError, \ +X (src, dst, ': rename failed :', msg) +X return '' +X # +X def PgCmd(interp, argv): +X if len(argv) < 2: +X raise UsageError, 'usage: page file ...' +X for name in argv[1:]: +X pagefile(name) +X return '' +X # +X def PwdCmd(interp, argv): +X if len(argv) > 1: +X raise UsageError, 'usage: pwd' +X else: +X return mac.getcwd() +X # +X def RmCmd(interp, argv): +X if len(argv) < 2: +X raise UsageError, 'usage: rm file ...' +X for name in argv[1:]: +X remove(name) +X return '' +X # +X def RmdirCmd(interp, argv): +X if len(argv) < 2: +X raise UsageError, 'usage: rmdir dir ...' +X for name in argv[1:]: +X rmdir(name) +X return '' +X # +X def SyncCmd(interp, argv): +X if len(argv) > 1: +X raise UsageError, 'usage: sync' +X try: +X mac.sync() +X except mac.error, msg: +X raise TclRuntimeError, ('sync failed :', msg) +X # +X +Xdef chdirto(dirname): +X try: +X mac.chdir(dirname) +X except mac.error, msg: +X raise TclRuntimeError, (dirname, ': chdir failed :', msg) +X +Xdef grepfile(prog, file): +X try: +X fp = open(file, 'r') +X except RuntimeError, msg: +X raise TclRuntimeError, (file, ': open failed :', msg) +X lineno = 0 +X while 1: +X line = fp.readline() +X if not line: break +X lineno = lineno+1 +X if prog.exec(line): +X print file+'('+`lineno`+'):', line, +X +Xdef lsdir(dirname): +X if not isdir(dirname): +X print dirname, ': no such directory' +X return +X names = mac.listdir(dirname) +X lsfiles(names, dirname) +X +Xdef lsfiles(names, dirname): +X names = names[:] # Make a copy so we can modify it +X for i in range(len(names)): +X name = names[i] +X if isdir(macpath.cat(dirname, name)): +X names[i] = ':' + name + ':' +X columnize(names) +X +Xdef makedir(name): +X if exists(name): +X print name, ': already exists' +X return +X try: +X mac.mkdir(name, 0777) +X except mac.error, msg: +X raise TclRuntimeError, (name, ': mkdir failed :', msg) +X +Xdef pagefile(name): +X import string +X if not isfile(name): +X print name, ': no such file' +X return +X LINES = 24 - 1 +X # For THINK C 3.0, make the path absolute: +X # if not macpath.isabs(name): +X # name = macpath.cat(mac.getcwd(), name) +X try: +X fp = open(name, 'r') +X except RuntimeError, msg: +X raise TclRuntimeError, (name, ': open failed :', msg) +X line = fp.readline() +X while line: +X for i in range(LINES): +X print line, +X line = fp.readline() +X if not line: break +X if line: +X try: +X more = raw_input('[more]') +X except (EOFError, KeyboardInterrupt): +X print +X break +X if string.strip(more)[:1] in ('q', 'Q'): +X break +X +Xdef remove(name): +X if not isfile(name): +X print name, ': no such file' +X return +X try: +X mac.unlink(name) +X except mac.error, msg: +X raise TclRuntimeError, (name, ': unlink failed :', msg) +X +Xdef rmdir(name): +X if not isdir(name): +X raise TclRuntimeError, (name, ': no such directory') +X try: +X mac.rmdir(name) +X except mac.error, msg: +X raise TclRuntimeError, (name, ': rmdir failed :', msg) +X +Xdef printlist(list): +X for word in list: +X print word, +X +Xdef columnize(list): +X import string +X COLUMNS = 80-1 +X n = len(list) +X colwidth = maxwidth(list) +X ncols = (COLUMNS + 1) / (colwidth + 1) +X if ncols < 1: ncols = 1 +X nrows = (n + ncols - 1) / ncols +X for irow in range(nrows): +X line = '' +X for icol in range(ncols): +X i = irow + nrows*icol +X if 0 <= i < n: +X word = list[i] +X if i+nrows < n: +X word = string.ljust(word, colwidth) +X if icol > 0: +X word = ' ' + word +X line = line + word +X print line +X +Xdef maxwidth(list): +X width = 0 +X for word in list: +X if len(word) > width: +X width = len(word) +X return width +X +Xthe_interpreter = ShellInterpreter().Create() +X +Xdef main(): +X Tcl.MainLoop(the_interpreter) +EOF +fi +if test -s 'lib/tablewin.py' +then echo '*** I will not over-write existing file lib/tablewin.py' +else +echo 'x - lib/tablewin.py' +sed 's/^X//' > 'lib/tablewin.py' << 'EOF' +X# Module 'tablewin' +X +X# Display a table, with per-item actions: +X +X# A1 | A2 | A3 | .... | AN +X# B1 | B2 | B3 | .... | BN +X# C1 | C2 | C3 | .... | CN +X# .. | .. | .. | .... | .. +X# Z1 | Z2 | Z3 | .... | ZN +X +X# Not all columns need to have the same length. +X# The data structure is a list of columns; +X# each column is a list of items. +X# Each item is a pair of a string and an action procedure. +X# The first item may be a column title. +X +Ximport stdwin +Ximport gwin +X +Xdef open(title, data): # Public function to open a table window +X # +X # Set geometry parameters (one day, these may be changeable) +X # +X margin = stdwin.textwidth(' ') +X lineheight = stdwin.lineheight() +X # +X # Geometry calculations +X # +X colstarts = [0] +X totwidth = 0 +X maxrows = 0 +X for coldata in data: +X # Height calculations +X rows = len(coldata) +X if rows > maxrows: maxrows = rows +X # Width calculations +X width = colwidth(coldata) + margin +X totwidth = totwidth + width +X colstarts.append(totwidth) +X # +X # Calculate document and window height +X # +X docwidth, docheight = totwidth, maxrows*lineheight +X winwidth, winheight = docwidth, docheight +X if winwidth > stdwin.textwidth('n')*100: winwidth = 0 +X if winheight > stdwin.lineheight()*30: winheight = 0 +X # +X # Create the window +X # +X stdwin.setdefwinsize(winwidth, winheight) +X w = gwin.open(title) +X # +X # Set properties and override methods +X # +X w.data = data +X w.margin = margin +X w.lineheight = lineheight +X w.colstarts = colstarts +X w.totwidth = totwidth +X w.maxrows = maxrows +X w.selection = (-1, -1) +X w.lastselection = (-1, -1) +X w.selshown = 0 +X w.setdocsize(docwidth, docheight) +X w.draw = draw +X w.mup = mup +X w.arrow = arrow +X # +X # Return +X # +X return w +X +Xdef update(w, data): # Change the data +X # +X # Hide selection +X # +X hidesel(w, w.begindrawing()) +X # +X # Get old geometry parameters +X # +X margin = w.margin +X lineheight = w.lineheight +X # +X # Geometry calculations +X # +X colstarts = [0] +X totwidth = 0 +X maxrows = 0 +X for coldata in data: +X # Height calculations +X rows = len(coldata) +X if rows > maxrows: maxrows = rows +X # Width calculations +X width = colwidth(coldata) + margin +X totwidth = totwidth + width +X colstarts.append(totwidth) +X # +X # Calculate document and window height +X # +X docwidth, docheight = totwidth, maxrows*lineheight +X # +X # Set changed properties and change window size +X # +X w.data = data +X w.colstarts = colstarts +X w.totwidth = totwidth +X w.maxrows = maxrows +X w.change((0, 0), (10000, 10000)) +X w.setdocsize(docwidth, docheight) +X w.change((0, 0), (docwidth, docheight)) +X # +X # Show selection, or forget it if out of range +X # +X showsel(w, w.begindrawing()) +X if not w.selshown: w.selection = (-1, -1) +X +Xdef colwidth(coldata): # Subroutine to calculate column width +X maxwidth = 0 +X for string, action in coldata: +X width = stdwin.textwidth(string) +X if width > maxwidth: maxwidth = width +X return maxwidth +X +Xdef draw(w, ((left, top), (right, bottom))): # Draw method +X ileft = whichcol(w, left) +X iright = whichcol(w, right-1) + 1 +X if iright > len(w.data): iright = len(w.data) +X itop = divmod(top, w.lineheight)[0] +X if itop < 0: itop = 0 +X ibottom, remainder = divmod(bottom, w.lineheight) +X if remainder: ibottom = ibottom + 1 +X d = w.begindrawing() +X if ileft <= w.selection[0] < iright: +X if itop <= w.selection[1] < ibottom: +X hidesel(w, d) +X d.erase((left, top), (right, bottom)) +X for i in range(ileft, iright): +X col = w.data[i] +X jbottom = len(col) +X if ibottom < jbottom: jbottom = ibottom +X h = w.colstarts[i] +X v = itop * w.lineheight +X for j in range(itop, jbottom): +X string, action = col[j] +X d.text((h, v), string) +X v = v + w.lineheight +X showsel(w, d) +X +Xdef mup(w, detail): # Mouse up method +X (h, v), nclicks, button, mask = detail +X icol = whichcol(w, h) +X if 0 <= icol < len(w.data): +X irow = divmod(v, w.lineheight)[0] +X col = w.data[icol] +X if 0 <= irow < len(col): +X string, action = col[irow] +X action(w, string, (icol, irow), detail) +X +Xdef whichcol(w, h): # Return column number (may be >= len(w.data)) +X for icol in range(0, len(w.data)): +X if h < w.colstarts[icol+1]: +X return icol +X return len(w.data) +X +Xdef arrow(w, type): +X import stdwinsupport +X S = stdwinsupport +X if type = S.wc_left: +X incr = -1, 0 +X elif type = S.wc_up: +X incr = 0, -1 +X elif type = S.wc_right: +X incr = 1, 0 +X elif type = S.wc_down: +X incr = 0, 1 +X else: +X return +X icol, irow = w.lastselection +X icol = icol + incr[0] +X if icol < 0: icol = len(w.data)-1 +X if icol >= len(w.data): icol = 0 +X if 0 <= icol < len(w.data): +X irow = irow + incr[1] +X if irow < 0: irow = len(w.data[icol]) - 1 +X if irow >= len(w.data[icol]): irow = 0 +X else: +X irow = 0 +X if 0 <= icol < len(w.data) and 0 <= irow < len(w.data[icol]): +X w.lastselection = icol, irow +X string, action = w.data[icol][irow] +X detail = (0, 0), 1, 1, 1 +X action(w, string, (icol, irow), detail) +X +X +X# Selection management +X# TO DO: allow multiple selected entries +X +Xdef select(w, selection): # Public function to set the item selection +X d = w.begindrawing() +X hidesel(w, d) +X w.selection = selection +X showsel(w, d) +X if w.selshown: lastselection = selection +X +Xdef hidesel(w, d): # Hide the selection, if shown +X if w.selshown: invertsel(w, d) +X +Xdef showsel(w, d): # Show the selection, if hidden +X if not w.selshown: invertsel(w, d) +X +Xdef invertsel(w, d): # Invert the selection, if valid +X icol, irow = w.selection +X if 0 <= icol < len(w.data) and 0 <= irow < len(w.data[icol]): +X left = w.colstarts[icol] +X right = w.colstarts[icol+1] +X top = irow * w.lineheight +X bottom = (irow+1) * w.lineheight +X d.invert((left, top), (right, bottom)) +X w.selshown = (not w.selshown) +X +X +X# Demonstration +X +Xdef demo_action(w, string, (icol, irow), detail): # Action function for demo +X select(w, (irow, icol)) +X +Xdef demo(): # Demonstration +X da = demo_action # shorthand +X col0 = [('a1', da), ('bbb1', da), ('c1', da)] +X col1 = [('a2', da), ('bbb2', da)] +X col2 = [('a3', da), ('b3', da), ('c3', da), ('d4', da), ('d5', da)] +X col3 = [] +X for i in range(1, 31): col3.append('xxx' + `i`, da) +X data = [col0, col1, col2, col3] +X w = open('tablewin.demo', data) +X gwin.mainloop() +X return w +EOF +fi +if test -s 'src/fileobject.c' +then echo '*** I will not over-write existing file src/fileobject.c' +else +echo 'x - src/fileobject.c' +sed 's/^X//' > 'src/fileobject.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* File object implementation */ +X +X/* XXX This should become a built-in module 'io'. It should support more +X functionality, better exception handling for invalid calls, etc. +X (Especially reading on a write-only file or vice versa!) +X It should also cooperate with posix to support popen(), which should +X share most code but have a special close function. */ +X +X#include "allobjects.h" +X +X#include "errno.h" +X#ifndef errno +Xextern int errno; +X#endif +X +Xtypedef struct { +X OB_HEAD +X FILE *f_fp; +X object *f_name; +X object *f_mode; +X /* XXX Should move the 'need space' on printing flag here */ +X} fileobject; +X +XFILE * +Xgetfilefile(f) +X object *f; +X{ +X if (!is_fileobject(f)) { +X err_badcall(); +X return NULL; +X } +X return ((fileobject *)f)->f_fp; +X} +X +Xobject * +Xnewopenfileobject(fp, name, mode) +X FILE *fp; +X char *name; +X char *mode; +X{ +X fileobject *f = NEWOBJ(fileobject, &Filetype); +X if (f == NULL) +X return NULL; +X f->f_fp = NULL; +X f->f_name = newstringobject(name); +X f->f_mode = newstringobject(mode); +X if (f->f_name == NULL || f->f_mode == NULL) { +X DECREF(f); +X return NULL; +X } +X f->f_fp = fp; +X return (object *) f; +X} +X +Xobject * +Xnewfileobject(name, mode) +X char *name, *mode; +X{ +X fileobject *f; +X FILE *fp; +X f = (fileobject *) newopenfileobject((FILE *)NULL, name, mode); +X if (f == NULL) +X return NULL; +X#ifdef THINK_C +X if (*mode == '*') { +X FILE *fopenRF(); +X f->f_fp = fopenRF(name, mode+1); +X } +X else +X#endif +X f->f_fp = fopen(name, mode); +X if (f->f_fp == NULL) { +X err_errno(RuntimeError); +X DECREF(f); +X return NULL; +X } +X return (object *)f; +X} +X +X/* Methods */ +X +Xstatic void +Xfile_dealloc(f) +X fileobject *f; +X{ +X if (f->f_fp != NULL) +X fclose(f->f_fp); +X if (f->f_name != NULL) +X DECREF(f->f_name); +X if (f->f_mode != NULL) +X DECREF(f->f_mode); +X free((char *)f); +X} +X +Xstatic void +Xfile_print(f, fp, flags) +X fileobject *f; +X FILE *fp; +X int flags; +X{ +X fprintf(fp, "<%s file ", f->f_fp == NULL ? "closed" : "open"); +X printobject(f->f_name, fp, flags); +X fprintf(fp, ", mode "); +X printobject(f->f_mode, fp, flags); +X fprintf(fp, ">"); +X} +X +Xstatic object * +Xfile_repr(f) +X fileobject *f; +X{ +X char buf[300]; +X /* XXX This differs from file_print if the filename contains +X quotes or other funny characters. */ +X sprintf(buf, "<%s file '%.256s', mode '%.10s'>", +X f->f_fp == NULL ? "closed" : "open", +X getstringvalue(f->f_name), +X getstringvalue(f->f_mode)); +X return newstringobject(buf); +X} +X +Xstatic object * +Xfile_close(f, args) +X fileobject *f; +X object *args; +X{ +X if (args != NULL) { +X err_badarg(); +X return NULL; +X } +X if (f->f_fp != NULL) { +X fclose(f->f_fp); +X f->f_fp = NULL; +X } +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xfile_read(f, args) +X fileobject *f; +X object *args; +X{ +X int n; +X object *v; +X if (f->f_fp == NULL) { +X err_badarg(); +X return NULL; +X } +X if (args == NULL || !is_intobject(args)) { +X err_badarg(); +X return NULL; +X } +X n = getintvalue(args); +X if (n < 0) { +X err_badarg(); +X return NULL; +X } +X v = newsizedstringobject((char *)NULL, n); +X if (v == NULL) +X return NULL; +X n = fread(getstringvalue(v), 1, n, f->f_fp); +X /* EOF is reported as an empty string */ +X /* XXX should detect real I/O errors? */ +X resizestring(&v, n); +X return v; +X} +X +X/* XXX Should this be unified with raw_input()? */ +X +Xstatic object * +Xfile_readline(f, args) +X fileobject *f; +X object *args; +X{ +X int n; +X object *v; +X if (f->f_fp == NULL) { +X err_badarg(); +X return NULL; +X } +X if (args == NULL) { +X n = 10000; /* XXX should really be unlimited */ +X } +X else if (is_intobject(args)) { +X n = getintvalue(args); +X if (n < 0) { +X err_badarg(); +X return NULL; +X } +X } +X else { +X err_badarg(); +X return NULL; +X } +X v = newsizedstringobject((char *)NULL, n); +X if (v == NULL) +X return NULL; +X#ifndef THINK_C_3_0 +X /* XXX Think C 3.0 wrongly reads up to n characters... */ +X n = n+1; +X#endif +X if (fgets(getstringvalue(v), n, f->f_fp) == NULL) { +X /* EOF is reported as an empty string */ +X /* XXX should detect real I/O errors? */ +X n = 0; +X } +X else { +X n = strlen(getstringvalue(v)); +X } +X resizestring(&v, n); +X return v; +X} +X +Xstatic object * +Xfile_write(f, args) +X fileobject *f; +X object *args; +X{ +X int n, n2; +X if (f->f_fp == NULL) { +X err_badarg(); +X return NULL; +X } +X if (args == NULL || !is_stringobject(args)) { +X err_badarg(); +X return NULL; +X } +X errno = 0; +X n2 = fwrite(getstringvalue(args), 1, n = getstringsize(args), f->f_fp); +X if (n2 != n) { +X if (errno == 0) +X errno = EIO; +X err_errno(RuntimeError); +X return NULL; +X } +X INCREF(None); +X return None; +X} +X +Xstatic struct methodlist file_methods[] = { +X {"write", file_write}, +X {"read", file_read}, +X {"readline", file_readline}, +X {"close", file_close}, +X {NULL, NULL} /* sentinel */ +X}; +X +Xstatic object * +Xfile_getattr(f, name) +X fileobject *f; +X char *name; +X{ +X return findmethod(file_methods, (object *)f, name); +X} +X +Xtypeobject Filetype = { +X OB_HEAD_INIT(&Typetype) +X 0, +X "file", +X sizeof(fileobject), +X 0, +X file_dealloc, /*tp_dealloc*/ +X file_print, /*tp_print*/ +X file_getattr, /*tp_getattr*/ +X 0, /*tp_setattr*/ +X 0, /*tp_compare*/ +X file_repr, /*tp_repr*/ +X}; +EOF +fi +if test -s 'src/floatobject.c' +then echo '*** I will not over-write existing file src/floatobject.c' +else +echo 'x - src/floatobject.c' +sed 's/^X//' > 'src/floatobject.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Float object implementation */ +X +X/* XXX There should be overflow checks here, but it's hard to check +X for any kind of float exception without losing portability. */ +X +X#include "allobjects.h" +X +X#include <errno.h> +X#ifndef errno +Xextern int errno; +X#endif +X +X#include <ctype.h> +X#include <math.h> +X +X#ifndef THINK_C +Xextern double fmod PROTO((double, double)); +Xextern double pow PROTO((double, double)); +X#endif +X +Xobject * +Xnewfloatobject(fval) +X double fval; +X{ +X /* For efficiency, this code is copied from newobject() */ +X register floatobject *op = (floatobject *) malloc(sizeof(floatobject)); +X if (op == NULL) +X return err_nomem(); +X NEWREF(op); +X op->ob_type = &Floattype; +X op->ob_fval = fval; +X return (object *) op; +X} +X +Xdouble +Xgetfloatvalue(op) +X object *op; +X{ +X if (!is_floatobject(op)) { +X err_badarg(); +X return -1; +X } +X else +X return ((floatobject *)op) -> ob_fval; +X} +X +X/* Methods */ +X +Xstatic void +Xfloat_buf_repr(buf, v) +X char *buf; +X floatobject *v; +X{ +X register char *cp; +X /* Subroutine for float_repr and float_print. +X We want float numbers to be recognizable as such, +X i.e., they should contain a decimal point or an exponent. +X However, %g may print the number as an integer; +X in such cases, we append ".0" to the string. */ +X sprintf(buf, "%.12g", v->ob_fval); +X cp = buf; +X if (*cp == '-') +X cp++; +X for (; *cp != '\0'; cp++) { +X /* Any non-digit means it's not an integer; +X this takes care of NAN and INF as well. */ +X if (!isdigit(*cp)) +X break; +X } +X if (*cp == '\0') { +X *cp++ = '.'; +X *cp++ = '0'; +X *cp++ = '\0'; +X } +X} +X +Xstatic void +Xfloat_print(v, fp, flags) +X floatobject *v; +X FILE *fp; +X int flags; +X{ +X char buf[100]; +X float_buf_repr(buf, v); +X fputs(buf, fp); +X} +X +Xstatic object * +Xfloat_repr(v) +X floatobject *v; +X{ +X char buf[100]; +X float_buf_repr(buf, v); +X return newstringobject(buf); +X} +X +Xstatic int +Xfloat_compare(v, w) +X floatobject *v, *w; +X{ +X double i = v->ob_fval; +X double j = w->ob_fval; +X return (i < j) ? -1 : (i > j) ? 1 : 0; +X} +X +Xstatic object * +Xfloat_add(v, w) +X floatobject *v; +X object *w; +X{ +X if (!is_floatobject(w)) { +X err_badarg(); +X return NULL; +X } +X return newfloatobject(v->ob_fval + ((floatobject *)w) -> ob_fval); +X} +X +Xstatic object * +Xfloat_sub(v, w) +X floatobject *v; +X object *w; +X{ +X if (!is_floatobject(w)) { +X err_badarg(); +X return NULL; +X } +X return newfloatobject(v->ob_fval - ((floatobject *)w) -> ob_fval); +X} +X +Xstatic object * +Xfloat_mul(v, w) +X floatobject *v; +X object *w; +X{ +X if (!is_floatobject(w)) { +X err_badarg(); +X return NULL; +X } +X return newfloatobject(v->ob_fval * ((floatobject *)w) -> ob_fval); +X} +X +Xstatic object * +Xfloat_div(v, w) +X floatobject *v; +X object *w; +X{ +X if (!is_floatobject(w)) { +X err_badarg(); +X return NULL; +X } +X if (((floatobject *)w) -> ob_fval == 0) { +X err_setstr(ZeroDivisionError, "float division by zero"); +X return NULL; +X } +X return newfloatobject(v->ob_fval / ((floatobject *)w) -> ob_fval); +X} +X +Xstatic object * +Xfloat_rem(v, w) +X floatobject *v; +X object *w; +X{ +X double wx; +X if (!is_floatobject(w)) { +X err_badarg(); +X return NULL; +X } +X wx = ((floatobject *)w) -> ob_fval; +X if (wx == 0.0) { +X err_setstr(ZeroDivisionError, "float division by zero"); +X return NULL; +X } +X return newfloatobject(fmod(v->ob_fval, wx)); +X} +X +Xstatic object * +Xfloat_pow(v, w) +X floatobject *v; +X object *w; +X{ +X double iv, iw, ix; +X if (!is_floatobject(w)) { +X err_badarg(); +X return NULL; +X } +X iv = v->ob_fval; +X iw = ((floatobject *)w)->ob_fval; +X if (iw == 0.0) +X return newfloatobject(1.0); /* x**0 is always 1, even 0**0 */ +X errno = 0; +X ix = pow(iv, iw); +X if (errno != 0) { +X /* XXX could it be another type of error? */ +X err_errno(OverflowError); +X return NULL; +X } +X return newfloatobject(ix); +X} +X +Xstatic object * +Xfloat_neg(v) +X floatobject *v; +X{ +X return newfloatobject(-v->ob_fval); +X} +X +Xstatic object * +Xfloat_pos(v) +X floatobject *v; +X{ +X return newfloatobject(v->ob_fval); +X} +X +Xstatic number_methods float_as_number = { +X float_add, /*tp_add*/ +X float_sub, /*tp_subtract*/ +X float_mul, /*tp_multiply*/ +X float_div, /*tp_divide*/ +X float_rem, /*tp_remainder*/ +X float_pow, /*tp_power*/ +X float_neg, /*tp_negate*/ +X float_pos, /*tp_plus*/ +X}; +X +Xtypeobject Floattype = { +X OB_HEAD_INIT(&Typetype) +X 0, +X "float", +X sizeof(floatobject), +X 0, +X free, /*tp_dealloc*/ +X float_print, /*tp_print*/ +X 0, /*tp_getattr*/ +X 0, /*tp_setattr*/ +X float_compare, /*tp_compare*/ +X float_repr, /*tp_repr*/ +X &float_as_number, /*tp_as_number*/ +X 0, /*tp_as_sequence*/ +X 0, /*tp_as_mapping*/ +X}; +X +X/* +XXXX This is not enough. Need: +X- automatic casts for mixed arithmetic (3.1 * 4) +X- mixed comparisons (!) +X- look at other uses of ints that could be extended to floats +X*/ +EOF +fi +if test -s 'src/grammar.c' +then echo '*** I will not over-write existing file src/grammar.c' +else +echo 'x - src/grammar.c' +sed 's/^X//' > 'src/grammar.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Grammar implementation */ +X +X#include "pgenheaders.h" +X +X#include <ctype.h> +X +X#include "assert.h" +X#include "token.h" +X#include "grammar.h" +X +Xextern int debugging; +X +Xgrammar * +Xnewgrammar(start) +X int start; +X{ +X grammar *g; +X +X g = NEW(grammar, 1); +X if (g == NULL) +X fatal("no mem for new grammar"); +X g->g_ndfas = 0; +X g->g_dfa = NULL; +X g->g_start = start; +X g->g_ll.ll_nlabels = 0; +X g->g_ll.ll_label = NULL; +X return g; +X} +X +Xdfa * +Xadddfa(g, type, name) +X grammar *g; +X int type; +X char *name; +X{ +X dfa *d; +X +X RESIZE(g->g_dfa, dfa, g->g_ndfas + 1); +X if (g->g_dfa == NULL) +X fatal("no mem to resize dfa in adddfa"); +X d = &g->g_dfa[g->g_ndfas++]; +X d->d_type = type; +X d->d_name = name; +X d->d_nstates = 0; +X d->d_state = NULL; +X d->d_initial = -1; +X d->d_first = NULL; +X return d; /* Only use while fresh! */ +X} +X +Xint +Xaddstate(d) +X dfa *d; +X{ +X state *s; +X +X RESIZE(d->d_state, state, d->d_nstates + 1); +X if (d->d_state == NULL) +X fatal("no mem to resize state in addstate"); +X s = &d->d_state[d->d_nstates++]; +X s->s_narcs = 0; +X s->s_arc = NULL; +X return s - d->d_state; +X} +X +Xvoid +Xaddarc(d, from, to, lbl) +X dfa *d; +X int lbl; +X{ +X state *s; +X arc *a; +X +X assert(0 <= from && from < d->d_nstates); +X assert(0 <= to && to < d->d_nstates); +X +X s = &d->d_state[from]; +X RESIZE(s->s_arc, arc, s->s_narcs + 1); +X if (s->s_arc == NULL) +X fatal("no mem to resize arc list in addarc"); +X a = &s->s_arc[s->s_narcs++]; +X a->a_lbl = lbl; +X a->a_arrow = to; +X} +X +Xint +Xaddlabel(ll, type, str) +X labellist *ll; +X int type; +X char *str; +X{ +X int i; +X label *lb; +X +X for (i = 0; i < ll->ll_nlabels; i++) { +X if (ll->ll_label[i].lb_type == type && +X strcmp(ll->ll_label[i].lb_str, str) == 0) +X return i; +X } +X RESIZE(ll->ll_label, label, ll->ll_nlabels + 1); +X if (ll->ll_label == NULL) +X fatal("no mem to resize labellist in addlabel"); +X lb = &ll->ll_label[ll->ll_nlabels++]; +X lb->lb_type = type; +X lb->lb_str = str; /* XXX strdup(str) ??? */ +X return lb - ll->ll_label; +X} +X +X/* Same, but rather dies than adds */ +X +Xint +Xfindlabel(ll, type, str) +X labellist *ll; +X int type; +X char *str; +X{ +X int i; +X label *lb; +X +X for (i = 0; i < ll->ll_nlabels; i++) { +X if (ll->ll_label[i].lb_type == type /*&& +X strcmp(ll->ll_label[i].lb_str, str) == 0*/) +X return i; +X } +X fprintf(stderr, "Label %d/'%s' not found\n", type, str); +X abort(); +X} +X +X/* Forward */ +Xstatic void translabel PROTO((grammar *, label *)); +X +Xvoid +Xtranslatelabels(g) +X grammar *g; +X{ +X int i; +X +X printf("Translating labels ...\n"); +X /* Don't translate EMPTY */ +X for (i = EMPTY+1; i < g->g_ll.ll_nlabels; i++) +X translabel(g, &g->g_ll.ll_label[i]); +X} +X +Xstatic void +Xtranslabel(g, lb) +X grammar *g; +X label *lb; +X{ +X int i; +X +X if (debugging) +X printf("Translating label %s ...\n", labelrepr(lb)); +X +X if (lb->lb_type == NAME) { +X for (i = 0; i < g->g_ndfas; i++) { +X if (strcmp(lb->lb_str, g->g_dfa[i].d_name) == 0) { +X if (debugging) +X printf("Label %s is non-terminal %d.\n", +X lb->lb_str, +X g->g_dfa[i].d_type); +X lb->lb_type = g->g_dfa[i].d_type; +X lb->lb_str = NULL; +X return; +X } +X } +X for (i = 0; i < (int)N_TOKENS; i++) { +X if (strcmp(lb->lb_str, tok_name[i]) == 0) { +X if (debugging) +X printf("Label %s is terminal %d.\n", +X lb->lb_str, i); +X lb->lb_type = i; +X lb->lb_str = NULL; +X return; +X } +X } +X printf("Can't translate NAME label '%s'\n", lb->lb_str); +X return; +X } +X +X if (lb->lb_type == STRING) { +X if (isalpha(lb->lb_str[1])) { +X char *p, *strchr(); +X if (debugging) +X printf("Label %s is a keyword\n", lb->lb_str); +X lb->lb_type = NAME; +X lb->lb_str++; +X p = strchr(lb->lb_str, '\''); +X if (p) +X *p = '\0'; +X } +X else { +X if (lb->lb_str[2] == lb->lb_str[0]) { +X int type = (int) tok_1char(lb->lb_str[1]); +X if (type != OP) { +X lb->lb_type = type; +X lb->lb_str = NULL; +X } +X else +X printf("Unknown OP label %s\n", +X lb->lb_str); +X } +X else +X printf("Can't translate STRING label %s\n", +X lb->lb_str); +X } +X } +X else +X printf("Can't translate label '%s'\n", labelrepr(lb)); +X} +EOF +fi +if test -s 'src/import.c' +then echo '*** I will not over-write existing file src/import.c' +else +echo 'x - src/import.c' +sed 's/^X//' > 'src/import.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Module definition and import implementation */ +X +X#include "allobjects.h" +X +X#include "node.h" +X#include "token.h" +X#include "graminit.h" +X#include "import.h" +X#include "errcode.h" +X#include "sysmodule.h" +X#include "pythonrun.h" +X +X/* Define pathname separator used in file names */ +X +X#ifdef THINK_C +X#define SEP ':' +X#endif +X +X#ifndef SEP +X#define SEP '/' +X#endif +X +Xstatic object *modules; +X +X/* Initialization */ +X +Xvoid +Xinitimport() +X{ +X if ((modules = newdictobject()) == NULL) +X fatal("no mem for dictionary of modules"); +X} +X +Xobject * +Xget_modules() +X{ +X return modules; +X} +X +Xobject * +Xadd_module(name) +X char *name; +X{ +X object *m; +X if ((m = dictlookup(modules, name)) != NULL && is_moduleobject(m)) +X return m; +X m = newmoduleobject(name); +X if (m == NULL) +X return NULL; +X if (dictinsert(modules, name, m) != 0) { +X DECREF(m); +X return NULL; +X } +X DECREF(m); /* Yes, it still exists, in modules! */ +X return m; +X} +X +Xstatic FILE * +Xopen_module(name, suffix, namebuf) +X char *name; +X char *suffix; +X char *namebuf; /* XXX No buffer overflow checks! */ +X{ +X object *path; +X FILE *fp; +X +X path = sysget("path"); +X if (path == NULL || !is_listobject(path)) { +X strcpy(namebuf, name); +X strcat(namebuf, suffix); +X fp = fopen(namebuf, "r"); +X } +X else { +X int npath = getlistsize(path); +X int i; +X fp = NULL; +X for (i = 0; i < npath; i++) { +X object *v = getlistitem(path, i); +X int len; +X if (!is_stringobject(v)) +X continue; +X strcpy(namebuf, getstringvalue(v)); +X len = getstringsize(v); +X if (len > 0 && namebuf[len-1] != SEP) +X namebuf[len++] = SEP; +X strcpy(namebuf+len, name); +X strcat(namebuf, suffix); +X fp = fopen(namebuf, "r"); +X if (fp != NULL) +X break; +X } +X } +X return fp; +X} +X +Xstatic object * +Xget_module(m, name, m_ret) +X /*module*/object *m; +X char *name; +X object **m_ret; +X{ +X object *d; +X FILE *fp; +X node *n; +X int err; +X char namebuf[256]; +X +X fp = open_module(name, ".py", namebuf); +X if (fp == NULL) { +X if (m == NULL) +X err_setstr(NameError, name); +X else +X err_setstr(RuntimeError, "no module source file"); +X return NULL; +X } +X err = parse_file(fp, namebuf, file_input, &n); +X fclose(fp); +X if (err != E_DONE) { +X err_input(err); +X return NULL; +X } +X if (m == NULL) { +X m = add_module(name); +X if (m == NULL) { +X freetree(n); +X return NULL; +X } +X *m_ret = m; +X } +X d = getmoduledict(m); +X return run_node(n, namebuf, d, d); +X} +X +Xstatic object * +Xload_module(name) +X char *name; +X{ +X object *m, *v; +X v = get_module((object *)NULL, name, &m); +X if (v == NULL) +X return NULL; +X DECREF(v); +X return m; +X} +X +Xobject * +Ximport_module(name) +X char *name; +X{ +X object *m; +X if ((m = dictlookup(modules, name)) == NULL) { +X if (init_builtin(name)) { +X if ((m = dictlookup(modules, name)) == NULL) +X err_setstr(SystemError, "builtin module missing"); +X } +X else { +X m = load_module(name); +X } +X } +X return m; +X} +X +Xobject * +Xreload_module(m) +X object *m; +X{ +X if (m == NULL || !is_moduleobject(m)) { +X err_setstr(TypeError, "reload() argument must be module"); +X return NULL; +X } +X /* XXX Ought to check for builtin modules -- can't reload these... */ +X return get_module(m, getmodulename(m), (object **)NULL); +X} +X +Xstatic void +Xcleardict(d) +X object *d; +X{ +X int i; +X for (i = getdictsize(d); --i >= 0; ) { +X char *k; +X k = getdictkey(d, i); +X if (k != NULL) +X (void) dictremove(d, k); +X } +X} +X +Xvoid +Xdoneimport() +X{ +X if (modules != NULL) { +X int i; +X /* Explicitly erase all modules; this is the safest way +X to get rid of at least *some* circular dependencies */ +X for (i = getdictsize(modules); --i >= 0; ) { +X char *k; +X k = getdictkey(modules, i); +X if (k != NULL) { +X object *m; +X m = dictlookup(modules, k); +X if (m != NULL && is_moduleobject(m)) { +X object *d; +X d = getmoduledict(m); +X if (d != NULL && is_dictobject(d)) { +X cleardict(d); +X } +X } +X } +X } +X cleardict(modules); +X } +X DECREF(modules); +X} +X +X +X/* Initialize built-in modules when first imported */ +X +Xextern struct { +X char *name; +X void (*initfunc)(); +X} inittab[]; +X +Xstatic int +Xinit_builtin(name) +X char *name; +X{ +X int i; +X for (i = 0; inittab[i].name != NULL; i++) { +X if (strcmp(name, inittab[i].name) == 0) { +X (*inittab[i].initfunc)(); +X return 1; +X } +X } +X return 0; +X} +EOF +fi +if test -s 'src/macmodule.c' +then echo '*** I will not over-write existing file src/macmodule.c' +else +echo 'x - src/macmodule.c' +sed 's/^X//' > 'src/macmodule.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Macintosh OS module implementation */ +X +X#include "allobjects.h" +X +X#include "import.h" +X#include "modsupport.h" +X +X#include "sigtype.h" +X +X#include "::unixemu:dir.h" +X#include "::unixemu:stat.h" +X +Xstatic object *MacError; /* Exception */ +X +X +Xstatic object * +Xmac_chdir(self, args) +X object *self; +X object *args; +X{ +X object *path; +X if (!getstrarg(args, &path)) +X return NULL; +X if (chdir(getstringvalue(path)) != 0) +X return err_errno(MacError); +X INCREF(None); +X return None; +X} +X +X +Xstatic object * +Xmac_getcwd(self, args) +X object *self; +X object *args; +X{ +X extern char *getwd(); +X char buf[1025]; +X if (!getnoarg(args)) +X return NULL; +X strcpy(buf, "mac.getcwd() failed"); /* In case getwd() doesn't set a msg */ +X if (getwd(buf) == NULL) { +X err_setstr(MacError, buf); +X return NULL; +X } +X return newstringobject(buf); +X} +X +X +Xstatic object * +Xmac_listdir(self, args) +X object *self; +X object *args; +X{ +X object *name, *d, *v; +X DIR *dirp; +X struct direct *ep; +X if (!getstrarg(args, &name)) +X return NULL; +X if ((dirp = opendir(getstringvalue(name))) == NULL) +X return err_errno(MacError); +X if ((d = newlistobject(0)) == NULL) { +X closedir(dirp); +X return NULL; +X } +X while ((ep = readdir(dirp)) != NULL) { +X v = newstringobject(ep->d_name); +X if (v == NULL) { +X DECREF(d); +X d = NULL; +X break; +X } +X if (addlistitem(d, v) != 0) { +X DECREF(v); +X DECREF(d); +X d = NULL; +X break; +X } +X DECREF(v); +X } +X closedir(dirp); +X return d; +X} +X +X +Xstatic object * +Xmac_mkdir(self, args) +X object *self; +X object *args; +X{ +X object *path; +X int mode; +X if (!getstrintarg(args, &path, &mode)) +X return NULL; +X if (mkdir(getstringvalue(path), mode) != 0) +X return err_errno(MacError); +X INCREF(None); +X return None; +X} +X +X +Xstatic object * +Xmac_rename(self, args) +X object *self; +X object *args; +X{ +X object *src, *dst; +X if (!getstrstrarg(args, &src, &dst)) +X return NULL; +X if (rename(getstringvalue(src), getstringvalue(dst)) != 0) +X return err_errno(MacError); +X INCREF(None); +X return None; +X} +X +X +Xstatic object * +Xmac_rmdir(self, args) +X object *self; +X object *args; +X{ +X object *path; +X if (!getstrarg(args, &path)) +X return NULL; +X if (rmdir(getstringvalue(path)) != 0) +X return err_errno(MacError); +X INCREF(None); +X return None; +X} +X +X +Xstatic object * +Xmac_stat(self, args) +X object *self; +X object *args; +X{ +X struct stat st; +X object *path; +X object *v; +X if (!getstrarg(args, &path)) +X return NULL; +X if (stat(getstringvalue(path), &st) != 0) +X return err_errno(MacError); +X v = newtupleobject(11); +X if (v == NULL) +X return NULL; +X#define SET(i, val) settupleitem(v, i, newintobject((long)(val))) +X#define XXX(i, val) SET(i, 0) /* For values my Mac stat doesn't support */ +X SET(0, st.st_mode); +X XXX(1, st.st_ino); +X XXX(2, st.st_dev); +X XXX(3, st.st_nlink); +X XXX(4, st.st_uid); +X XXX(5, st.st_gid); +X SET(6, st.st_size); +X XXX(7, st.st_atime); +X SET(8, st.st_mtime); +X XXX(9, st.st_ctime); +X SET(10, st.st_rsize); /* Mac-specific: resource size */ +X#undef SET +X if (err_occurred()) { +X DECREF(v); +X return NULL; +X } +X return v; +X} +X +X +Xstatic object * +Xmac_sync(self, args) +X object *self; +X object *args; +X{ +X if (!getnoarg(args)) +X return NULL; +X sync(); +X INCREF(None); +X return None; +X} +X +X +Xstatic object * +Xmac_unlink(self, args) +X object *self; +X object *args; +X{ +X object *path; +X if (!getstrarg(args, &path)) +X return NULL; +X if (unlink(getstringvalue(path)) != 0) +X return err_errno(MacError); +X INCREF(None); +X return None; +X} +X +X +Xstatic struct methodlist mac_methods[] = { +X {"chdir", mac_chdir}, +X {"getcwd", mac_getcwd}, +X {"listdir", mac_listdir}, +X {"mkdir", mac_mkdir}, +X {"rename", mac_rename}, +X {"rmdir", mac_rmdir}, +X {"stat", mac_stat}, +X {"sync", mac_sync}, +X {"unlink", mac_unlink}, +X {NULL, NULL} /* Sentinel */ +X}; +X +X +Xvoid +Xinitmac() +X{ +X object *m, *d; +X +X m = initmodule("mac", mac_methods); +X d = getmoduledict(m); +X +X /* Initialize mac.error exception */ +X MacError = newstringobject("mac.error"); +X if (MacError == NULL || dictinsert(d, "error", MacError) != 0) +X fatal("can't define mac.error"); +X} +EOF +fi +if test -s 'src/object.c' +then echo '*** I will not over-write existing file src/object.c' +else +echo 'x - src/object.c' +sed 's/^X//' > 'src/object.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Generic object operations; and implementation of None (NoObject) */ +X +X#include "allobjects.h" +X +X#ifdef REF_DEBUG +Xlong ref_total; +X#endif +X +X/* Object allocation routines used by NEWOBJ and NEWVAROBJ macros. +X These are used by the individual routines for object creation. +X Do not call them otherwise, they do not initialize the object! */ +X +Xobject * +Xnewobject(tp) +X typeobject *tp; +X{ +X object *op = (object *) malloc(tp->tp_basicsize); +X if (op == NULL) +X return err_nomem(); +X NEWREF(op); +X op->ob_type = tp; +X return op; +X} +X +X#if 0 /* unused */ +X +Xvarobject * +Xnewvarobject(tp, size) +X typeobject *tp; +X unsigned int size; +X{ +X varobject *op = (varobject *) +X malloc(tp->tp_basicsize + size * tp->tp_itemsize); +X if (op == NULL) +X return err_nomem(); +X NEWREF(op); +X op->ob_type = tp; +X op->ob_size = size; +X return op; +X} +X +X#endif +X +Xint StopPrint; /* Flag to indicate printing must be stopped */ +X +Xstatic int prlevel; +X +Xvoid +Xprintobject(op, fp, flags) +X object *op; +X FILE *fp; +X int flags; +X{ +X /* Hacks to make printing a long or recursive object interruptible */ +X /* XXX Interrupts should leave a more permanent error */ +X prlevel++; +X if (!StopPrint && intrcheck()) { +X fprintf(fp, "\n[print interrupted]\n"); +X StopPrint = 1; +X } +X if (!StopPrint) { +X if (op == NULL) { +X fprintf(fp, "<nil>"); +X } +X else { +X if (op->ob_refcnt <= 0) +X fprintf(fp, "(refcnt %d):", op->ob_refcnt); +X if (op->ob_type->tp_print == NULL) { +X fprintf(fp, "<%s object at %lx>", +X op->ob_type->tp_name, (long)op); +X } +X else { +X (*op->ob_type->tp_print)(op, fp, flags); +X } +X } +X } +X prlevel--; +X if (prlevel == 0) +X StopPrint = 0; +X} +X +Xobject * +Xreprobject(v) +X object *v; +X{ +X object *w = NULL; +X /* Hacks to make converting a long or recursive object interruptible */ +X prlevel++; +X if (!StopPrint && intrcheck()) { +X StopPrint = 1; +X err_set(KeyboardInterrupt); +X } +X if (!StopPrint) { +X if (v == NULL) { +X w = newstringobject("<NULL>"); +X } +X else if (v->ob_type->tp_repr == NULL) { +X char buf[100]; +X sprintf(buf, "<%.80s object at %lx>", +X v->ob_type->tp_name, (long)v); +X w = newstringobject(buf); +X } +X else { +X w = (*v->ob_type->tp_repr)(v); +X } +X if (StopPrint) { +X XDECREF(w); +X w = NULL; +X } +X } +X prlevel--; +X if (prlevel == 0) +X StopPrint = 0; +X return w; +X} +X +Xint +Xcmpobject(v, w) +X object *v, *w; +X{ +X typeobject *tp; +X if (v == w) +X return 0; +X if (v == NULL) +X return -1; +X if (w == NULL) +X return 1; +X if ((tp = v->ob_type) != w->ob_type) +X return strcmp(tp->tp_name, w->ob_type->tp_name); +X if (tp->tp_compare == NULL) +X return (v < w) ? -1 : 1; +X return ((*tp->tp_compare)(v, w)); +X} +X +Xobject * +Xgetattr(v, name) +X object *v; +X char *name; +X{ +X if (v->ob_type->tp_getattr == NULL) { +X err_setstr(TypeError, "attribute-less object"); +X return NULL; +X } +X else { +X return (*v->ob_type->tp_getattr)(v, name); +X } +X} +X +Xint +Xsetattr(v, name, w) +X object *v; +X char *name; +X object *w; +X{ +X if (v->ob_type->tp_setattr == NULL) { +X if (v->ob_type->tp_getattr == NULL) +X err_setstr(TypeError, "attribute-less object"); +X else +X err_setstr(TypeError, "object has read-only attributes"); +X return -1; +X } +X else { +X return (*v->ob_type->tp_setattr)(v, name, w); +X } +X} +X +X +X/* +XNoObject is usable as a non-NULL undefined value, used by the macro None. +XThere is (and should be!) no way to create other objects of this type, +Xso there is exactly one (which is indestructible, by the way). +X*/ +X +Xstatic void +Xnone_print(op, fp, flags) +X object *op; +X FILE *fp; +X int flags; +X{ +X fprintf(fp, "None"); +X} +X +Xstatic object * +Xnone_repr(op) +X object *op; +X{ +X return newstringobject("None"); +X} +X +Xstatic typeobject Notype = { +X OB_HEAD_INIT(&Typetype) +X 0, +X "None", +X 0, +X 0, +X 0, /*tp_dealloc*/ /*never called*/ +X none_print, /*tp_print*/ +X 0, /*tp_getattr*/ +X 0, /*tp_setattr*/ +X 0, /*tp_compare*/ +X none_repr, /*tp_repr*/ +X 0, /*tp_as_number*/ +X 0, /*tp_as_sequence*/ +X 0, /*tp_as_mapping*/ +X}; +X +Xobject NoObject = { +X OB_HEAD_INIT(&Notype) +X}; +X +X +X#ifdef TRACE_REFS +X +Xstatic object refchain = {&refchain, &refchain}; +X +XNEWREF(op) +X object *op; +X{ +X ref_total++; +X op->ob_refcnt = 1; +X op->_ob_next = refchain._ob_next; +X op->_ob_prev = &refchain; +X refchain._ob_next->_ob_prev = op; +X refchain._ob_next = op; +X} +X +XUNREF(op) +X register object *op; +X{ +X register object *p; +X if (op->ob_refcnt < 0) { +X fprintf(stderr, "UNREF negative refcnt\n"); +X abort(); +X } +X for (p = refchain._ob_next; p != &refchain; p = p->_ob_next) { +X if (p == op) +X break; +X } +X if (p == &refchain) { /* Not found */ +X fprintf(stderr, "UNREF unknown object\n"); +X abort(); +X } +X op->_ob_next->_ob_prev = op->_ob_prev; +X op->_ob_prev->_ob_next = op->_ob_next; +X} +X +XDELREF(op) +X object *op; +X{ +X UNREF(op); +X (*(op)->ob_type->tp_dealloc)(op); +X} +X +Xprintrefs(fp) +X FILE *fp; +X{ +X object *op; +X fprintf(fp, "Remaining objects:\n"); +X for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) { +X fprintf(fp, "[%d] ", op->ob_refcnt); +X printobject(op, fp, 0); +X putc('\n', fp); +X } +X} +X +X#endif +EOF +fi +if test -s 'src/tupleobject.c' +then echo '*** I will not over-write existing file src/tupleobject.c' +else +echo 'x - src/tupleobject.c' +sed 's/^X//' > 'src/tupleobject.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Tuple object implementation */ +X +X#include "allobjects.h" +X +Xobject * +Xnewtupleobject(size) +X register int size; +X{ +X register int i; +X register tupleobject *op; +X if (size < 0) { +X err_badcall(); +X return NULL; +X } +X op = (tupleobject *) +X malloc(sizeof(tupleobject) + size * sizeof(object *)); +X if (op == NULL) +X return err_nomem(); +X NEWREF(op); +X op->ob_type = &Tupletype; +X op->ob_size = size; +X for (i = 0; i < size; i++) +X op->ob_item[i] = NULL; +X return (object *) op; +X} +X +Xint +Xgettuplesize(op) +X register object *op; +X{ +X if (!is_tupleobject(op)) { +X err_badcall(); +X return -1; +X } +X else +X return ((tupleobject *)op)->ob_size; +X} +X +Xobject * +Xgettupleitem(op, i) +X register object *op; +X register int i; +X{ +X if (!is_tupleobject(op)) { +X err_badcall(); +X return NULL; +X } +X if (i < 0 || i >= ((tupleobject *)op) -> ob_size) { +X err_setstr(IndexError, "tuple index out of range"); +X return NULL; +X } +X return ((tupleobject *)op) -> ob_item[i]; +X} +X +Xint +Xsettupleitem(op, i, newitem) +X register object *op; +X register int i; +X register object *newitem; +X{ +X register object *olditem; +X if (!is_tupleobject(op)) { +X if (newitem != NULL) +X DECREF(newitem); +X err_badcall(); +X return -1; +X } +X if (i < 0 || i >= ((tupleobject *)op) -> ob_size) { +X if (newitem != NULL) +X DECREF(newitem); +X err_setstr(IndexError, "tuple assignment index out of range"); +X return -1; +X } +X olditem = ((tupleobject *)op) -> ob_item[i]; +X ((tupleobject *)op) -> ob_item[i] = newitem; +X if (olditem != NULL) +X DECREF(olditem); +X return 0; +X} +X +X/* Methods */ +X +Xstatic void +Xtupledealloc(op) +X register tupleobject *op; +X{ +X register int i; +X for (i = 0; i < op->ob_size; i++) { +X if (op->ob_item[i] != NULL) +X DECREF(op->ob_item[i]); +X } +X free((ANY *)op); +X} +X +Xstatic void +Xtupleprint(op, fp, flags) +X tupleobject *op; +X FILE *fp; +X int flags; +X{ +X int i; +X fprintf(fp, "("); +X for (i = 0; i < op->ob_size && !StopPrint; i++) { +X if (i > 0) { +X fprintf(fp, ", "); +X } +X printobject(op->ob_item[i], fp, flags); +X } +X if (op->ob_size == 1) +X fprintf(fp, ","); +X fprintf(fp, ")"); +X} +X +Xobject * +Xtuplerepr(v) +X tupleobject *v; +X{ +X object *s, *t, *comma; +X int i; +X s = newstringobject("("); +X comma = newstringobject(", "); +X for (i = 0; i < v->ob_size && s != NULL; i++) { +X if (i > 0) +X joinstring(&s, comma); +X t = reprobject(v->ob_item[i]); +X joinstring(&s, t); +X if (t != NULL) +X DECREF(t); +X } +X DECREF(comma); +X if (v->ob_size == 1) { +X t = newstringobject(","); +X joinstring(&s, t); +X DECREF(t); +X } +X t = newstringobject(")"); +X joinstring(&s, t); +X DECREF(t); +X return s; +X} +X +Xstatic int +Xtuplecompare(v, w) +X register tupleobject *v, *w; +X{ +X register int len = +X (v->ob_size < w->ob_size) ? v->ob_size : w->ob_size; +X register int i; +X for (i = 0; i < len; i++) { +X int cmp = cmpobject(v->ob_item[i], w->ob_item[i]); +X if (cmp != 0) +X return cmp; +X } +X return v->ob_size - w->ob_size; +X} +X +Xstatic int +Xtuplelength(a) +X tupleobject *a; +X{ +X return a->ob_size; +X} +X +Xstatic object * +Xtupleitem(a, i) +X register tupleobject *a; +X register int i; +X{ +X if (i < 0 || i >= a->ob_size) { +X err_setstr(IndexError, "tuple index out of range"); +X return NULL; +X } +X INCREF(a->ob_item[i]); +X return a->ob_item[i]; +X} +X +Xstatic object * +Xtupleslice(a, ilow, ihigh) +X register tupleobject *a; +X register int ilow, ihigh; +X{ +X register tupleobject *np; +X register int i; +X if (ilow < 0) +X ilow = 0; +X if (ihigh > a->ob_size) +X ihigh = a->ob_size; +X if (ihigh < ilow) +X ihigh = ilow; +X if (ilow == 0 && ihigh == a->ob_size) { +X /* XXX can only do this if tuples are immutable! */ +X INCREF(a); +X return (object *)a; +X } +X np = (tupleobject *)newtupleobject(ihigh - ilow); +X if (np == NULL) +X return NULL; +X for (i = ilow; i < ihigh; i++) { +X object *v = a->ob_item[i]; +X INCREF(v); +X np->ob_item[i - ilow] = v; +X } +X return (object *)np; +X} +X +Xstatic object * +Xtupleconcat(a, bb) +X register tupleobject *a; +X register object *bb; +X{ +X register int size; +X register int i; +X tupleobject *np; +X if (!is_tupleobject(bb)) { +X err_badarg(); +X return NULL; +X } +X#define b ((tupleobject *)bb) +X size = a->ob_size + b->ob_size; +X np = (tupleobject *) newtupleobject(size); +X if (np == NULL) { +X return err_nomem(); +X } +X for (i = 0; i < a->ob_size; i++) { +X object *v = a->ob_item[i]; +X INCREF(v); +X np->ob_item[i] = v; +X } +X for (i = 0; i < b->ob_size; i++) { +X object *v = b->ob_item[i]; +X INCREF(v); +X np->ob_item[i + a->ob_size] = v; +X } +X return (object *)np; +X#undef b +X} +X +Xstatic sequence_methods tuple_as_sequence = { +X tuplelength, /*sq_length*/ +X tupleconcat, /*sq_concat*/ +X 0, /*sq_repeat*/ +X tupleitem, /*sq_item*/ +X tupleslice, /*sq_slice*/ +X 0, /*sq_ass_item*/ +X 0, /*sq_ass_slice*/ +X}; +X +Xtypeobject Tupletype = { +X OB_HEAD_INIT(&Typetype) +X 0, +X "tuple", +X sizeof(tupleobject) - sizeof(object *), +X sizeof(object *), +X tupledealloc, /*tp_dealloc*/ +X tupleprint, /*tp_print*/ +X 0, /*tp_getattr*/ +X 0, /*tp_setattr*/ +X tuplecompare, /*tp_compare*/ +X tuplerepr, /*tp_repr*/ +X 0, /*tp_as_number*/ +X &tuple_as_sequence, /*tp_as_sequence*/ +X 0, /*tp_as_mapping*/ +X}; +EOF +fi +echo 'Part 14 out of 21 of pack.out complete.' +exit 0 diff --git a/shar/python-0.9.1-15-21.shar b/shar/python-0.9.1-15-21.shar new file mode 100644 index 0000000..3cc3c78 --- /dev/null +++ b/shar/python-0.9.1-15-21.shar @@ -0,0 +1,2539 @@ +: This is a shell archive. +: Extract with 'sh this_file'. +: +: Extract part 01 first since it makes all directories +echo 'Start of pack.out, part 15 out of 21:' +if test -s 'demo/sgi/gl/kites.py' +then echo '*** I will not over-write existing file demo/sgi/gl/kites.py' +else +echo 'x - demo/sgi/gl/kites.py' +sed 's/^X//' > 'demo/sgi/gl/kites.py' << 'EOF' +X#! /ufs/guido/bin/sgi/python +X +X# *** This only works correctly on a 24 bit-plane machine. *** +X# +X# A simple Python program that tests the some parts of the +X# GL library. It shows the speed that can be obtained when +X# doing simple graphics. +X# +X# The bottleneck in this program is NOT Python but the graphics +X# engine; i.e Python can feed the graphics pipeline fast enough +X# on the 4D/25G. +X# +X# This program show 3 kites flying around the screen. It uses +X# +X# * bgnpolygon, endpolygon +X# * v3, n3 +X# * lmdef, lmbind +X# +X# Usage : +X# +X# ESC -> exit program +X# MOUSE3 -> freeze toggle +X# MOUSE2 -> one step (use this in freeze state) +X +Xfrom GL import * +Xfrom gl import * +Ximport DEVICE +Xfrom math import * +X +X# +X# viewobj : sets the rotation, translation and scaling +X# set appropiate material, call drawobject() +X# +Xdef viewobj (r, s, t, mat) : +X pushmatrix() +X rot (r * 10.0, 'X') +X rot (r * 10.0, 'Y') +X rot (r * 10.0, 'Z') +X scale (s[0], s[1], s[2]) +X translate (t[0], t[1], t[2]) +X lmbind(MATERIAL, mat) +X drawobject() +X popmatrix() +X +X# +X# makeobj : the contructor of the object +X# +Xdef mkobj () : +X v0 = (-5.0 ,0.0, 0.0) +X v1 = (0.0 ,5.0, 0.0) +X v2 = (5.0 ,0.0, 0.0) +X v3 = (0.0 ,2.0, 0.0) +X n0 = (sqrt(2.0)/2.0, sqrt(2.0)/2.0, 0.0) +X vn = ((v0, n0), (v1, n0), (v2, n0), (v3, n0)) +X # +X return vn +X +X# +X# the object itself as an array of vertices and normals +X# +Xkite = mkobj () +X +X# +X# drawobject : draw a triangle. with bgnpolygon +X# +Xdef drawobject () : +X # +X bgnpolygon() +X vnarray (kite) +X endpolygon() +X +X# +X# identity matrix +X# +Xidmat=[1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0] +X +X# +X# the rgb-value of light-blue +X# +XLightBlue = (43,169,255) +X +X# +X# the different materials. +X# +Xm1=[SPECULAR,0.0,0.0,0.6,DIFFUSE,0.0,0.0,0.8,SHININESS,20.0,LMNULL] +Xm2=[SPECULAR,0.8,0.0,0.1,DIFFUSE,0.8,0.0,0.3,SHININESS,120.0,LMNULL] +Xm3=[SPECULAR,0.0,1.0,0.0,DIFFUSE,0.0,0.6,0.0,SHININESS,120.0,LMNULL] +X +X# +X# lightsources +X# +Xlight1 = [LCOLOR,1.0,1.0,1.0,POSITION,15.0,15.0,0.0,1.0,LMNULL] +Xlight2 = [LCOLOR,1.0,1.0,1.0,POSITION,-15.0,15.0,0.0,1.0,LMNULL] +X +X# +X# the lightmodel +X# +Xmodel = [AMBIENT,0.2,0.2,0.2,LMNULL] +X +X# +X# initgl : opens the window, configures the pipeline to 2buf and zbuf, +X# sets the viewing, defines and binds the materials +X# +Xdef initgl () : +X # +X # open window +X # +X foreground () +X keepaspect (1, 1) +X prefposition (100, 500, 100, 500) +X w = winopen ('PYTHON lights') +X keepaspect (1, 1) +X winconstraints() +X # +X # configure pipeline (zbuf, 2buf, GOURAUD and RGBmode) +X # +X zbuffer (1) +X doublebuffer () +X shademodel (GOURAUD) +X RGBmode () +X gconfig () +X # +X # define and bind materials (set perspective BEFORE loadmat !) +X # +X mmode(MVIEWING) +X perspective (900, 1.0, 1.0, 20.0) +X loadmatrix(idmat) +X lmdef(DEFMATERIAL, 1, m1) +X lmdef(DEFMATERIAL, 2, m2) +X lmdef(DEFMATERIAL, 3, m3) +X lmdef(DEFLIGHT, 1, light1) +X lmdef(DEFLIGHT, 2, light2) +X lmdef(DEFLMODEL, 1, model) +X lmbind(LIGHT0,1) +X lmbind(LIGHT1,2) +X lmbind(LMODEL,1) +X # +X # set viewing +X # +X lookat (0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0) +X # +X # ask for the REDRAW and ESCKEY events +X # +X qdevice(DEVICE.MOUSE3) +X qdevice(DEVICE.MOUSE2) +X qdevice(DEVICE.REDRAW) +X qdevice(DEVICE.ESCKEY) +X +X# +X# GoForIT : use 2buf to redraw the object 2n times. index i is used as +X# the (smoothly changing) rotation angle +X# +Xdef GoForIt(i) : +X freeze = 1 +X while 1 : +X if freeze <> 0 : +X i = i + 1 +X # +X # clear z-buffer and clear background to light-blue +X # +X zclear() +X c3i (LightBlue) +X clear() +X # +X # draw the 3 traiangles scaled above each other. +X # +X viewobj(float(i),[1.0,1.0,1.0],[1.0,1.0,1.0],1) +X viewobj(float(i),[0.75,0.75,0.75],[0.0,2.0,2.0],2) +X viewobj(float(i),[0.5,0.5,0.5],[0.0,4.0,4.0],3) +X # +X swapbuffers() +X # +X if qtest() <> 0 : +X dev, val = qread() +X if dev = DEVICE.ESCKEY : +X break +X elif dev = DEVICE.REDRAW : +X reshapeviewport () +X elif dev = DEVICE.MOUSE3 and val <> 0 : +X freeze = 1 - freeze +X elif dev = DEVICE.MOUSE2 and val <> 0 : +X i = i + 1 +X +X +X# the main program +X# +Xdef main () : +X initgl () +X GoForIt (0) +X +X# +X# exec main +X# +Xmain () +EOF +chmod +x 'demo/sgi/gl/kites.py' +fi +if test -s 'demo/sgi/gl_panel/nurbs/nurbs.s' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/nurbs/nurbs.s' +else +echo 'x - demo/sgi/gl_panel/nurbs/nurbs.s' +sed 's/^X//' > 'demo/sgi/gl_panel/nurbs/nurbs.s' << 'EOF' +X;;; This file was automatically generated by the panel editor. +X;;; If you read it into gnu emacs, it will automagically format itself. +X +X(panel (prop help creator:user-panel-help) +X(prop user-panel #t) +X(label "NURB controls") +X(x 815) +X(y 22) +X(al (pnl_toggle_button (name "trim") +X(prop help creator:user-act-help) +X(label "trim on/off") +X(x 4) +X(y 4.5) +X(w 0.45) +X(h 0.4) +X(downfunc move-then-resize) +X) +X(pnl_toggle_button (name "motion") +X(prop help creator:user-act-help) +X(label "motion on/off") +X(y 1) +X(downfunc move-then-resize) +X) +X(pnl_toggle_button (name "xyzaxis") +X(prop help creator:user-act-help) +X(label "xyz-axis") +X(y 3) +X(downfunc move-then-resize) +X) +X(pnl_toggle_button (name "trimpnts") +X(prop help creator:user-act-help) +X(label "trimming pnts") +X(y 3.5) +X(downfunc move-then-resize) +X) +X(pnl_toggle_button (name "cntlpnts") +X(prop help creator:user-act-help) +X(label "control pnts") +X(y 4) +X(downfunc move-then-resize) +X) +X(pnl_toggle_button (name "nurb") +X(prop help creator:user-act-help) +X(label "nurb") +X(y 4.5) +X(val 1) +X(downfunc move-then-resize) +X) +X(pnl_button (name "quit") +X(prop help creator:user-act-help) +X(label "quit") +X(x 4) +X(y 1) +X(labeltype 1) +X(downfunc move-then-resize) +X) +X(pnl_label (prop help creator:user-act-help) +X(label "TRIMMING") +X(x 4) +X(y 5) +X(downfunc move-then-resize) +X) +X(pnl_label (prop help creator:user-act-help) +X(label "MOTION") +X(y 1.5) +X(downfunc move-then-resize) +X) +X(pnl_label (prop help creator:user-act-help) +X(label "VISIBILITY") +X(y 5) +X(downfunc move-then-resize) +X) +X) +X) +X;;; Local Variables: +X;;; mode: scheme +X;;; eval: (save-excursion (goto-char (point-min)) (kill-line 3)) +X;;; eval: (save-excursion (goto-char (point-min)) (replace-regexp "[ \n]*)" ")")) +X;;; eval: (indent-region (point-min) (point-max) nil) +X;;; eval: (progn (kill-line -3) (delete-backward-char 1) (save-buffer)) +X;;; End: +EOF +fi +if test -s 'lib/Sliders.py' +then echo '*** I will not over-write existing file lib/Sliders.py' +else +echo 'x - lib/Sliders.py' +sed 's/^X//' > 'lib/Sliders.py' << 'EOF' +X# Module 'Sliders' +X +X +Ximport stdwin +Xfrom stdwinevents import * +Ximport rect +Xfrom Buttons import * +Xfrom HVSplit import HSplit +X +X +X# Field indices in event detail +X# +X_HV = 0 +X_CLICKS = 1 +X_BUTTON = 2 +X_MASK = 3 +X +X +X# DragSlider is the simplest possible slider. +X# It looks like a button but dragging the mouse left or right +X# changes the controlled value. +X# It does not support any of the triggers or hooks defined by Buttons, +X# but defines its own setval_trigger and setval_hook. +X# +Xclass DragSliderReactivity() = BaseReactivity(): +X # +X def mouse_down(self, detail): +X h, v = hv = detail[_HV] +X if self.enabled and self.mousetest(hv): +X self.anchor = h +X self.oldval = self.val +X self.active = 1 +X # +X def mouse_move(self, detail): +X if self.active: +X h, v = detail[_HV] +X self.setval(self.oldval + (h - self.anchor)) +X # +X def mouse_up(self, detail): +X if self.active: +X h, v = detail[_HV] +X self.setval(self.oldval + (h - self.anchor)) +X self.active = 0 +X # +X +Xclass DragSliderAppearance() = ButtonAppearance(): +X # +X # INVARIANTS maintained by the setval method: +X # +X # self.min <= self.val <= self.max +X # self.text = self.pretext + `self.val` + self.postext +X # +X # (Notice that unlike Python ranges, the end point belongs +X # to the range.) +X # +X def init_appearance(self): +X ButtonAppearance.init_appearance(self) +X self.min = 0 +X self.val = 0 +X self.max = 100 +X self.hook = 0 +X self.pretext = self.postext = '' +X self.recalctext() +X # +X # The 'get*' and 'set*' methods belong to the generic slider interface +X # +X def getval(self): return self.val +X # +X def sethook(self, hook): +X self.hook = hook +X # +X def setminvalmax(self, (min, val, max)): +X self.min = min +X self.max = max +X self.setval(val) +X # +X def settexts(self, (pretext, postext)): +X self.pretext = pretext +X self.postext = postext +X self.recalctext() +X # +X def setval(self, val): +X val = min(self.max, max(self.min, val)) +X if val <> self.val: +X self.val = val +X self.recalctext() +X self.trigger() +X # +X def trigger(self): +X if self.hook: +X self.hook(self) +X # +X def recalctext(self): +X self.settext(self.pretext + `self.val` + self.postext) +X # +X +Xclass DragSlider() = DragSliderReactivity(), DragSliderAppearance(), Define(): +X def definetext(self, (parent, text)): +X raise RuntimeError, 'DragSlider.definetext() not supported' +X +X +X# Auxiliary class for PushButton incorporated in ComplexSlider +X# +Xclass _StepButton() = PushButton(): +X def define(self, parent): +X self = PushButton.define(self, parent) +X self.step = 0 +X return self +X def setstep(self, step): +X self.step = step +X def definetextstep(self, (parent, text, step)): +X self = self.definetext(parent, text) +X self.setstep(step) +X return self +X def init_reactivity(self): +X PushButton.init_reactivity(self) +X self.parent.need_timer(self) +X def step_trigger(self): +X self.parent.setval(self.parent.getval() + self.step) +X def down_trigger(self): +X self.step_trigger() +X self.parent.settimer(5) +X def timer(self): +X if self.hilited: +X self.step_trigger() +X if self.active: +X self.parent.settimer(1) +X +X +X# A complex slider is an HSplit initialized to three buttons: +X# one to step down, a dragslider, and one to step up. +X# +Xclass ComplexSlider() = HSplit(): +X # +X # Override Slider define() method +X # +X def define(self, parent): +X self = self.create(parent) # HSplit +X # +X self.downbutton = _StepButton().definetextstep(self, '-', -1) +X self.dragbutton = DragSlider().define(self) +X self.upbutton = _StepButton().definetextstep(self, '+', 1) +X # +X return self +X # +X # Override HSplit methods +X # +X def minsize(self, m): +X w1, h1 = self.downbutton.minsize(m) +X w2, h2 = self.dragbutton.minsize(m) +X w3, h3 = self.upbutton.minsize(m) +X height = max(h1, h2, h3) +X w1 = max(w1, height) +X w3 = max(w3, height) +X return w1+w2+w3, height +X # +X def setbounds(self, bounds): +X (left, top), (right, bottom) = self.bounds = bounds +X size = bottom - top +X self.downbutton.setbounds((left, top), (left+size, bottom)) +X self.dragbutton.setbounds((left+size, top), \ +X (right-size, bottom)) +X self.upbutton.setbounds((right-size, top), (right, bottom)) +X # +X # Pass other Slider methods on to dragbutton +X # +X def getval(self): return self.dragbutton.getval() +X def sethook(self, hook): self.dragbutton.sethook(hook) +X def setminvalmax(self, args): self.dragbutton.setminvalmax(args) +X def settexts(self, args): self.dragbutton.settexts(args) +X def setval(self, val): self.dragbutton.setval(val) +X def enable(self, flag): +X self.downbutton.enable(flag) +X self.dragbutton.enable(flag) +X self.upbutton.enable(flag) +EOF +fi +if test -s 'lib/clock.py' +then echo '*** I will not over-write existing file lib/clock.py' +else +echo 'x - lib/clock.py' +sed 's/^X//' > 'lib/clock.py' << 'EOF' +X# 'klok' -- A simple alarm clock +X +X# The alarm can be set at 5 minute intervals on a 12 hour basis. +X# It is controlled with the mouse: +X# - Click and drag around the circle to set the alarm. +X# - Click far outside the circle to clear the alarm. +X# - Click near the center to set the alarm at the last time set. +X# The alarm time is indicated by a small triangle just outside the circle, +X# and also by a digital time at the bottom. +X# The indicators disappear when the alarm is not set. +X# When the alarm goes off, it beeps every minute for five minutes, +X# and the clock turns into inverse video. +X# Click or activate the window to turn the ringing off. +X +Ximport stdwin +Xfrom stdwinevents import WE_MOUSE_DOWN, WE_MOUSE_MOVE, WE_MOUSE_UP, \ +X WE_TIMER, WE_DRAW, WE_SIZE, WE_CLOSE, WE_ACTIVATE +Ximport time +Xfrom math import sin, cos, atan2, pi, sqrt +X +XDEFWIDTH, DEFHEIGHT = 200, 200 +X +Xmouse_events = (WE_MOUSE_DOWN, WE_MOUSE_MOVE, WE_MOUSE_UP) +Xorigin = 0, 0 +Xfaraway = 2000, 2000 +Xeverywhere = origin, faraway +X +Xclass struct(): pass # A class to declare featureless objects +X +XG = struct() # Global variables (most set in setdimensions()) +XG.tzdiff = 5*3600 # THINK computes UCT from local time assuming EST! +X +XA = struct() # Globals used by the alarm +XA.set = 1 # True when alarm is set +XA.time = 11*60 + 40 # Time when alarm must go off +XA.ring = 0 # True when alarm is ringing +X +Xdef main(): +X try: +X realmain() +X except KeyboardInterrupt: +X print 'KeyboardInterrupt' +X finally: +X G.w = 0 +X +Xdef realmain(): +X setdimensions(DEFWIDTH, DEFHEIGHT) +X stdwin.setdefwinsize(G.farcorner) +X G.w = stdwin.open('klok') +X settimer() +X while 1: +X type, window, detail = stdwin.getevent() +X if type = WE_DRAW: +X drawproc(detail) +X elif type = WE_TIMER: +X settimer() +X drawproc(everywhere) +X elif type in mouse_events: +X mouseclick(type, detail) +X elif type = WE_ACTIVATE: +X if A.ring: +X # Turn the ringing off +X A.ring = 0 +X G.w.begindrawing().invert(G.mainarea) +X elif type = WE_SIZE: +X G.w.change(everywhere) +X width, height = G.w.getwinsize() +X height = height - stdwin.lineheight() +X setdimensions(width, height) +X elif type = WE_CLOSE: +X break +X +Xdef setdimensions(width, height): +X if width < height: size = width +X else: size = height +X halfwidth = width/2 +X halfheight = height/2 +X G.center = halfwidth, halfheight +X G.radius = size*45/100 +X G.width = width +X G.height = height +X G.corner = width, height +X G.mainarea = origin, G.corner +X G.lineheight = stdwin.lineheight() +X G.farcorner = width, height + G.lineheight +X G.statusarea = (0, height), G.farcorner +X G.fullarea = origin, G.farcorner +X +Xdef settimer(): +X now = getlocaltime() +X G.times = calctime(now) +X delay = 61 - now % 60 +X G.w.settimer(10 * delay) +X minutes = (now/60) % 720 +X if A.ring: +X # Is it time to stop the alarm ringing? +X since = (minutes - A.time + 720) % 720 +X if since >= 5: +X # Stop it now +X A.ring = 0 +X else: +X # Ring again, once every minute +X stdwin.fleep() +X elif A.set and minutes = A.time: +X # Start the alarm ringing +X A.ring = 1 +X stdwin.fleep() +X +Xdef drawproc(area): +X hours, minutes, seconds = G.times +X d = G.w.begindrawing() +X d.cliprect(area) +X d.erase(everywhere) +X d.circle(G.center, G.radius) +X d.line(G.center, calcpoint(hours*30 + minutes/2, 0.6)) +X d.line(G.center, calcpoint(minutes*6, 1.0)) +X str = dd(hours) + ':' + dd(minutes) +X p = (G.width - d.textwidth(str))/2, G.height * 3 / 4 +X d.text(p, str) +X if A.set: +X drawalarm(d) +X drawalarmtime(d) +X if A.ring: +X d.invert(G.mainarea) +X +Xdef mouseclick(type, detail): +X d = G.w.begindrawing() +X if A.ring: +X # First turn the ringing off +X A.ring = 0 +X d.invert(G.mainarea) +X h, v = detail[0] +X ch, cv = G.center +X x, y = h-ch, cv-v +X dist = sqrt(x*x + y*y) / float(G.radius) +X if dist > 1.2: +X if A.set: +X drawalarm(d) +X erasealarmtime(d) +X A.set = 0 +X elif dist < 0.8: +X if not A.set: +X A.set = 1 +X drawalarm(d) +X drawalarmtime(d) +X else: +X # Convert to half-degrees (range 0..720) +X alpha = atan2(y, x) +X hdeg = alpha*360.0/pi +X hdeg = 180.0 - hdeg +X hdeg = (hdeg + 720.0) % 720.0 +X atime = 5*int(hdeg/5.0 + 0.5) +X if atime <> A.time or not A.set: +X if A.set: +X drawalarm(d) +X erasealarmtime(d) +X A.set = 1 +X A.time = atime +X drawalarm(d) +X drawalarmtime(d) +X +Xdef drawalarm(d): +X p1 = calcpoint(float(A.time)/2.0, 1.02) +X p2 = calcpoint(float(A.time)/2.0 - 4.0, 1.1) +X p3 = calcpoint(float(A.time)/2.0 + 4.0, 1.1) +X d.xorline(p1, p2) +X d.xorline(p2, p3) +X d.xorline(p3, p1) +X +Xdef erasealarmtime(d): +X d.erase(G.statusarea) +X +Xdef drawalarmtime(d): +X # A.time is in the range 0..720 with origin at 12 o'clock +X # Convert to hours (0..12) and minutes (12*(0..60)) +X hh = A.time/60 +X mm = A.time%60 +X str = 'Alarm@' + dd(hh) + ':' + dd(mm) +X p1 = (G.width - d.textwidth(str))/2, G.height +X d.text(p1, str) +X +Xdef calctime(now): +X seconds = now % 60 +X minutes = (now/60) % 60 +X hours = (now/3600) % 12 +X return hours, minutes, seconds +X +Xdef calcpoint(degrees, size): +X alpha = pi/2.0 - float(degrees) * pi/180.0 +X x, y = cos(alpha), sin(alpha) +X h, v = G.center +X r = float(G.radius) +X return h + int(x*size*r), v - int(y*size*r) +X +Xdef dd(n): +X s = `n` +X return '0'*(2-len(s)) + s +X +Xdef getlocaltime(): +X return time.time() - G.tzdiff +X +X#main() +EOF +fi +if test -s 'lib/dircmp.py' +then echo '*** I will not over-write existing file lib/dircmp.py' +else +echo 'x - lib/dircmp.py' +sed 's/^X//' > 'lib/dircmp.py' << 'EOF' +X# Module 'dirmp' +X# +X# Defines a class to build directory diff tools on. +X +Ximport posix +X +Ximport path +X +Ximport dircache +Ximport cmpcache +Ximport statcache +Xfrom stat import * +X +X# Directory comparison class. +X# +Xclass dircmp(): +X # +X def new(dd, (a, b)): # Initialize +X dd.a = a +X dd.b = b +X # Properties that caller may change before callingdd. run(): +X dd.hide = ['.', '..'] # Names never to be shown +X dd.ignore = ['RCS', 'tags'] # Names ignored in comparison +X # +X return dd +X # +X def run(dd): # Compare everything except common subdirectories +X dd.a_list = filter(dircache.listdir(dd.a), dd.hide) +X dd.b_list = filter(dircache.listdir(dd.b), dd.hide) +X dd.a_list.sort() +X dd.b_list.sort() +X dd.phase1() +X dd.phase2() +X dd.phase3() +X # +X def phase1(dd): # Compute common names +X dd.a_only = [] +X dd.common = [] +X for x in dd.a_list: +X if x in dd.b_list: +X dd.common.append(x) +X else: +X dd.a_only.append(x) +X # +X dd.b_only = [] +X for x in dd.b_list: +X if x not in dd.common: +X dd.b_only.append(x) +X # +X def phase2(dd): # Distinguish files, directories, funnies +X dd.common_dirs = [] +X dd.common_files = [] +X dd.common_funny = [] +X # +X for x in dd.common: +X a_path = path.cat(dd.a, x) +X b_path = path.cat(dd.b, x) +X # +X ok = 1 +X try: +X a_stat = statcache.stat(a_path) +X except posix.error, why: +X # print 'Can\'t stat', a_path, ':', why[1] +X ok = 0 +X try: +X b_stat = statcache.stat(b_path) +X except posix.error, why: +X # print 'Can\'t stat', b_path, ':', why[1] +X ok = 0 +X # +X if ok: +X a_type = S_IFMT(a_stat[ST_MODE]) +X b_type = S_IFMT(b_stat[ST_MODE]) +X if a_type <> b_type: +X dd.common_funny.append(x) +X elif S_ISDIR(a_type): +X dd.common_dirs.append(x) +X elif S_ISREG(a_type): +X dd.common_files.append(x) +X else: +X dd.common_funny.append(x) +X else: +X dd.common_funny.append(x) +X # +X def phase3(dd): # Find out differences between common files +X xx = cmpfiles(dd.a, dd.b, dd.common_files) +X dd.same_files, dd.diff_files, dd.funny_files = xx +X # +X def phase4(dd): # Find out differences between common subdirectories +X # A new dircmp object is created for each common subdirectory, +X # these are stored in a dictionary indexed by filename. +X # The hide and ignore properties are inherited from the parent +X dd.subdirs = {} +X for x in dd.common_dirs: +X a_x = path.cat(dd.a, x) +X b_x = path.cat(dd.b, x) +X dd.subdirs[x] = newdd = dircmp().new(a_x, b_x) +X newdd.hide = dd.hide +X newdd.ignore = dd.ignore +X newdd.run() +X # +X def phase4_closure(dd): # Recursively call phase4() on subdirectories +X dd.phase4() +X for x in dd.subdirs.keys(): +X dd.subdirs[x].phase4_closure() +X # +X def report(dd): # Print a report on the differences between a and b +X # Assume that phases 1 to 3 have been executed +X # Output format is purposely lousy +X print 'diff', dd.a, dd.b +X if dd.a_only: +X print 'Only in', dd.a, ':', dd.a_only +X if dd.b_only: +X print 'Only in', dd.b, ':', dd.b_only +X if dd.same_files: +X print 'Identical files :', dd.same_files +X if dd.diff_files: +X print 'Differing files :', dd.diff_files +X if dd.funny_files: +X print 'Trouble with common files :', dd.funny_files +X if dd.common_dirs: +X print 'Common subdirectories :', dd.common_dirs +X if dd.common_funny: +X print 'Common funny cases :', dd.common_funny +X # +X def report_closure(dd): # Print reports on dd and on subdirs +X # If phase 4 hasn't been done, no subdir reports are printed +X dd.report() +X try: +X x = dd.subdirs +X except NameError: +X return # No subdirectories computed +X for x in dd.subdirs.keys(): +X print +X dd.subdirs[x].report_closure() +X # +X def report_phase4_closure(dd): # Report and do phase 4 recursively +X dd.report() +X dd.phase4() +X for x in dd.subdirs.keys(): +X print +X dd.subdirs[x].report_phase4_closure() +X +X +X# Compare common files in two directories. +X# Return: +X# - files that compare equal +X# - files that compare different +X# - funny cases (can't stat etc.) +X# +Xdef cmpfiles(a, b, common): +X res = ([], [], []) +X for x in common: +X res[cmp(path.cat(a, x), path.cat(b, x))].append(x) +X return res +X +X +X# Compare two files. +X# Return: +X# 0 for equal +X# 1 for different +X# 2 for funny cases (can't stat, etc.) +X# +Xdef cmp(a, b): +X try: +X if cmpcache.cmp(a, b): return 0 +X return 1 +X except posix.error: +X return 2 +X +X +X# Remove a list item. +X# NB: This modifies the list argument. +X# +Xdef remove(list, item): +X for i in range(len(list)): +X if list[i] = item: +X del list[i] +X break +X +X +X# Return a copy with items that occur in skip removed. +X# +Xdef filter(list, skip): +X result = [] +X for item in list: +X if item not in skip: result.append(item) +X return result +X +X +X# Demonstration and testing. +X# +Xdef demo(): +X import sys +X import getopt +X options, args = getopt.getopt(sys.argv[1:], 'r') +X if len(args) <> 2: raise getopt.error, 'need exactly two args' +X dd = dircmp().new(args[0], args[1]) +X dd.run() +X if ('-r', '') in options: +X dd.report_phase4_closure() +X else: +X dd.report() +X +X# demo() +EOF +fi +if test -s 'lib/dis.py' +then echo '*** I will not over-write existing file lib/dis.py' +else +echo 'x - lib/dis.py' +sed 's/^X//' > 'lib/dis.py' << 'EOF' +X# Disassembler +X +Ximport sys +Ximport string +X +Xdef dis(): +X tb = sys.last_traceback +X while tb.tb_next: tb = tb.tb_next +X distb(tb) +X +Xdef distb(tb): +X disassemble(tb.tb_frame.f_code, tb.tb_lasti) +X +Xdef disco(co): +X disassemble(co, -1) +X +Xdef disassemble(co, lasti): +X code = co.co_code +X labels = findlabels(code) +X n = len(code) +X i = 0 +X while i < n: +X c = code[i] +X op = ord(c) +X if op = SET_LINENO and i > 0: print # Extra blank line +X if i = lasti: print '-->', +X else: print ' ', +X if i in labels: print '>>', +X else: print ' ', +X print string.rjust(`i`, 4), +X print string.ljust(opname[op], 15), +X i = i+1 +X if op >= HAVE_ARGUMENT: +X oparg = ord(code[i]) + ord(code[i+1])*256 +X i = i+2 +X print string.rjust(`oparg`, 5), +X if op in hasconst: +X print '(' + `co.co_consts[oparg]` + ')', +X elif op in hasname: +X print '(' + co.co_names[oparg] + ')', +X elif op in hasjrel: +X print '(to ' + `i + oparg` + ')', +X print +X +Xdef findlabels(code): +X labels = [] +X n = len(code) +X i = 0 +X while i < n: +X c = code[i] +X op = ord(c) +X i = i+1 +X if op >= HAVE_ARGUMENT: +X oparg = ord(code[i]) + ord(code[i+1])*256 +X i = i+2 +X label = -1 +X if op in hasjrel: +X label = i+oparg +X elif op in hasjabs: +X label = oparg +X if label >= 0: +X if label not in labels: +X labels.append(label) +X return labels +X +Xhasconst = [] +Xhasname = [] +Xhasjrel = [] +Xhasjabs = [] +X +Xopname = range(256) +Xfor op in opname: opname[op] = '<' + `op` + '>' +X +Xdef def_op(name, op): +X opname[op] = name +X +Xdef name_op(name, op): +X opname[op] = name +X hasname.append(op) +X +Xdef jrel_op(name, op): +X opname[op] = name +X hasjrel.append(op) +X +Xdef jabs_op(name, op): +X opname[op] = name +X hasjabs.append(op) +X +X# Instruction opcodes for compiled code +X +Xdef_op('STOP_CODE', 0) +Xdef_op('POP_TOP', 1) +Xdef_op('ROT_TWO', 2) +Xdef_op('ROT_THREE', 3) +Xdef_op('DUP_TOP', 4) +X +Xdef_op('UNARY_POSITIVE', 10) +Xdef_op('UNARY_NEGATIVE', 11) +Xdef_op('UNARY_NOT', 12) +Xdef_op('UNARY_CONVERT', 13) +Xdef_op('UNARY_CALL', 14) +X +Xdef_op('BINARY_MULTIPLY', 20) +Xdef_op('BINARY_DIVIDE', 21) +Xdef_op('BINARY_MODULO', 22) +Xdef_op('BINARY_ADD', 23) +Xdef_op('BINARY_SUBTRACT', 24) +Xdef_op('BINARY_SUBSCR', 25) +Xdef_op('BINARY_CALL', 26) +X +Xdef_op('SLICE+0', 30) +Xdef_op('SLICE+1', 31) +Xdef_op('SLICE+2', 32) +Xdef_op('SLICE+3', 33) +X +Xdef_op('STORE_SLICE+0', 40) +Xdef_op('STORE_SLICE+1', 41) +Xdef_op('STORE_SLICE+2', 42) +Xdef_op('STORE_SLICE+3', 43) +X +Xdef_op('DELETE_SLICE+0', 50) +Xdef_op('DELETE_SLICE+1', 51) +Xdef_op('DELETE_SLICE+2', 52) +Xdef_op('DELETE_SLICE+3', 53) +X +Xdef_op('STORE_SUBSCR', 60) +Xdef_op('DELETE_SUBSCR', 61) +X +Xdef_op('PRINT_EXPR', 70) +Xdef_op('PRINT_ITEM', 71) +Xdef_op('PRINT_NEWLINE', 72) +X +Xdef_op('BREAK_LOOP', 80) +Xdef_op('RAISE_EXCEPTION', 81) +Xdef_op('LOAD_LOCALS', 82) +Xdef_op('RETURN_VALUE', 83) +Xdef_op('REQUIRE_ARGS', 84) +Xdef_op('REFUSE_ARGS', 85) +Xdef_op('BUILD_FUNCTION', 86) +Xdef_op('POP_BLOCK', 87) +Xdef_op('END_FINALLY', 88) +Xdef_op('BUILD_CLASS', 89) +X +XHAVE_ARGUMENT = 90 # Opcodes from here have an argument: +X +Xname_op('STORE_NAME', 90) # Index in name list +Xname_op('DELETE_NAME', 91) # "" +Xdef_op('UNPACK_TUPLE', 92) # Number of tuple items +Xdef_op('UNPACK_LIST', 93) # Number of list items +X# unused: 94 +Xname_op('STORE_ATTR', 95) # Index in name list +Xname_op('DELETE_ATTR', 96) # "" +X +Xdef_op('LOAD_CONST', 100) # Index in const list +Xhasconst.append(100) +Xname_op('LOAD_NAME', 101) # Index in name list +Xdef_op('BUILD_TUPLE', 102) # Number of tuple items +Xdef_op('BUILD_LIST', 103) # Number of list items +Xdef_op('BUILD_MAP', 104) # Always zero for now +Xname_op('LOAD_ATTR', 105) # Index in name list +Xdef_op('COMPARE_OP', 106) # Comparison operator +Xname_op('IMPORT_NAME', 107) # Index in name list +Xname_op('IMPORT_FROM', 108) # Index in name list +X +Xjrel_op('JUMP_FORWARD', 110) # Number of bytes to skip +Xjrel_op('JUMP_IF_FALSE', 111) # "" +Xjrel_op('JUMP_IF_TRUE', 112) # "" +Xjabs_op('JUMP_ABSOLUTE', 113) # Target byte offset from beginning of code +Xjrel_op('FOR_LOOP', 114) # Number of bytes to skip +X +Xjrel_op('SETUP_LOOP', 120) # Distance to target address +Xjrel_op('SETUP_EXCEPT', 121) # "" +Xjrel_op('SETUP_FINALLY', 122) # "" +X +Xdef_op('SET_LINENO', 127) # Current line number +XSET_LINENO = 127 +EOF +fi +if test -s 'lib/lambda.py' +then echo '*** I will not over-write existing file lib/lambda.py' +else +echo 'x - lib/lambda.py' +sed 's/^X//' > 'lib/lambda.py' << 'EOF' +X# A bit of Lambda Calculus illustrated in Python. +X# +X# This does not use Python's built-in 'eval' or 'exec' functions! +X +X +X# Currying +X# +X# From a function with 2 args, f(x, y), and a value for the 1st arg, +X# we can create a new function with one argument fx(y) = f(x, y). +X# This is called "Currying" (after the idea's inventor, a Mr. Curry). +X# +X# To implement this we create a class member, of which fx is a method; +X# f and x are stored as data attributes of the member. +X +Xclass _CurryClass(): +X def new(self, (f, x)): +X self.f = f +X self.x = x +X return self +X def fx(self, y): +X return self.f(self.x, y) +X +Xdef CURRY(f, x): +X # NB: f is not "simple": it has 2 arguments +X return _CurryClass().new(f, x).fx +X +X +X# Numbers in Lambda Calculus +X# +X# In the lambda calculus, natural numbers are represented by +X# higher-order functions Ntimes(f, x) that yield f applied N +X# times to x, e.g., Twice(f, x) = f(f(x)). +X# As far as I understand, there is no difference in real lambda +X# calculus between +X# lambda f x : f(f(x)) +X# and +X# lambda f : f o f # 'o' means function composition +X# but in Python we have to write the first as Twice(f, x) and +X# the second as twice(f). +X +Xdef Never(f, x): return x +Xdef Once(f, x): return f(x) +Xdef Twice(f, x): return f(f(x)) +Xdef Thrice(f, x): return f(f(f(x))) +Xdef Fourfold(f, x): return f(f(f(f(x)))) +X# (etc.) +X +Xdef never(f): return CURRY(Never, f) +Xdef once(f): return CURRY(Once, f) +Xdef twice(f): return CURRY(Twice, f) +Xdef thrice(f): return CURRY(Thrice, f) +Xdef fourfold(f): return CURRY(Fourfold, f) +X# (etc.) +X +X +X# NB: actually 'ntimes' is less concrete than 'Ntimes', as +X# 'ntimes' returns a function, while 'Ntimes' returns a value +X# similar to what f(x) returns. 'Ntimes' can be derived +X# from 'ntimes', as follows: +X# def Ntimes(f, x): return ntimes(f)(x) +X# but this doesn't help us since 'ntimes' can only be defined +X# using Ntimes (or a trick like the one used by CURRY). +X +X +X# Arithmetic in Lambda Calculus +X# +X# We can perform simple arithmetic on the un-curried versions, e.g., +X# Successor(Twice) = Thrice (2+1) +X# Sum(Thrice, Twice) = Fivefold (3+2) +X# Product(Thrice, Twice) = Sixfold (3*2) +X# Power(Thrice, Twice) = Ninefold (3**2) +X# +X# First we define versions that need f and x arguments. +X# They have funny argument forms so the final functions can +X# use CURRY, which only works on functions of exactly 2 arguments. +X +Xdef SUCCESSOR(Ntimes, (f, x)): return f(Ntimes(f, x)) +Xdef SUCCESSOR(Ntimes, (f, x)): return Ntimes(f, f(x)) # Same effect +Xdef SUM(Ntimes, (Mtimes, (f, x))): return Ntimes(f, Mtimes(f, x)) +Xdef PRODUCT(Ntimes, (Mtimes, (f, x))): return Ntimes(CURRY(Mtimes, f), x) +Xdef POWER(Ntimes, (Mtimes, (f, x))): +X return Mtimes(CURRY(CURRY, Ntimes), f)(x) +X +Xdef Successor(Ntimes): return CURRY(SUCCESSOR, Ntimes) +Xdef Sum(Ntimes, Mtimes): return CURRY(CURRY(SUM, Ntimes), Mtimes) +Xdef Product(Ntimes, Mtimes): return CURRY(CURRY(PRODUCT, Ntimes), Mtimes) +Xdef Power(Ntimes, Mtimes): return CURRY(CURRY(POWER, Ntimes), Mtimes) +X +X +X# Sorry, I don't have a clue on how to do subtraction or division... +X +X +X# References +X# +X# All I know about lambda calculus is from Roger Penrose's +X# The Emperor's New Mind, Chapter 2. +X +X +X# P.S.: Here is a Lambda function in Python. +X# It uses 'exec' and expects two strings to describe the arguments +X# and the function expression. Example: +X# lambda('x', 'x+1') +X# defines the successor function. +X +Xdef lambda(args, expr): +X if '\n' in args or '\n' in expr: +X raise RuntimeError, 'lambda: no cheating!' +X stmt = 'def func(' + args + '): return ' + expr + '\n' +X print 'lambda:', stmt, +X exec(stmt) +X return func +X +X +X# P.P.S.S.: Here is a way to construct Ntimes and ntimes directly. +X# Example: +X# GenericNtimes(4) +X# is equivalent to Fourfold. +X +Xclass _GenericNtimesClass(): +X def new(self, n): +X self.n = n +X return self +X def Ntimes(self, (f, x)): +X n = self.n +X while n > 0: x, n = f(x), n-1 +X return x +X +Xdef GenericNtimes(n): +X return _GenericNtimesClass().new(n).Ntimes +X +X +X# To construct any 'ntimes' function from the corresponding 'Ntimes', +X# we use a trick as used by CURRY. For example, +X# Ntimes2ntimes(Fourfold) +X# yields a function equivalent to fourfold. +X +Xclass _Ntimes2ntimesClass(): +X def new(self, Ntimes): +X self.Ntimes = Ntimes +X return self +X def ntimes(self, f): +X return CURRY(self.Ntimes, f) +X +Xdef Ntimes2ntimes(Ntimes): return _Ntimes2ntimesClass().new(Ntimes).ntimes +X +X +X# This allows us to construct generic 'ntimes' functions. Example: +X# generic_ntimes(3) +X# is the same as thrice. +X +Xdef generic_ntimes(n): return Ntimes2ntimes(GenericNtimes(n)) +EOF +fi +if test -s 'lib/tb.py' +then echo '*** I will not over-write existing file lib/tb.py' +else +echo 'x - lib/tb.py' +sed 's/^X//' > 'lib/tb.py' << 'EOF' +X# Print tracebacks, with a dump of local variables. +X# Also an interactive stack trace browser. +X +Ximport sys +Xtry: +X import mac +X os = mac +Xexcept NameError: +X import posix +X os = posix +Xfrom stat import * +Ximport string +X +Xdef br(): browser(sys.last_traceback) +X +Xdef tb(): printtb(sys.last_traceback) +X +Xdef browser(tb): +X if not tb: +X print 'No traceback.' +X return +X tblist = [] +X while tb: +X tblist.append(tb) +X tb = tb.tb_next +X ptr = len(tblist)-1 +X tb = tblist[ptr] +X while 1: +X if tb <> tblist[ptr]: +X tb = tblist[ptr] +X print `ptr` + ':', +X printtbheader(tb) +X try: +X line = raw_input('TB: ') +X except KeyboardInterrupt: +X print '\n[Interrupted]' +X break +X except EOFError: +X print '\n[EOF]' +X break +X cmd = string.strip(line) +X if cmd: +X if cmd = 'quit': +X break +X elif cmd = 'list': +X browserlist(tb) +X elif cmd = 'up': +X if ptr-1 >= 0: ptr = ptr-1 +X else: print 'Bottom of stack.' +X elif cmd = 'down': +X if ptr+1 < len(tblist): ptr = ptr+1 +X else: print 'Top of stack.' +X elif cmd = 'locals': +X printsymbols(tb.tb_frame.f_locals) +X elif cmd = 'globals': +X printsymbols(tb.tb_frame.f_globals) +X elif cmd in ('?', 'help'): +X browserhelp() +X else: +X browserexec(tb, cmd) +X +Xdef browserlist(tb): +X filename = tb.tb_frame.f_code.co_filename +X lineno = tb.tb_lineno +X last = lineno +X first = max(1, last-10) +X for i in range(first, last+1): +X if i = lineno: prefix = '***' + string.rjust(`i`, 4) + ':' +X else: prefix = string.rjust(`i`, 7) + ':' +X line = readfileline(filename, i) +X if line[-1:] = '\n': line = line[:-1] +X print prefix + line +X +Xdef browserexec(tb, cmd): +X locals = tb.tb_frame.f_locals +X globals = tb.tb_frame.f_globals +X try: +X exec(cmd+'\n', globals, locals) +X except: +X print '*** Exception:', +X print sys.exc_type, +X if sys.exc_value <> None: +X print ':', sys.exc_value, +X print +X print 'Type help to get help.' +X +Xdef browserhelp(): +X print +X print ' This is the traceback browser. Commands are:' +X print ' up : move one level up in the call stack' +X print ' down : move one level down in the call stack' +X print ' locals : print all local variables at this level' +X print ' globals : print all global variables at this level' +X print ' list : list source code around the failure' +X print ' help : print help (what you are reading now)' +X print ' quit : back to command interpreter' +X print ' Typing any other 1-line statement will execute it' +X print ' using the current level\'s symbol tables' +X print +X +Xdef printtb(tb): +X while tb: +X print1tb(tb) +X tb = tb.tb_next +X +Xdef print1tb(tb): +X printtbheader(tb) +X if tb.tb_frame.f_locals is not tb.tb_frame.f_globals: +X printsymbols(tb.tb_frame.f_locals) +X +Xdef printtbheader(tb): +X filename = tb.tb_frame.f_code.co_filename +X lineno = tb.tb_lineno +X info = '"' + filename + '"(' + `lineno` + ')' +X line = readfileline(filename, lineno) +X if line: +X info = info + ': ' + string.strip(line) +X print info +X +Xdef printsymbols(d): +X keys = d.keys() +X keys.sort() +X for name in keys: +X print ' ' + string.ljust(name, 12) + ':', +X printobject(d[name], 4) +X print +X +Xdef printobject(v, maxlevel): +X if v = None: +X print 'None', +X elif type(v) in (type(0), type(0.0)): +X print v, +X elif type(v) = type(''): +X if len(v) > 20: +X print `v[:17] + '...'`, +X else: +X print `v`, +X elif type(v) = type(()): +X print '(', +X printlist(v, maxlevel) +X print ')', +X elif type(v) = type([]): +X print '[', +X printlist(v, maxlevel) +X print ']', +X elif type(v) = type({}): +X print '{', +X printdict(v, maxlevel) +X print '}', +X else: +X print v, +X +Xdef printlist(v, maxlevel): +X n = len(v) +X if n = 0: return +X if maxlevel <= 0: +X print '...', +X return +X for i in range(min(6, n)): +X printobject(v[i], maxlevel-1) +X if i+1 < n: print ',', +X if n > 6: print '...', +X +Xdef printdict(v, maxlevel): +X keys = v.keys() +X n = len(keys) +X if n = 0: return +X if maxlevel <= 0: +X print '...', +X return +X keys.sort() +X for i in range(min(6, n)): +X key = keys[i] +X print `key` + ':', +X printobject(v[key], maxlevel-1) +X if i+1 < n: print ',', +X if n > 6: print '...', +X +X_filecache = {} +X +Xdef readfileline(filename, lineno): +X try: +X stat = os.stat(filename) +X except os.error, msg: +X print 'Cannot stat', filename, '--', msg +X return '' +X cache_ok = 0 +X if _filecache.has_key(filename): +X cached_stat, lines = _filecache[filename] +X if stat[ST_SIZE] = cached_stat[ST_SIZE] and \ +X stat[ST_MTIME] = cached_stat[ST_MTIME]: +X cache_ok = 1 +X else: +X print 'Stale cache entry for', filename +X del _filecache[filename] +X if not cache_ok: +X lines = readfilelines(filename) +X if not lines: +X return '' +X _filecache[filename] = stat, lines +X if 0 <= lineno-1 < len(lines): +X return lines[lineno-1] +X else: +X print 'Line number out of range, last line is', len(lines) +X return '' +X +Xdef readfilelines(filename): +X try: +X fp = open(filename, 'r') +X except: +X print 'Cannot open', filename +X return [] +X lines = [] +X while 1: +X line = fp.readline() +X if not line: break +X lines.append(line) +X if not lines: +X print 'Empty file', filename +X return lines +EOF +fi +if test -s 'src/errors.c' +then echo '*** I will not over-write existing file src/errors.c' +else +echo 'x - src/errors.c' +sed 's/^X//' > 'src/errors.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Error handling -- see also run.c */ +X +X/* New error handling interface. +X +X The following problem exists (existed): methods of built-in modules +X are called with 'self' and 'args' arguments, but without a context +X argument, so they have no way to raise a specific exception. +X The same is true for the object implementations: no context argument. +X The old convention was to set 'errno' and to return NULL. +X The caller (usually call_function() in eval.c) detects the NULL +X return value and then calls puterrno(ctx) to turn the errno value +X into a true exception. Problems with this approach are: +X - it used standard errno values to indicate Python-specific errors, +X but this means that when such an error code is reported by a system +X call (e.g., in module posix), the user gets a confusing message +X - errno is a global variable, which makes extensions to a multi- +X threading environment difficult; e.g., in IRIX, multi-threaded +X programs must use the function oserror() instead of looking in errno +X - there is no portable way to add new error numbers for specic +X situations -- the value space for errno is reserved to the OS, yet +X the way to turn module-specific errors into a module-specific +X exception requires module-specific values for errno +X - there is no way to add a more situation-specific message to an +X error. +X +X The new interface solves all these problems. To return an error, a +X built-in function calls err_set(exception), err_setval(exception, +X value) or err_setstr(exception, string), and returns NULL. These +X functions save the value for later use by puterrno(). To adapt this +X scheme to a multi-threaded environment, only the implementation of +X err_setval() has to be changed. +X*/ +X +X#include "allobjects.h" +X +X#include <errno.h> +X#ifndef errno +Xextern int errno; +X#endif +X +X#include "errcode.h" +X +Xextern char *strerror PROTO((int)); +X +X/* Last exception stored by err_setval() */ +X +Xstatic object *last_exception; +Xstatic object *last_exc_val; +X +Xvoid +Xerr_setval(exception, value) +X object *exception; +X object *value; +X{ +X XDECREF(last_exception); +X XINCREF(exception); +X last_exception = exception; +X +X XDECREF(last_exc_val); +X XINCREF(value); +X last_exc_val = value; +X} +X +Xvoid +Xerr_set(exception) +X object *exception; +X{ +X err_setval(exception, (object *)NULL); +X} +X +Xvoid +Xerr_setstr(exception, string) +X object *exception; +X char *string; +X{ +X object *value = newstringobject(string); +X err_setval(exception, value); +X XDECREF(value); +X} +X +Xint +Xerr_occurred() +X{ +X return last_exception != NULL; +X} +X +Xvoid +Xerr_get(p_exc, p_val) +X object **p_exc; +X object **p_val; +X{ +X *p_exc = last_exception; +X last_exception = NULL; +X *p_val = last_exc_val; +X last_exc_val = NULL; +X} +X +Xvoid +Xerr_clear() +X{ +X XDECREF(last_exception); +X last_exception = NULL; +X XDECREF(last_exc_val); +X last_exc_val = NULL; +X} +X +X/* Convenience functions to set a type error exception and return 0 */ +X +Xint +Xerr_badarg() +X{ +X err_setstr(TypeError, "illegal argument type for built-in operation"); +X return 0; +X} +X +Xobject * +Xerr_nomem() +X{ +X err_set(MemoryError); +X return NULL; +X} +X +Xobject * +Xerr_errno(exc) +X object *exc; +X{ +X object *v = newtupleobject(2); +X if (v != NULL) { +X settupleitem(v, 0, newintobject((long)errno)); +X settupleitem(v, 1, newstringobject(strerror(errno))); +X } +X err_setval(exc, v); +X XDECREF(v); +X return NULL; +X} +X +Xvoid +Xerr_badcall() +X{ +X err_setstr(SystemError, "bad argument to internal function"); +X} +X +X/* Set the error appropriate to the given input error code (see errcode.h) */ +X +Xvoid +Xerr_input(err) +X int err; +X{ +X switch (err) { +X case E_DONE: +X case E_OK: +X break; +X case E_SYNTAX: +X err_setstr(RuntimeError, "syntax error"); +X break; +X case E_TOKEN: +X err_setstr(RuntimeError, "illegal token"); +X break; +X case E_INTR: +X err_set(KeyboardInterrupt); +X break; +X case E_NOMEM: +X err_nomem(); +X break; +X case E_EOF: +X err_set(EOFError); +X break; +X default: +X err_setstr(RuntimeError, "unknown input error"); +X break; +X } +X} +EOF +fi +if test -s 'src/mathmodule.c' +then echo '*** I will not over-write existing file src/mathmodule.c' +else +echo 'x - src/mathmodule.c' +sed 's/^X//' > 'src/mathmodule.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Math module -- standard C math library functions, pi and e */ +X +X#include "allobjects.h" +X +X#include <errno.h> +X#ifndef errno +Xextern int errno; +X#endif +X +X#include "modsupport.h" +X +X#include <math.h> +X +Xstatic int +Xgetdoublearg(args, px) +X register object *args; +X double *px; +X{ +X if (args == NULL) +X return err_badarg(); +X if (is_floatobject(args)) { +X *px = getfloatvalue(args); +X return 1; +X } +X if (is_intobject(args)) { +X *px = getintvalue(args); +X return 1; +X } +X return err_badarg(); +X} +X +Xstatic int +Xget2doublearg(args, px, py) +X register object *args; +X double *px, *py; +X{ +X if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2) +X return err_badarg(); +X return getdoublearg(gettupleitem(args, 0), px) && +X getdoublearg(gettupleitem(args, 1), py); +X} +X +Xstatic object * +Xmath_1(args, func) +X object *args; +X double (*func) FPROTO((double)); +X{ +X double x; +X if (!getdoublearg(args, &x)) +X return NULL; +X errno = 0; +X x = (*func)(x); +X if (errno != 0) +X return NULL; +X else +X return newfloatobject(x); +X} +X +Xstatic object * +Xmath_2(args, func) +X object *args; +X double (*func) FPROTO((double, double)); +X{ +X double x, y; +X if (!get2doublearg(args, &x, &y)) +X return NULL; +X errno = 0; +X x = (*func)(x, y); +X if (errno != 0) +X return NULL; +X else +X return newfloatobject(x); +X} +X +X#define FUNC1(stubname, func) \ +X static object * stubname(self, args) object *self, *args; { \ +X return math_1(args, func); \ +X } +X +X#define FUNC2(stubname, func) \ +X static object * stubname(self, args) object *self, *args; { \ +X return math_2(args, func); \ +X } +X +XFUNC1(math_acos, acos) +XFUNC1(math_asin, asin) +XFUNC1(math_atan, atan) +XFUNC2(math_atan2, atan2) +XFUNC1(math_ceil, ceil) +XFUNC1(math_cos, cos) +XFUNC1(math_cosh, cosh) +XFUNC1(math_exp, exp) +XFUNC1(math_fabs, fabs) +XFUNC1(math_floor, floor) +X#if 0 +X/* XXX This one is not in the Amoeba library yet, so what the heck... */ +XFUNC2(math_fmod, fmod) +X#endif +XFUNC1(math_log, log) +XFUNC1(math_log10, log10) +XFUNC2(math_pow, pow) +XFUNC1(math_sin, sin) +XFUNC1(math_sinh, sinh) +XFUNC1(math_sqrt, sqrt) +XFUNC1(math_tan, tan) +XFUNC1(math_tanh, tanh) +X +X#if 0 +X/* What about these? */ +Xdouble frexp(double x, int *i); +Xdouble ldexp(double x, int n); +Xdouble modf(double x, double *i); +X#endif +X +Xstatic struct methodlist math_methods[] = { +X {"acos", math_acos}, +X {"asin", math_asin}, +X {"atan", math_atan}, +X {"atan2", math_atan2}, +X {"ceil", math_ceil}, +X {"cos", math_cos}, +X {"cosh", math_cosh}, +X {"exp", math_exp}, +X {"fabs", math_fabs}, +X {"floor", math_floor}, +X#if 0 +X {"fmod", math_fmod}, +X {"frexp", math_freqp}, +X {"ldexp", math_ldexp}, +X#endif +X {"log", math_log}, +X {"log10", math_log10}, +X#if 0 +X {"modf", math_modf}, +X#endif +X {"pow", math_pow}, +X {"sin", math_sin}, +X {"sinh", math_sinh}, +X {"sqrt", math_sqrt}, +X {"tan", math_tan}, +X {"tanh", math_tanh}, +X {NULL, NULL} /* sentinel */ +X}; +X +Xvoid +Xinitmath() +X{ +X object *m, *d, *v; +X +X m = initmodule("math", math_methods); +X d = getmoduledict(m); +X dictinsert(d, "pi", v = newfloatobject(atan(1.0) * 4.0)); +X DECREF(v); +X dictinsert(d, "e", v = newfloatobject(exp(1.0))); +X DECREF(v); +X} +EOF +fi +if test -s 'src/sysmodule.c' +then echo '*** I will not over-write existing file src/sysmodule.c' +else +echo 'x - src/sysmodule.c' +sed 's/^X//' > 'src/sysmodule.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* System module */ +X +X/* +XVarious bits of information used by the interpreter are collected in +Xmodule 'sys'. +XFunction member: +X- exit(sts): call (C, POSIX) exit(sts) +XData members: +X- stdin, stdout, stderr: standard file objects +X- modules: the table of modules (dictionary) +X- path: module search path (list of strings) +X- argv: script arguments (list of strings) +X- ps1, ps2: optional primary and secondary prompts (strings) +X*/ +X +X#include "allobjects.h" +X +X#include "sysmodule.h" +X#include "import.h" +X#include "modsupport.h" +X +X/* Define delimiter used in $PYTHONPATH */ +X +X#ifdef THINK_C +X#define DELIM ' ' +X#endif +X +X#ifndef DELIM +X#define DELIM ':' +X#endif +X +Xstatic object *sysdict; +X +Xobject * +Xsysget(name) +X char *name; +X{ +X return dictlookup(sysdict, name); +X} +X +XFILE * +Xsysgetfile(name, def) +X char *name; +X FILE *def; +X{ +X FILE *fp = NULL; +X object *v = sysget(name); +X if (v != NULL) +X fp = getfilefile(v); +X if (fp == NULL) +X fp = def; +X return fp; +X} +X +Xint +Xsysset(name, v) +X char *name; +X object *v; +X{ +X if (v == NULL) +X return dictremove(sysdict, name); +X else +X return dictinsert(sysdict, name, v); +X} +X +Xstatic object * +Xsys_exit(self, args) +X object *self; +X object *args; +X{ +X int sts; +X if (!getintarg(args, &sts)) +X return NULL; +X goaway(sts); +X exit(sts); /* Just in case */ +X /* NOTREACHED */ +X} +X +Xstatic struct methodlist sys_methods[] = { +X {"exit", sys_exit}, +X {NULL, NULL} /* sentinel */ +X}; +X +Xstatic object *sysin, *sysout, *syserr; +X +Xvoid +Xinitsys() +X{ +X object *m = initmodule("sys", sys_methods); +X sysdict = getmoduledict(m); +X INCREF(sysdict); +X /* NB keep an extra ref to the std files to avoid closing them +X when the user deletes them */ +X /* XXX File objects should have a "don't close" flag instead */ +X sysin = newopenfileobject(stdin, "<stdin>", "r"); +X sysout = newopenfileobject(stdout, "<stdout>", "w"); +X syserr = newopenfileobject(stderr, "<stderr>", "w"); +X if (err_occurred()) +X fatal("can't create sys.std* file objects"); +X dictinsert(sysdict, "stdin", sysin); +X dictinsert(sysdict, "stdout", sysout); +X dictinsert(sysdict, "stderr", syserr); +X dictinsert(sysdict, "modules", get_modules()); +X if (err_occurred()) +X fatal("can't insert sys.* objects in sys dict"); +X} +X +Xstatic object * +Xmakepathobject(path, delim) +X char *path; +X int delim; +X{ +X int i, n; +X char *p; +X object *v, *w; +X +X n = 1; +X p = path; +X while ((p = strchr(p, delim)) != NULL) { +X n++; +X p++; +X } +X v = newlistobject(n); +X if (v == NULL) +X return NULL; +X for (i = 0; ; i++) { +X p = strchr(path, delim); +X if (p == NULL) +X p = strchr(path, '\0'); /* End of string */ +X w = newsizedstringobject(path, (int) (p - path)); +X if (w == NULL) { +X DECREF(v); +X return NULL; +X } +X setlistitem(v, i, w); +X if (*p == '\0') +X break; +X path = p+1; +X } +X return v; +X} +X +Xvoid +Xsetpythonpath(path) +X char *path; +X{ +X object *v; +X if ((v = makepathobject(path, DELIM)) == NULL) +X fatal("can't create sys.path"); +X if (sysset("path", v) != 0) +X fatal("can't assign sys.path"); +X DECREF(v); +X} +X +Xstatic object * +Xmakeargvobject(argc, argv) +X int argc; +X char **argv; +X{ +X object *av; +X if (argc < 0 || argv == NULL) +X argc = 0; +X av = newlistobject(argc); +X if (av != NULL) { +X int i; +X for (i = 0; i < argc; i++) { +X object *v = newstringobject(argv[i]); +X if (v == NULL) { +X DECREF(av); +X av = NULL; +X break; +X } +X setlistitem(av, i, v); +X } +X } +X return av; +X} +X +Xvoid +Xsetpythonargv(argc, argv) +X int argc; +X char **argv; +X{ +X object *av = makeargvobject(argc, argv); +X if (av == NULL) +X fatal("no mem for sys.argv"); +X if (sysset("argv", av) != 0) +X fatal("can't assign sys.argv"); +X DECREF(av); +X} +EOF +fi +if test -s 'src/timemodule.c' +then echo '*** I will not over-write existing file src/timemodule.c' +else +echo 'x - src/timemodule.c' +sed 's/^X//' > 'src/timemodule.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Time module */ +X +X#include "allobjects.h" +X +X#include "modsupport.h" +X +X#include "sigtype.h" +X +X#include <signal.h> +X#include <setjmp.h> +X +X#ifdef __STDC__ +X#include <time.h> +X#else /* !__STDC__ */ +Xtypedef unsigned long time_t; +Xextern time_t time(); +X#endif /* !__STDC__ */ +X +X +X/* Time methods */ +X +Xstatic object * +Xtime_time(self, args) +X object *self; +X object *args; +X{ +X long secs; +X if (!getnoarg(args)) +X return NULL; +X secs = time((time_t *)NULL); +X return newintobject(secs); +X} +X +Xstatic jmp_buf sleep_intr; +X +Xstatic void +Xsleep_catcher(sig) +X int sig; +X{ +X longjmp(sleep_intr, 1); +X} +X +Xstatic object * +Xtime_sleep(self, args) +X object *self; +X object *args; +X{ +X int secs; +X SIGTYPE (*sigsave)(); +X if (!getintarg(args, &secs)) +X return NULL; +X if (setjmp(sleep_intr)) { +X signal(SIGINT, sigsave); +X err_set(KeyboardInterrupt); +X return NULL; +X } +X sigsave = signal(SIGINT, SIG_IGN); +X if (sigsave != (SIGTYPE (*)()) SIG_IGN) +X signal(SIGINT, sleep_catcher); +X sleep(secs); +X signal(SIGINT, sigsave); +X INCREF(None); +X return None; +X} +X +X#ifdef THINK_C +X#define DO_MILLI +X#endif /* THINK_C */ +X +X#ifdef AMOEBA +X#define DO_MILLI +Xextern long sys_milli(); +X#define millitimer sys_milli +X#endif /* AMOEBA */ +X +X#ifdef BSD_TIME +X#define DO_MILLI +X#endif /* BSD_TIME */ +X +X#ifdef DO_MILLI +X +Xstatic object * +Xtime_millisleep(self, args) +X object *self; +X object *args; +X{ +X long msecs; +X SIGTYPE (*sigsave)(); +X if (!getlongarg(args, &msecs)) +X return NULL; +X if (setjmp(sleep_intr)) { +X signal(SIGINT, sigsave); +X err_set(KeyboardInterrupt); +X return NULL; +X } +X sigsave = signal(SIGINT, SIG_IGN); +X if (sigsave != (SIGTYPE (*)()) SIG_IGN) +X signal(SIGINT, sleep_catcher); +X millisleep(msecs); +X signal(SIGINT, sigsave); +X INCREF(None); +X return None; +X} +X +Xstatic object * +Xtime_millitimer(self, args) +X object *self; +X object *args; +X{ +X long msecs; +X extern long millitimer(); +X if (!getnoarg(args)) +X return NULL; +X msecs = millitimer(); +X return newintobject(msecs); +X} +X +X#endif /* DO_MILLI */ +X +X +Xstatic struct methodlist time_methods[] = { +X#ifdef DO_MILLI +X {"millisleep", time_millisleep}, +X {"millitimer", time_millitimer}, +X#endif /* DO_MILLI */ +X {"sleep", time_sleep}, +X {"time", time_time}, +X {NULL, NULL} /* sentinel */ +X}; +X +X +Xvoid +Xinittime() +X{ +X initmodule("time", time_methods); +X} +X +X +X#ifdef THINK_C +X +X#define MacTicks (* (long *)0x16A) +X +Xstatic +Xsleep(msecs) +X int msecs; +X{ +X register long deadline; +X +X deadline = MacTicks + msecs * 60; +X while (MacTicks < deadline) { +X if (intrcheck()) +X sleep_catcher(SIGINT); +X } +X} +X +Xstatic +Xmillisleep(msecs) +X long msecs; +X{ +X register long deadline; +X +X deadline = MacTicks + msecs * 3 / 50; /* msecs * 60 / 1000 */ +X while (MacTicks < deadline) { +X if (intrcheck()) +X sleep_catcher(SIGINT); +X } +X} +X +Xstatic long +Xmillitimer() +X{ +X return MacTicks * 50 / 3; /* MacTicks * 1000 / 60 */ +X} +X +X#endif /* THINK_C */ +X +X +X#ifdef BSD_TIME +X +X#include <sys/types.h> +X#include <sys/time.h> +X +Xstatic long +Xmillitimer() +X{ +X struct timeval t; +X struct timezone tz; +X if (gettimeofday(&t, &tz) != 0) +X return -1; +X return t.tv_sec*1000 + t.tv_usec/1000; +X +X} +X +Xstatic +Xmillisleep(msecs) +X long msecs; +X{ +X struct timeval t; +X t.tv_sec = msecs/1000; +X t.tv_usec = (msecs%1000)*1000; +X (void) select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t); +X} +X +X#endif /* BSD_TIME */ +X +EOF +fi +if test -s 'src/traceback.c' +then echo '*** I will not over-write existing file src/traceback.c' +else +echo 'x - src/traceback.c' +sed 's/^X//' > 'src/traceback.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Traceback implementation */ +X +X#include "allobjects.h" +X +X#include "compile.h" +X#include "frameobject.h" +X#include "traceback.h" +X#include "structmember.h" +X +Xtypedef struct _tracebackobject { +X OB_HEAD +X struct _tracebackobject *tb_next; +X frameobject *tb_frame; +X int tb_lasti; +X int tb_lineno; +X} tracebackobject; +X +X#define OFF(x) offsetof(tracebackobject, x) +X +Xstatic struct memberlist tb_memberlist[] = { +X {"tb_next", T_OBJECT, OFF(tb_next)}, +X {"tb_frame", T_OBJECT, OFF(tb_frame)}, +X {"tb_lasti", T_INT, OFF(tb_lasti)}, +X {"tb_lineno", T_INT, OFF(tb_lineno)}, +X {NULL} /* Sentinel */ +X}; +X +Xstatic object * +Xtb_getattr(tb, name) +X tracebackobject *tb; +X char *name; +X{ +X return getmember((char *)tb, tb_memberlist, name); +X} +X +Xstatic void +Xtb_dealloc(tb) +X tracebackobject *tb; +X{ +X XDECREF(tb->tb_next); +X XDECREF(tb->tb_frame); +X DEL(tb); +X} +X +Xstatic typeobject Tracebacktype = { +X OB_HEAD_INIT(&Typetype) +X 0, +X "traceback", +X sizeof(tracebackobject), +X 0, +X tb_dealloc, /*tp_dealloc*/ +X 0, /*tp_print*/ +X tb_getattr, /*tp_getattr*/ +X 0, /*tp_setattr*/ +X 0, /*tp_compare*/ +X 0, /*tp_repr*/ +X 0, /*tp_as_number*/ +X 0, /*tp_as_sequence*/ +X 0, /*tp_as_mapping*/ +X}; +X +X#define is_tracebackobject(v) ((v)->ob_type == &Tracebacktype) +X +Xstatic tracebackobject * +Xnewtracebackobject(next, frame, lasti, lineno) +X tracebackobject *next; +X frameobject *frame; +X int lasti, lineno; +X{ +X tracebackobject *tb; +X if ((next != NULL && !is_tracebackobject(next)) || +X frame == NULL || !is_frameobject(frame)) { +X err_badcall(); +X return NULL; +X } +X tb = NEWOBJ(tracebackobject, &Tracebacktype); +X if (tb != NULL) { +X XINCREF(next); +X tb->tb_next = next; +X XINCREF(frame); +X tb->tb_frame = frame; +X tb->tb_lasti = lasti; +X tb->tb_lineno = lineno; +X } +X return tb; +X} +X +Xstatic tracebackobject *tb_current = NULL; +X +Xint +Xtb_here(frame, lasti, lineno) +X frameobject *frame; +X int lasti; +X int lineno; +X{ +X tracebackobject *tb; +X tb = newtracebackobject(tb_current, frame, lasti, lineno); +X if (tb == NULL) +X return -1; +X XDECREF(tb_current); +X tb_current = tb; +X return 0; +X} +X +Xobject * +Xtb_fetch() +X{ +X object *v; +X v = (object *)tb_current; +X tb_current = NULL; +X return v; +X} +X +Xint +Xtb_store(v) +X object *v; +X{ +X if (v != NULL && !is_tracebackobject(v)) { +X err_badcall(); +X return -1; +X } +X XDECREF(tb_current); +X XINCREF(v); +X tb_current = (tracebackobject *)v; +X return 0; +X} +X +Xstatic void +Xtb_displayline(fp, filename, lineno) +X FILE *fp; +X char *filename; +X int lineno; +X{ +X FILE *xfp; +X char buf[1000]; +X int i; +X if (filename[0] == '<' && filename[strlen(filename)-1] == '>') +X return; +X xfp = fopen(filename, "r"); +X if (xfp == NULL) { +X fprintf(fp, " (cannot open \"%s\")\n", filename); +X return; +X } +X for (i = 0; i < lineno; i++) { +X if (fgets(buf, sizeof buf, xfp) == NULL) +X break; +X } +X if (i == lineno) { +X char *p = buf; +X while (*p == ' ' || *p == '\t') +X p++; +X fprintf(fp, " %s", p); +X if (strchr(p, '\n') == NULL) +X fprintf(fp, "\n"); +X } +X fclose(xfp); +X} +X +Xstatic void +Xtb_printinternal(tb, fp) +X tracebackobject *tb; +X FILE *fp; +X{ +X while (tb != NULL) { +X if (intrcheck()) { +X fprintf(fp, "[interrupted]\n"); +X break; +X } +X fprintf(fp, " File \""); +X printobject(tb->tb_frame->f_code->co_filename, fp, PRINT_RAW); +X fprintf(fp, "\", line %d\n", tb->tb_lineno); +X tb_displayline(fp, +X getstringvalue(tb->tb_frame->f_code->co_filename), +X tb->tb_lineno); +X tb = tb->tb_next; +X } +X} +X +Xint +Xtb_print(v, fp) +X object *v; +X FILE *fp; +X{ +X if (v == NULL) +X return 0; +X if (!is_tracebackobject(v)) { +X err_badcall(); +X return -1; +X } +X sysset("last_traceback", v); +X tb_printinternal((tracebackobject *)v, fp); +X return 0; +X} +EOF +fi +echo 'Part 15 out of 21 of pack.out complete.' +exit 0 diff --git a/shar/python-0.9.1-16-21.shar b/shar/python-0.9.1-16-21.shar new file mode 100644 index 0000000..dc787e0 --- /dev/null +++ b/shar/python-0.9.1-16-21.shar @@ -0,0 +1,2495 @@ +: This is a shell archive. +: Extract with 'sh this_file'. +: +: Extract part 01 first since it makes all directories +echo 'Start of pack.out, part 16 out of 21:' +if test -s 'demo/sgi/gl_panel/flying/materials.s' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/flying/materials.s' +else +echo 'x - demo/sgi/gl_panel/flying/materials.s' +sed 's/^X//' > 'demo/sgi/gl_panel/flying/materials.s' << 'EOF' +X;;; This file was automatically generated by the panel editor. +X;;; If you read it into gnu emacs, it will automagically format itself. +X +X(panel (prop help creator:user-panel-help) +X(prop user-panel #t) +X(label "Materials") +X(al (pnl_label (prop help creator:user-act-help) +X(label "specular") +X(x 4) +X(y 0.5) +X(downfunc move-then-resize) +X) +X(pnl_label (prop help creator:user-act-help) +X(label "diffuse") +X(x 4) +X(y 4) +X(downfunc move-then-resize) +X) +X(pnl_radio_button (name "m7") +X(prop help creator:user-act-help) +X(label "material 7") +X(x 6.5) +X(y 1.5) +X(h 0.36) +X(downfunc move-then-resize) +X) +X(pnl_radio_button (name "m9") +X(prop help creator:user-act-help) +X(label "material 9") +X(x 6.5) +X(y 0.5) +X(h 0.36) +X(downfunc move-then-resize) +X) +X(pnl_radio_button (name "m8") +X(prop help creator:user-act-help) +X(label "material 8") +X(x 6.5) +X(y 1) +X(h 0.36) +X(downfunc move-then-resize) +X) +X(pnl_radio_button (name "m6") +X(prop help creator:user-act-help) +X(label "material 6") +X(x 6.5) +X(y 2) +X(h 0.36) +X(downfunc move-then-resize) +X) +X(pnl_radio_button (name "m5") +X(prop help creator:user-act-help) +X(label "material 5") +X(x 6.5) +X(y 2.5) +X(h 0.36) +X(downfunc move-then-resize) +X) +X(pnl_radio_button (name "m4") +X(prop help creator:user-act-help) +X(label "material 4") +X(x 6.5) +X(y 3) +X(h 0.36) +X(downfunc move-then-resize) +X) +X(pnl_radio_button (name "m3") +X(prop help creator:user-act-help) +X(label "material 3") +X(x 6.5) +X(y 3.5) +X(h 0.36) +X(downfunc move-then-resize) +X) +X(pnl_radio_button (name "m2") +X(prop help creator:user-act-help) +X(label "material 2") +X(x 6.5) +X(y 4) +X(h 0.36) +X(downfunc move-then-resize) +X) +X(pnl_radio_button (name "m1") +X(prop help creator:user-act-help) +X(label "material 1") +X(x 6.5) +X(y 4.5) +X(h 0.36) +X(downfunc move-then-resize) +X) +X(pnl_filled_hslider (name "diffB") +X(prop help creator:user-act-help) +X(label "B") +X(y 3.5) +X(w 3.3) +X(h 0.4) +X(labeltype 0) +X(downfunc move-then-resize) +X) +X(pnl_filled_hslider (name "diffG") +X(prop help creator:user-act-help) +X(label "G") +X(y 4) +X(w 3.3) +X(h 0.4) +X(labeltype 0) +X(downfunc move-then-resize) +X) +X(pnl_filled_hslider (name "diffR") +X(prop help creator:user-act-help) +X(label "R") +X(y 4.5) +X(w 3.3) +X(h 0.4) +X(labeltype 0) +X(downfunc move-then-resize) +X) +X(pnl_filled_hslider (name "specB") +X(prop help creator:user-act-help) +X(label "B") +X(w 3.3) +X(h 0.4) +X(labeltype 0) +X(downfunc move-then-resize) +X) +X(pnl_filled_hslider (name "specG") +X(prop help creator:user-act-help) +X(label "G") +X(y 0.5) +X(w 3.3) +X(h 0.4) +X(labeltype 0) +X(downfunc move-then-resize) +X) +X(pnl_filled_hslider (name "specR") +X(prop help creator:user-act-help) +X(label "R") +X(y 1) +X(w 3.3) +X(h 0.4) +X(labeltype 0) +X(downfunc move-then-resize) +X) +X(pnl_filled_hslider (name "shine") +X(prop help creator:user-act-help) +X(label "shininess") +X(y 2.25) +X(w 3.3) +X(h 0.4) +X(labeltype 0) +X(downfunc move-then-resize) +X) +X) +X) +X;;; Local Variables: +X;;; mode: scheme +X;;; eval: (save-excursion (goto-char (point-min)) (kill-line 3)) +X;;; eval: (save-excursion (goto-char (point-min)) (replace-regexp "[ \n]*)" ")")) +X;;; eval: (indent-region (point-min) (point-max) nil) +X;;; eval: (progn (kill-line -3) (delete-backward-char 1) (save-buffer)) +X;;; End: +EOF +fi +if test -s 'src/config.c' +then echo '*** I will not over-write existing file src/config.c' +else +echo 'x - src/config.c' +sed 's/^X//' > 'src/config.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Configurable Python configuration file */ +X +X#include <stdio.h> +X +X#ifdef USE_STDWIN +X#include <stdwin.h> +X +Xstatic int use_stdwin; +X#endif +X +X/*ARGSUSED*/ +Xvoid +Xinitargs(p_argc, p_argv) +X int *p_argc; +X char ***p_argv; +X{ +X#ifdef USE_STDWIN +X extern char *getenv(); +X char *display; +X +X /* Ignore an initial argument of '-s', for backward compatibility */ +X if (*p_argc > 1 && strcmp((*p_argv)[1], "-s") == 0) { +X (*p_argv)[1] = (*p_argv)[0]; +X (*p_argc)--, (*p_argv)++; +X } +X +X /* Assume we have to initialize stdwin if either of the following +X conditions holds: +X - the environment variable $DISPLAY is set +X - there is an argument "-display" somewhere +X */ +X +X display = getenv("DISPLAY"); +X if (display != 0) +X use_stdwin = 1; +X else { +X int i; +X /* Scan through the arguments looking for "-display" */ +X for (i = 1; i < *p_argc; i++) { +X if (strcmp((*p_argv)[i], "-display") == 0) { +X use_stdwin = 1; +X break; +X } +X } +X } +X +X if (use_stdwin) +X wargs(p_argc, p_argv); +X#endif +X} +X +Xvoid +Xinitcalls() +X{ +X} +X +Xvoid +Xdonecalls() +X{ +X#ifdef USE_STDWIN +X if (use_stdwin) +X wdone(); +X#endif +X#ifdef USE_AUDIO +X asa_done(); +X#endif +X} +X +X#ifdef USE_STDWIN +Xstatic void +Xmaybeinitstdwin() +X{ +X if (use_stdwin) +X initstdwin(); +X else +X fprintf(stderr, +X "No $DISPLAY nor -display arg -- stdwin not available\n"); +X} +X#endif +X +X#ifndef PYTHONPATH +X#define PYTHONPATH ".:/usr/local/lib/python" +X#endif +X +Xextern char *getenv(); +X +Xchar * +Xgetpythonpath() +X{ +X char *path = getenv("PYTHONPATH"); +X if (path == 0) +X path = PYTHONPATH; +X return path; +X} +X +X +X/* Table of built-in modules. +X These are initialized when first imported. */ +X +X/* Standard modules */ +Xextern void inittime(); +Xextern void initmath(); +Xextern void initregexp(); +Xextern void initposix(); +X#ifdef USE_AUDIO +Xextern void initaudio(); +X#endif +X#ifdef USE_AMOEBA +Xextern void initamoeba(); +X#endif +X#ifdef USE_GL +Xextern void initgl(); +X#ifdef USE_PANEL +Xextern void initpanel(); +X#endif +X#endif +X#ifdef USE_STDWIN +Xextern void maybeinitstdwin(); +X#endif +X +Xstruct { +X char *name; +X void (*initfunc)(); +X} inittab[] = { +X +X /* Standard modules */ +X +X {"time", inittime}, +X {"math", initmath}, +X {"regexp", initregexp}, +X {"posix", initposix}, +X +X +X /* Optional modules */ +X +X#ifdef USE_AUDIO +X {"audio", initaudio}, +X#endif +X +X#ifdef USE_AMOEBA +X {"amoeba", initamoeba}, +X#endif +X +X#ifdef USE_GL +X {"gl", initgl}, +X#ifdef USE_PANEL +X {"pnl", initpanel}, +X#endif +X#endif +X +X#ifdef USE_STDWIN +X {"stdwin", maybeinitstdwin}, +X#endif +X +X {0, 0} /* Sentinel */ +X}; +EOF +fi +if test -s 'src/frameobject.c' +then echo '*** I will not over-write existing file src/frameobject.c' +else +echo 'x - src/frameobject.c' +sed 's/^X//' > 'src/frameobject.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Frame object implementation */ +X +X#include "allobjects.h" +X +X#include "compile.h" +X#include "frameobject.h" +X#include "opcode.h" +X#include "structmember.h" +X +X#define OFF(x) offsetof(frameobject, x) +X +Xstatic struct memberlist frame_memberlist[] = { +X {"f_back", T_OBJECT, OFF(f_back)}, +X {"f_code", T_OBJECT, OFF(f_code)}, +X {"f_globals", T_OBJECT, OFF(f_globals)}, +X {"f_locals", T_OBJECT, OFF(f_locals)}, +X {NULL} /* Sentinel */ +X}; +X +Xstatic object * +Xframe_getattr(f, name) +X frameobject *f; +X char *name; +X{ +X return getmember((char *)f, frame_memberlist, name); +X} +X +Xstatic void +Xframe_dealloc(f) +X frameobject *f; +X{ +X XDECREF(f->f_back); +X XDECREF(f->f_code); +X XDECREF(f->f_globals); +X XDECREF(f->f_locals); +X XDEL(f->f_valuestack); +X XDEL(f->f_blockstack); +X DEL(f); +X} +X +Xtypeobject Frametype = { +X OB_HEAD_INIT(&Typetype) +X 0, +X "frame", +X sizeof(frameobject), +X 0, +X frame_dealloc, /*tp_dealloc*/ +X 0, /*tp_print*/ +X frame_getattr, /*tp_getattr*/ +X 0, /*tp_setattr*/ +X 0, /*tp_compare*/ +X 0, /*tp_repr*/ +X 0, /*tp_as_number*/ +X 0, /*tp_as_sequence*/ +X 0, /*tp_as_mapping*/ +X}; +X +Xframeobject * +Xnewframeobject(back, code, globals, locals, nvalues, nblocks) +X frameobject *back; +X codeobject *code; +X object *globals; +X object *locals; +X int nvalues; +X int nblocks; +X{ +X frameobject *f; +X if ((back != NULL && !is_frameobject(back)) || +X code == NULL || !is_codeobject(code) || +X globals == NULL || !is_dictobject(globals) || +X locals == NULL || !is_dictobject(locals) || +X nvalues < 0 || nblocks < 0) { +X err_badcall(); +X return NULL; +X } +X f = NEWOBJ(frameobject, &Frametype); +X if (f != NULL) { +X if (back) +X INCREF(back); +X f->f_back = back; +X INCREF(code); +X f->f_code = code; +X INCREF(globals); +X f->f_globals = globals; +X INCREF(locals); +X f->f_locals = locals; +X f->f_valuestack = NEW(object *, nvalues+1); +X f->f_blockstack = NEW(block, nblocks+1); +X f->f_nvalues = nvalues; +X f->f_nblocks = nblocks; +X f->f_iblock = 0; +X if (f->f_valuestack == NULL || f->f_blockstack == NULL) { +X err_nomem(); +X DECREF(f); +X f = NULL; +X } +X } +X return f; +X} +X +X/* Block management */ +X +Xvoid +Xsetup_block(f, type, handler, level) +X frameobject *f; +X int type; +X int handler; +X int level; +X{ +X block *b; +X if (f->f_iblock >= f->f_nblocks) { +X fprintf(stderr, "XXX block stack overflow\n"); +X abort(); +X } +X b = &f->f_blockstack[f->f_iblock++]; +X b->b_type = type; +X b->b_level = level; +X b->b_handler = handler; +X} +X +Xblock * +Xpop_block(f) +X frameobject *f; +X{ +X block *b; +X if (f->f_iblock <= 0) { +X fprintf(stderr, "XXX block stack underflow\n"); +X abort(); +X } +X b = &f->f_blockstack[--f->f_iblock]; +X return b; +X} +EOF +fi +if test -s 'src/metagrammar.c' +then echo '*** I will not over-write existing file src/metagrammar.c' +else +echo 'x - src/metagrammar.c' +sed 's/^X//' > 'src/metagrammar.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X#include "pgenheaders.h" +X#include "metagrammar.h" +X#include "grammar.h" +X#include "pgen.h" +Xstatic arc arcs_0_0[3] = { +X {2, 0}, +X {3, 0}, +X {4, 1}, +X}; +Xstatic arc arcs_0_1[1] = { +X {0, 1}, +X}; +Xstatic state states_0[2] = { +X {3, arcs_0_0}, +X {1, arcs_0_1}, +X}; +Xstatic arc arcs_1_0[1] = { +X {5, 1}, +X}; +Xstatic arc arcs_1_1[1] = { +X {6, 2}, +X}; +Xstatic arc arcs_1_2[1] = { +X {7, 3}, +X}; +Xstatic arc arcs_1_3[1] = { +X {3, 4}, +X}; +Xstatic arc arcs_1_4[1] = { +X {0, 4}, +X}; +Xstatic state states_1[5] = { +X {1, arcs_1_0}, +X {1, arcs_1_1}, +X {1, arcs_1_2}, +X {1, arcs_1_3}, +X {1, arcs_1_4}, +X}; +Xstatic arc arcs_2_0[1] = { +X {8, 1}, +X}; +Xstatic arc arcs_2_1[2] = { +X {9, 0}, +X {0, 1}, +X}; +Xstatic state states_2[2] = { +X {1, arcs_2_0}, +X {2, arcs_2_1}, +X}; +Xstatic arc arcs_3_0[1] = { +X {10, 1}, +X}; +Xstatic arc arcs_3_1[2] = { +X {10, 1}, +X {0, 1}, +X}; +Xstatic state states_3[2] = { +X {1, arcs_3_0}, +X {2, arcs_3_1}, +X}; +Xstatic arc arcs_4_0[2] = { +X {11, 1}, +X {13, 2}, +X}; +Xstatic arc arcs_4_1[1] = { +X {7, 3}, +X}; +Xstatic arc arcs_4_2[3] = { +X {14, 4}, +X {15, 4}, +X {0, 2}, +X}; +Xstatic arc arcs_4_3[1] = { +X {12, 4}, +X}; +Xstatic arc arcs_4_4[1] = { +X {0, 4}, +X}; +Xstatic state states_4[5] = { +X {2, arcs_4_0}, +X {1, arcs_4_1}, +X {3, arcs_4_2}, +X {1, arcs_4_3}, +X {1, arcs_4_4}, +X}; +Xstatic arc arcs_5_0[3] = { +X {5, 1}, +X {16, 1}, +X {17, 2}, +X}; +Xstatic arc arcs_5_1[1] = { +X {0, 1}, +X}; +Xstatic arc arcs_5_2[1] = { +X {7, 3}, +X}; +Xstatic arc arcs_5_3[1] = { +X {18, 1}, +X}; +Xstatic state states_5[4] = { +X {3, arcs_5_0}, +X {1, arcs_5_1}, +X {1, arcs_5_2}, +X {1, arcs_5_3}, +X}; +Xstatic dfa dfas[6] = { +X {256, "MSTART", 0, 2, states_0, +X "\070\000\000"}, +X {257, "RULE", 0, 5, states_1, +X "\040\000\000"}, +X {258, "RHS", 0, 2, states_2, +X "\040\010\003"}, +X {259, "ALT", 0, 2, states_3, +X "\040\010\003"}, +X {260, "ITEM", 0, 5, states_4, +X "\040\010\003"}, +X {261, "ATOM", 0, 4, states_5, +X "\040\000\003"}, +X}; +Xstatic label labels[19] = { +X {0, "EMPTY"}, +X {256, 0}, +X {257, 0}, +X {4, 0}, +X {0, 0}, +X {1, 0}, +X {11, 0}, +X {258, 0}, +X {259, 0}, +X {18, 0}, +X {260, 0}, +X {9, 0}, +X {10, 0}, +X {261, 0}, +X {16, 0}, +X {14, 0}, +X {3, 0}, +X {7, 0}, +X {8, 0}, +X}; +Xstatic grammar gram = { +X 6, +X dfas, +X {19, labels}, +X 256 +X}; +X +Xgrammar * +Xmeta_grammar() +X{ +X return &gram; +X} +EOF +fi +if test -s 'src/methodobject.c' +then echo '*** I will not over-write existing file src/methodobject.c' +else +echo 'x - src/methodobject.c' +sed 's/^X//' > 'src/methodobject.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Method object implementation */ +X +X#include "allobjects.h" +X +X#include "token.h" +X +Xtypedef struct { +X OB_HEAD +X char *m_name; +X method m_meth; +X object *m_self; +X} methodobject; +X +Xobject * +Xnewmethodobject(name, meth, self) +X char *name; /* static string */ +X method meth; +X object *self; +X{ +X methodobject *op = NEWOBJ(methodobject, &Methodtype); +X if (op != NULL) { +X op->m_name = name; +X op->m_meth = meth; +X if (self != NULL) +X INCREF(self); +X op->m_self = self; +X } +X return (object *)op; +X} +X +Xmethod +Xgetmethod(op) +X object *op; +X{ +X if (!is_methodobject(op)) { +X err_badcall(); +X return NULL; +X } +X return ((methodobject *)op) -> m_meth; +X} +X +Xobject * +Xgetself(op) +X object *op; +X{ +X if (!is_methodobject(op)) { +X err_badcall(); +X return NULL; +X } +X return ((methodobject *)op) -> m_self; +X} +X +X/* Methods (the standard built-in methods, that is) */ +X +Xstatic void +Xmeth_dealloc(m) +X methodobject *m; +X{ +X if (m->m_self != NULL) +X DECREF(m->m_self); +X free((char *)m); +X} +X +Xstatic void +Xmeth_print(m, fp, flags) +X methodobject *m; +X FILE *fp; +X int flags; +X{ +X if (m->m_self == NULL) +X fprintf(fp, "<built-in function '%s'>", m->m_name); +X else +X fprintf(fp, "<built-in method '%s' of some %s object>", +X m->m_name, m->m_self->ob_type->tp_name); +X} +X +Xstatic object * +Xmeth_repr(m) +X methodobject *m; +X{ +X char buf[200]; +X if (m->m_self == NULL) +X sprintf(buf, "<built-in function '%.80s'>", m->m_name); +X else +X sprintf(buf, +X "<built-in method '%.80s' of some %.80s object>", +X m->m_name, m->m_self->ob_type->tp_name); +X return newstringobject(buf); +X} +X +Xtypeobject Methodtype = { +X OB_HEAD_INIT(&Typetype) +X 0, +X "method", +X sizeof(methodobject), +X 0, +X meth_dealloc, /*tp_dealloc*/ +X meth_print, /*tp_print*/ +X 0, /*tp_getattr*/ +X 0, /*tp_setattr*/ +X 0, /*tp_compare*/ +X meth_repr, /*tp_repr*/ +X 0, /*tp_as_number*/ +X 0, /*tp_as_sequence*/ +X 0, /*tp_as_mapping*/ +X}; +X +X/* Find a method in a module's method table. +X Usually called from an object's getattr method. */ +X +Xobject * +Xfindmethod(ml, op, name) +X struct methodlist *ml; +X object *op; +X char *name; +X{ +X for (; ml->ml_name != NULL; ml++) { +X if (strcmp(name, ml->ml_name) == 0) +X return newmethodobject(ml->ml_name, ml->ml_meth, op); +X } +X err_setstr(NameError, name); +X return NULL; +X} +EOF +fi +if test -s 'src/moduleobject.c' +then echo '*** I will not over-write existing file src/moduleobject.c' +else +echo 'x - src/moduleobject.c' +sed 's/^X//' > 'src/moduleobject.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Module object implementation */ +X +X#include "allobjects.h" +X +Xtypedef struct { +X OB_HEAD +X object *md_name; +X object *md_dict; +X} moduleobject; +X +Xobject * +Xnewmoduleobject(name) +X char *name; +X{ +X moduleobject *m = NEWOBJ(moduleobject, &Moduletype); +X if (m == NULL) +X return NULL; +X m->md_name = newstringobject(name); +X m->md_dict = newdictobject(); +X if (m->md_name == NULL || m->md_dict == NULL) { +X DECREF(m); +X return NULL; +X } +X return (object *)m; +X} +X +Xobject * +Xgetmoduledict(m) +X object *m; +X{ +X if (!is_moduleobject(m)) { +X err_badcall(); +X return NULL; +X } +X return ((moduleobject *)m) -> md_dict; +X} +X +Xchar * +Xgetmodulename(m) +X object *m; +X{ +X if (!is_moduleobject(m)) { +X err_badarg(); +X return NULL; +X } +X return getstringvalue(((moduleobject *)m) -> md_name); +X} +X +X/* Methods */ +X +Xstatic void +Xmodule_dealloc(m) +X moduleobject *m; +X{ +X if (m->md_name != NULL) +X DECREF(m->md_name); +X if (m->md_dict != NULL) +X DECREF(m->md_dict); +X free((char *)m); +X} +X +Xstatic void +Xmodule_print(m, fp, flags) +X moduleobject *m; +X FILE *fp; +X int flags; +X{ +X fprintf(fp, "<module '%s'>", getstringvalue(m->md_name)); +X} +X +Xstatic object * +Xmodule_repr(m) +X moduleobject *m; +X{ +X char buf[100]; +X sprintf(buf, "<module '%.80s'>", getstringvalue(m->md_name)); +X return newstringobject(buf); +X} +X +Xstatic object * +Xmodule_getattr(m, name) +X moduleobject *m; +X char *name; +X{ +X object *res; +X if (strcmp(name, "__dict__") == 0) { +X INCREF(m->md_dict); +X return m->md_dict; +X } +X if (strcmp(name, "__name__") == 0) { +X INCREF(m->md_name); +X return m->md_name; +X } +X res = dictlookup(m->md_dict, name); +X if (res == NULL) +X err_setstr(NameError, name); +X else +X INCREF(res); +X return res; +X} +X +Xstatic int +Xmodule_setattr(m, name, v) +X moduleobject *m; +X char *name; +X object *v; +X{ +X if (strcmp(name, "__dict__") == 0 || strcmp(name, "__name__") == 0) { +X err_setstr(NameError, "can't assign to reserved member name"); +X return -1; +X } +X if (v == NULL) +X return dictremove(m->md_dict, name); +X else +X return dictinsert(m->md_dict, name, v); +X} +X +Xtypeobject Moduletype = { +X OB_HEAD_INIT(&Typetype) +X 0, /*ob_size*/ +X "module", /*tp_name*/ +X sizeof(moduleobject), /*tp_size*/ +X 0, /*tp_itemsize*/ +X module_dealloc, /*tp_dealloc*/ +X module_print, /*tp_print*/ +X module_getattr, /*tp_getattr*/ +X module_setattr, /*tp_setattr*/ +X 0, /*tp_compare*/ +X module_repr, /*tp_repr*/ +X}; +EOF +fi +if test -s 'src/opcode.h' +then echo '*** I will not over-write existing file src/opcode.h' +else +echo 'x - src/opcode.h' +sed 's/^X//' > 'src/opcode.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Instruction opcodes for compiled code */ +X +X#define STOP_CODE 0 +X#define POP_TOP 1 +X#define ROT_TWO 2 +X#define ROT_THREE 3 +X#define DUP_TOP 4 +X +X#define UNARY_POSITIVE 10 +X#define UNARY_NEGATIVE 11 +X#define UNARY_NOT 12 +X#define UNARY_CONVERT 13 +X#define UNARY_CALL 14 +X +X#define BINARY_MULTIPLY 20 +X#define BINARY_DIVIDE 21 +X#define BINARY_MODULO 22 +X#define BINARY_ADD 23 +X#define BINARY_SUBTRACT 24 +X#define BINARY_SUBSCR 25 +X#define BINARY_CALL 26 +X +X#define SLICE 30 +X/* Also uses 31-33 */ +X +X#define STORE_SLICE 40 +X/* Also uses 41-43 */ +X +X#define DELETE_SLICE 50 +X/* Also uses 51-53 */ +X +X#define STORE_SUBSCR 60 +X#define DELETE_SUBSCR 61 +X +X#define PRINT_EXPR 70 +X#define PRINT_ITEM 71 +X#define PRINT_NEWLINE 72 +X +X#define BREAK_LOOP 80 +X#define RAISE_EXCEPTION 81 +X#define LOAD_LOCALS 82 +X#define RETURN_VALUE 83 +X#define REQUIRE_ARGS 84 +X#define REFUSE_ARGS 85 +X#define BUILD_FUNCTION 86 +X#define POP_BLOCK 87 +X#define END_FINALLY 88 +X#define BUILD_CLASS 89 +X +X#define HAVE_ARGUMENT 90 /* Opcodes from here have an argument: */ +X +X#define STORE_NAME 90 /* Index in name list */ +X#define DELETE_NAME 91 /* "" */ +X#define UNPACK_TUPLE 92 /* Number of tuple items */ +X#define UNPACK_LIST 93 /* Number of list items */ +X/* unused: 94 */ +X#define STORE_ATTR 95 /* Index in name list */ +X#define DELETE_ATTR 96 /* "" */ +X +X#define LOAD_CONST 100 /* Index in const list */ +X#define LOAD_NAME 101 /* Index in name list */ +X#define BUILD_TUPLE 102 /* Number of tuple items */ +X#define BUILD_LIST 103 /* Number of list items */ +X#define BUILD_MAP 104 /* Always zero for now */ +X#define LOAD_ATTR 105 /* Index in name list */ +X#define COMPARE_OP 106 /* Comparison operator */ +X#define IMPORT_NAME 107 /* Index in name list */ +X#define IMPORT_FROM 108 /* Index in name list */ +X +X#define JUMP_FORWARD 110 /* Number of bytes to skip */ +X#define JUMP_IF_FALSE 111 /* "" */ +X#define JUMP_IF_TRUE 112 /* "" */ +X#define JUMP_ABSOLUTE 113 /* Target byte offset from beginning of code */ +X#define FOR_LOOP 114 /* Number of bytes to skip */ +X +X#define SETUP_LOOP 120 /* Target address (absolute) */ +X#define SETUP_EXCEPT 121 /* "" */ +X#define SETUP_FINALLY 122 /* "" */ +X +X#define SET_LINENO 127 /* Current line number */ +X +X/* Comparison operator codes (argument to COMPARE_OP) */ +Xenum cmp_op {LT, LE, EQ, NE, GT, GE, IN, NOT_IN, IS, IS_NOT, EXC_MATCH, BAD}; +X +X#define HAS_ARG(op) ((op) >= HAVE_ARGUMENT) +EOF +fi +if test -s 'src/parsetok.c' +then echo '*** I will not over-write existing file src/parsetok.c' +else +echo 'x - src/parsetok.c' +sed 's/^X//' > 'src/parsetok.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Parser-tokenizer link implementation */ +X +X#include "pgenheaders.h" +X#include "tokenizer.h" +X#include "node.h" +X#include "grammar.h" +X#include "parser.h" +X#include "parsetok.h" +X#include "errcode.h" +X +X +X/* Forward */ +Xstatic int parsetok PROTO((struct tok_state *, grammar *, int, node **)); +X +X +X/* Parse input coming from a string. Return error code, print some errors. */ +X +Xint +Xparsestring(s, g, start, n_ret) +X char *s; +X grammar *g; +X int start; +X node **n_ret; +X{ +X struct tok_state *tok = tok_setups(s); +X int ret; +X +X if (tok == NULL) { +X fprintf(stderr, "no mem for tok_setups\n"); +X return E_NOMEM; +X } +X ret = parsetok(tok, g, start, n_ret); +X if (ret == E_TOKEN || ret == E_SYNTAX) { +X fprintf(stderr, "String parsing error at line %d\n", +X tok->lineno); +X } +X tok_free(tok); +X return ret; +X} +X +X +X/* Parse input coming from a file. Return error code, print some errors. */ +X +Xint +Xparsefile(fp, filename, g, start, ps1, ps2, n_ret) +X FILE *fp; +X char *filename; +X grammar *g; +X int start; +X char *ps1, *ps2; +X node **n_ret; +X{ +X struct tok_state *tok = tok_setupf(fp, ps1, ps2); +X int ret; +X +X if (tok == NULL) { +X fprintf(stderr, "no mem for tok_setupf\n"); +X return E_NOMEM; +X } +X ret = parsetok(tok, g, start, n_ret); +X if (ret == E_TOKEN || ret == E_SYNTAX) { +X char *p; +X fprintf(stderr, "Parsing error: file %s, line %d:\n", +X filename, tok->lineno); +X *tok->inp = '\0'; +X if (tok->inp > tok->buf && tok->inp[-1] == '\n') +X tok->inp[-1] = '\0'; +X fprintf(stderr, "%s\n", tok->buf); +X for (p = tok->buf; p < tok->cur; p++) { +X if (*p == '\t') +X putc('\t', stderr); +X else +X putc(' ', stderr); +X } +X fprintf(stderr, "^\n"); +X } +X tok_free(tok); +X return ret; +X} +X +X +X/* Parse input coming from the given tokenizer structure. +X Return error code. */ +X +Xstatic int +Xparsetok(tok, g, start, n_ret) +X struct tok_state *tok; +X grammar *g; +X int start; +X node **n_ret; +X{ +X parser_state *ps; +X int ret; +X +X if ((ps = newparser(g, start)) == NULL) { +X fprintf(stderr, "no mem for new parser\n"); +X return E_NOMEM; +X } +X +X for (;;) { +X char *a, *b; +X int type; +X int len; +X char *str; +X +X type = tok_get(tok, &a, &b); +X if (type == ERRORTOKEN) { +X ret = tok->done; +X break; +X } +X len = b - a; +X str = NEW(char, len + 1); +X if (str == NULL) { +X fprintf(stderr, "no mem for next token\n"); +X ret = E_NOMEM; +X break; +X } +X strncpy(str, a, len); +X str[len] = '\0'; +X ret = addtoken(ps, (int)type, str, tok->lineno); +X if (ret != E_OK) { +X if (ret == E_DONE) { +X *n_ret = ps->p_tree; +X ps->p_tree = NULL; +X } +X else if (tok->lineno <= 1 && tok->done == E_EOF) +X ret = E_EOF; +X break; +X } +X } +X +X delparser(ps); +X return ret; +X} +EOF +fi +if test -s 'src/pgenmain.c' +then echo '*** I will not over-write existing file src/pgenmain.c' +else +echo 'x - src/pgenmain.c' +sed 's/^X//' > 'src/pgenmain.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Parser generator main program */ +X +X/* This expects a filename containing the grammar as argv[1] (UNIX) +X or asks the console for such a file name (THINK C). +X It writes its output on two files in the current directory: +X - "graminit.c" gets the grammar as a bunch of initialized data +X - "graminit.h" gets the grammar's non-terminals as #defines. +X Error messages and status info during the generation process are +X written to stdout, or sometimes to stderr. */ +X +X#include "pgenheaders.h" +X#include "grammar.h" +X#include "node.h" +X#include "parsetok.h" +X#include "pgen.h" +X +Xint debugging; +X +X/* Forward */ +Xgrammar *getgrammar PROTO((char *filename)); +X#ifdef THINK_C +Xint main PROTO((int, char **)); +Xchar *askfile PROTO((void)); +X#endif +X +Xint +Xmain(argc, argv) +X int argc; +X char **argv; +X{ +X grammar *g; +X node *n; +X FILE *fp; +X char *filename; +X +X#ifdef THINK_C +X filename = askfile(); +X#else +X if (argc != 2) { +X fprintf(stderr, "usage: %s grammar\n", argv[0]); +X exit(2); +X } +X filename = argv[1]; +X#endif +X g = getgrammar(filename); +X fp = fopen("graminit.c", "w"); +X if (fp == NULL) { +X perror("graminit.c"); +X exit(1); +X } +X printf("Writing graminit.c ...\n"); +X printgrammar(g, fp); +X fclose(fp); +X fp = fopen("graminit.h", "w"); +X if (fp == NULL) { +X perror("graminit.h"); +X exit(1); +X } +X printf("Writing graminit.h ...\n"); +X printnonterminals(g, fp); +X fclose(fp); +X exit(0); +X} +X +Xgrammar * +Xgetgrammar(filename) +X char *filename; +X{ +X FILE *fp; +X node *n; +X grammar *g0, *g; +X +X fp = fopen(filename, "r"); +X if (fp == NULL) { +X perror(filename); +X exit(1); +X } +X g0 = meta_grammar(); +X n = NULL; +X parsefile(fp, filename, g0, g0->g_start, (char *)NULL, (char *)NULL, &n); +X fclose(fp); +X if (n == NULL) { +X fprintf(stderr, "Parsing error.\n"); +X exit(1); +X } +X g = pgen(n); +X if (g == NULL) { +X printf("Bad grammar.\n"); +X exit(1); +X } +X return g; +X} +X +X#ifdef THINK_C +Xchar * +Xaskfile() +X{ +X char buf[256]; +X static char name[256]; +X printf("Input file name: "); +X if (fgets(buf, sizeof buf, stdin) == NULL) { +X printf("EOF\n"); +X exit(1); +X } +X /* XXX The (unsigned char *) case is needed by THINK C 3.0 */ +X if (sscanf(/*(unsigned char *)*/buf, " %s ", name) != 1) { +X printf("No file\n"); +X exit(1); +X } +X return name; +X} +X#endif +X +Xvoid +Xfatal(msg) +X char *msg; +X{ +X fprintf(stderr, "pgen: FATAL ERROR: %s\n", msg); +X exit(1); +X} +X +X/* XXX TO DO: +X - check for duplicate definitions of names (instead of fatal err) +X*/ +EOF +fi +if test -s 'src/printgrammar.c' +then echo '*** I will not over-write existing file src/printgrammar.c' +else +echo 'x - src/printgrammar.c' +sed 's/^X//' > 'src/printgrammar.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Print a bunch of C initializers that represent a grammar */ +X +X#include "pgenheaders.h" +X#include "grammar.h" +X +X/* Forward */ +Xstatic void printarcs PROTO((int, dfa *, FILE *)); +Xstatic void printstates PROTO((grammar *, FILE *)); +Xstatic void printdfas PROTO((grammar *, FILE *)); +Xstatic void printlabels PROTO((grammar *, FILE *)); +X +Xvoid +Xprintgrammar(g, fp) +X grammar *g; +X FILE *fp; +X{ +X fprintf(fp, "#include \"pgenheaders.h\"\n"); +X fprintf(fp, "#include \"grammar.h\"\n"); +X printdfas(g, fp); +X printlabels(g, fp); +X fprintf(fp, "grammar gram = {\n"); +X fprintf(fp, "\t%d,\n", g->g_ndfas); +X fprintf(fp, "\tdfas,\n"); +X fprintf(fp, "\t{%d, labels},\n", g->g_ll.ll_nlabels); +X fprintf(fp, "\t%d\n", g->g_start); +X fprintf(fp, "};\n"); +X} +X +Xvoid +Xprintnonterminals(g, fp) +X grammar *g; +X FILE *fp; +X{ +X dfa *d; +X int i; +X +X d = g->g_dfa; +X for (i = g->g_ndfas; --i >= 0; d++) +X fprintf(fp, "#define %s %d\n", d->d_name, d->d_type); +X} +X +Xstatic void +Xprintarcs(i, d, fp) +X int i; +X dfa *d; +X FILE *fp; +X{ +X arc *a; +X state *s; +X int j, k; +X +X s = d->d_state; +X for (j = 0; j < d->d_nstates; j++, s++) { +X fprintf(fp, "static arc arcs_%d_%d[%d] = {\n", +X i, j, s->s_narcs); +X a = s->s_arc; +X for (k = 0; k < s->s_narcs; k++, a++) +X fprintf(fp, "\t{%d, %d},\n", a->a_lbl, a->a_arrow); +X fprintf(fp, "};\n"); +X } +X} +X +Xstatic void +Xprintstates(g, fp) +X grammar *g; +X FILE *fp; +X{ +X state *s; +X dfa *d; +X int i, j; +X +X d = g->g_dfa; +X for (i = 0; i < g->g_ndfas; i++, d++) { +X printarcs(i, d, fp); +X fprintf(fp, "static state states_%d[%d] = {\n", +X i, d->d_nstates); +X s = d->d_state; +X for (j = 0; j < d->d_nstates; j++, s++) +X fprintf(fp, "\t{%d, arcs_%d_%d},\n", +X s->s_narcs, i, j); +X fprintf(fp, "};\n"); +X } +X} +X +Xstatic void +Xprintdfas(g, fp) +X grammar *g; +X FILE *fp; +X{ +X dfa *d; +X int i, j; +X +X printstates(g, fp); +X fprintf(fp, "static dfa dfas[%d] = {\n", g->g_ndfas); +X d = g->g_dfa; +X for (i = 0; i < g->g_ndfas; i++, d++) { +X fprintf(fp, "\t{%d, \"%s\", %d, %d, states_%d,\n", +X d->d_type, d->d_name, d->d_initial, d->d_nstates, i); +X fprintf(fp, "\t \""); +X for (j = 0; j < NBYTES(g->g_ll.ll_nlabels); j++) +X fprintf(fp, "\\%03o", d->d_first[j] & 0xff); +X fprintf(fp, "\"},\n"); +X } +X fprintf(fp, "};\n"); +X} +X +Xstatic void +Xprintlabels(g, fp) +X grammar *g; +X FILE *fp; +X{ +X label *l; +X int i; +X +X fprintf(fp, "static label labels[%d] = {\n", g->g_ll.ll_nlabels); +X l = g->g_ll.ll_label; +X for (i = g->g_ll.ll_nlabels; --i >= 0; l++) { +X if (l->lb_str == NULL) +X fprintf(fp, "\t{%d, 0},\n", l->lb_type); +X else +X fprintf(fp, "\t{%d, \"%s\"},\n", +X l->lb_type, l->lb_str); +X } +X fprintf(fp, "};\n"); +X} +EOF +fi +if test -s 'src/regsub.c' +then echo '*** I will not over-write existing file src/regsub.c' +else +echo 'x - src/regsub.c' +sed 's/^X//' > 'src/regsub.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* +X * regsub +X * +X * Copyright (c) 1986 by University of Toronto. +X * Written by Henry Spencer. Not derived from licensed software. +X#ifdef MULTILINE +X * Changed by Guido van Rossum, CWI, Amsterdam +X * for multi-line support. +X#endif +X * +X * Permission is granted to anyone to use this software for any +X * purpose on any computer system, and to redistribute it freely, +X * subject to the following restrictions: +X * +X * 1. The author is not responsible for the consequences of use of +X * this software, no matter how awful, even if they arise +X * from defects in it. +X * +X * 2. The origin of this software must not be misrepresented, either +X * by explicit claim or by omission. +X * +X * 3. Altered versions must be plainly marked as such, and must not +X * be misrepresented as being the original software. +X */ +X#include <stdio.h> +X#include "regexp.h" +X#include "regmagic.h" +X +X#ifndef CHARBITS +X#define UCHARAT(p) ((int)*(unsigned char *)(p)) +X#else +X#define UCHARAT(p) ((int)*(p)&CHARBITS) +X#endif +X +X/* +X - regsub - perform substitutions after a regexp match +X */ +Xvoid +Xregsub(prog, source, dest) +Xregexp *prog; +Xchar *source; +Xchar *dest; +X{ +X register char *src; +X register char *dst; +X register char c; +X register int no; +X register int len; +X extern char *strncpy(); +X +X if (prog == NULL || source == NULL || dest == NULL) { +X regerror("NULL parm to regsub"); +X return; +X } +X if (UCHARAT(prog->program) != MAGIC) { +X regerror("damaged regexp fed to regsub"); +X return; +X } +X +X src = source; +X dst = dest; +X while ((c = *src++) != '\0') { +X if (c == '&') +X no = 0; +X else if (c == '\\' && '0' <= *src && *src <= '9') +X no = *src++ - '0'; +X else +X no = -1; +X +X if (no < 0) { /* Ordinary character. */ +X if (c == '\\' && (*src == '\\' || *src == '&')) +X c = *src++; +X#ifdef MULTILINE +X else if (c == '\\' && *src == 'n') { +X c = '\n'; +X src++; +X } +X#endif +X *dst++ = c; +X } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) { +X len = prog->endp[no] - prog->startp[no]; +X (void) strncpy(dst, prog->startp[no], len); +X dst += len; +X if (len != 0 && *(dst-1) == '\0') { /* strncpy hit NUL. */ +X regerror("damaged match string"); +X return; +X } +X } +X } +X *dst++ = '\0'; +X} +EOF +fi +if test -s 'src/sc_errors.c' +then echo '*** I will not over-write existing file src/sc_errors.c' +else +echo 'x - src/sc_errors.c' +sed 's/^X//' > 'src/sc_errors.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X +X#include <stdio.h> +X +X#include "PROTO.h" +X#include "object.h" +X#include "errors.h" +X#include "sc_errors.h" +X#include "stringobject.h" +X#include "tupleobject.h" +X +Xobject * +Xerr_scerr(sc_errno) +X int sc_errno; +X{ +X switch(sc_errno) { +X +X case NoBufSize: +X err_setstr(StubcodeError, "Stubcode didn't start with BufSize"); +X break; +X +X case TwoBufSize: +X err_setstr(StubcodeError, "Stubcode can't have more then one BufSize"); +X break; +X +X case ElementIsNull: +X err_setstr(StubcodeError, "Trying to access an NIL object"); +X break; +X +X case StackOverflow: +X err_setstr(StubcodeError, "Stack overflow"); +X return NULL; +X +X case StackUnderflow: +X err_setstr(StubcodeError, "Stack underflow"); +X return NULL; +X +X case NoEndLoop: +X err_setstr(StubcodeError, "LoopXXX with no EndLoop"); +X return NULL; +X +X case BufferOverflow: +X err_setstr(StubcodeError, "Buffer overflow"); +X return NULL; +X +X } +X return NULL; +X} +X +Xerr_scerrset(sc_errno, value, instr) +X int sc_errno; +X object *value; +X char *instr; +X{ +X object *str, *str1, *t; +X +X if ((t = newtupleobject(3)) == NULL) { +X return -1; +X } +X if ((str = newstringobject(instr)) == NULL) { +X return -1; +X } +X if (settupleitem(t, 2, str) != 0) { +X return -1; +X } +X INCREF(value); +X if (settupleitem(t, 1, value) != 0) { +X DECREF(t); +X return -1; +X } +X switch(sc_errno) { +X +X case TypeFailure: +X if ((str1 = newstringobject("Unexpected type")) == NULL) { +X DECREF(t); +X return -1; +X } +X break; +X +X case RangeError: +X if ((str1 = newstringobject("Value out of range")) == NULL) { +X DECREF(t); +X return -1; +X } +X break; +X +X case SizeError: +X if ((str1 = newstringobject("Value doesn't have the right size")) == NULL) { +X DECREF(t); +X return -1; +X } +X break; +X +X case FlagError: +X if ((str1 = newstringobject("Illegal flag value")) == NULL) { +X DECREF(t); +X return -1; +X } +X break; +X +X case TransError: +X if ((str1 = newstringobject("hdr.h_status != 0")) == NULL) { +X DECREF(t); +X return -1; +X } +X break; +X +X default: +X if ((str1 = newstringobject("sc_errno not found")) == NULL) { +X DECREF(t); +X return -1; +X } +X break; +X } +X if (settupleitem(t, 0, str1) != 0) { +X DECREF(t); +X return -1; +X } +X err_setval(StubcodeError, t); +X DECREF(t); +X return -1; +X} +EOF +fi +if test -s 'src/sc_global.h' +then echo '*** I will not over-write existing file src/sc_global.h' +else +echo 'x - src/sc_global.h' +sed 's/^X//' > 'src/sc_global.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X +X/* +X** This file contains the data used in Ail, Python and sc2txt. +X** +X** If you want to add an instuction to the instructions just define +X** it here and add the instruction in the function sc_interpreter in +X** the file sc_interpreter.c in the switch. You also have to make a +X** new function with the name x{instruction_name} in the file +X** sc_interpreter. +X*/ +X +X/* +X** When you want to change the types of the opcode or the operand +X** you maybe need to adjust the options to mypf. And the defines : +X** SwapOpcode, SwapOperand. +X*/ +X +Xtypedef unsigned char TscOpcode; +Xtypedef long TscOperand; +X +X#define SC_MAGIC 0x19901991 +X +X#define SwapOpcode(x) x = x +X#define SwapOperand(l) ((l))=(((((l))>>24)&0xFF)|((((l))>>8)&0xFF00)|((((l))<<8)&0xFF0000)|((((l))<<24)&0xFF000000)) +X +X#define STKSIZE 256 +X +X#define OPERAND 0x80 +X#define FLAGS 0x40 +X +X/* +X** The headerfields. The value of the flag is the index of the fields +X** array from the file mhdr.c plus one +X*/ +X +X#define H_EXTRA 0x00000001 +X#define H_SIZE 0x00000002 +X#define H_OFFSET 0x00000003 +X#define H_PORT 0x00000004 +X#define H_PRIV 0x00000005 +X#define PSEUDOFIELD 0x00000006 +X#define ALL_FIELDS 0x000000ff +X +X/* +X** The specefiers for the integers +X*/ +X +X#define NOSIGN 0x00000100 +X#define INT32 0x00000200 +X#define ALLTYPES 0xffffff00 +X +X/* +X** The opcode with no operand +X*/ +X +X#define ListS 0x00 +X#define PutVS 0x01 +X#define GetVS 0x02 +X#define StringS 0x03 +X#define Equal 0x04 +X#define NoArgs 0x05 +X +X/* +X * Between 0x10 and 0x3f there is space for predefined marshal +X * and unmarshal functions or macros that do not have an operand +X */ +X +X#define MarshTC 0x10 +X#define UnMarshTC 0x11 +X +X/* +X** The opcode with a number as operand +X*/ +X +X#define BufSize 0x80 +X#define Trans 0x81 +X#define TTupleS 0x82 +X#define Unpack 0x83 +X#define PutFS 0x84 +X#define TStringSeq 0x85 +X#define TStringSlt 0x86 +X#define TListSeq 0x87 +X#define TListSlt 0x88 +X#define LoopPut 0x89 +X#define EndLoop 0x8a +X#define Dup 0x8b +X#define Pop 0x8c +X#define Align 0x8d +X#define Pack 0x8e +X#define LoopGet 0x8f +X#define GetFS 0x90 +X#define PushI 0x91 +X +X/* +X** Between 0xa0 and 0xbf there is space for predefined marshal +X** and unmarshal functions or macros with a numberas operand +X*/ +X +X +X/* +X** The opcodes with flags as operand +X*/ +X +X#define AilWord 0xc0 +X#define PutI 0xc1 +X#define PutC 0xc2 +X#define GetI 0xc3 +X#define GetC 0xc4 +X +X/* +X** Between 0xe0 and 0xff there is space for predefined marshal +X** and unmarshal functions or macros with flags as operand +X*/ +EOF +fi +if test -s 'src/scdbg.c' +then echo '*** I will not over-write existing file src/scdbg.c' +else +echo 'x - src/scdbg.c' +sed 's/^X//' > 'src/scdbg.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X +X#include "sc_global.h" +X +Xvoid xPrintNum(Num) +XTscOperand Num; +X{ +X +X printf(" %ld",(long)Num); +X} +X +Xvoid xPrintFlags(Flags) +XTscOperand Flags; +X{ +Xlong x; +X +X x = (long)Flags; +X x = x & 0x0000000F; +X if (x == H_EXTRA) printf(" h_extra"); +X if (x == H_SIZE) printf(" h_size"); +X if (x == H_OFFSET) printf(" h_offset"); +X if (x == H_PORT) printf(" h_port"); +X if (x == H_PRIV) printf(" h_priv"); +X if (x == PSEUDOFIELD) printf(" h_port and h_priv"); +X x = (long)Flags; +X if (x & NOSIGN) printf(" unsigned"); +X if (x & INT32) printf(" int32"); +X} +X +Xvoid xPrintCode(Opcode) +XTscOpcode Opcode; +X{ +X +X switch (Opcode) { +X +X case BufSize: printf("BufSize"); +X break; +X +X case Trans: printf("Trans"); +X break; +X +X case TTupleS: printf("TTupleS"); +X break; +X +X case Unpack: printf("Unpack"); +X break; +X +X case AilWord: printf("AilWord"); +X break; +X +X case ListS: printf("ListS"); +X break; +X +X case StringS: printf("StringS"); +X break; +X +X case PutFS: printf("PutFS"); +X break; +X +X case TStringSeq: printf("TStringSeq"); +X break; +X +X case TStringSlt: printf("TStringSlt"); +X break; +X +X case PutVS: printf("PutVS"); +X break; +X +X case TListSeq: printf("TListSeq"); +X break; +X +X case TListSlt: printf("TListSlt"); +X break; +X +X case LoopPut: printf("LoopPut"); +X break; +X +X case EndLoop: printf("EndLoop"); +X break; +X +X case PutI: printf("PutI"); +X break; +X +X case PutC: printf("PutC"); +X break; +X +X case Dup: printf("Dup"); +X break; +X +X case Pop: printf("Pop"); +X break; +X +X case Align: printf("Align"); +X break; +X +X case Pack: printf("Pack"); +X break; +X +X case GetVS: printf("GetVS"); +X break; +X +X case LoopGet: printf("LoopGet"); +X break; +X +X case GetFS: printf("GetFS"); +X break; +X +X case GetI: printf("GetI"); +X break; +X +X case GetC: printf("GetC"); +X break; +X +X case PushI: printf("PushI"); +X break; +X +X case MarshTC: printf("MarshTC"); +X break; +X +X case UnMarshTC: printf("UnMarshTC"); +X break; +X +X case Equal: printf("Equal"); +X break; +X +X default: printf("Unknown opcode %04x",(int)Opcode); +X break; +X } +X} +EOF +fi +if test -s 'src/structmember.c' +then echo '*** I will not over-write existing file src/structmember.c' +else +echo 'x - src/structmember.c' +sed 's/^X//' > 'src/structmember.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Map C struct members to Python object attributes */ +X +X#include "allobjects.h" +X +X#include "structmember.h" +X +Xobject * +Xgetmember(addr, mlist, name) +X char *addr; +X struct memberlist *mlist; +X char *name; +X{ +X struct memberlist *l; +X +X for (l = mlist; l->name != NULL; l++) { +X if (strcmp(l->name, name) == 0) { +X object *v; +X addr += l->offset; +X switch (l->type) { +X case T_SHORT: +X v = newintobject((long) *(short*)addr); +X break; +X case T_INT: +X v = newintobject((long) *(int*)addr); +X break; +X case T_LONG: +X v = newintobject(*(long*)addr); +X break; +X case T_FLOAT: +X v = newfloatobject((double)*(float*)addr); +X break; +X case T_DOUBLE: +X v = newfloatobject(*(double*)addr); +X break; +X case T_STRING: +X if (*(char**)addr == NULL) { +X INCREF(None); +X v = None; +X } +X else +X v = newstringobject(*(char**)addr); +X break; +X case T_OBJECT: +X v = *(object **)addr; +X if (v == NULL) +X v = None; +X INCREF(v); +X break; +X default: +X err_setstr(SystemError, "bad memberlist type"); +X v = NULL; +X } +X return v; +X } +X } +X +X err_setstr(NameError, name); +X return NULL; +X} +X +Xint +Xsetmember(addr, mlist, name, v) +X char *addr; +X struct memberlist *mlist; +X char *name; +X object *v; +X{ +X struct memberlist *l; +X +X for (l = mlist; l->name != NULL; l++) { +X if (strcmp(l->name, name) == 0) { +X if (l->readonly || l->type == T_STRING) { +X err_setstr(RuntimeError, "readonly attribute"); +X return -1; +X } +X addr += l->offset; +X switch (l->type) { +X case T_SHORT: +X if (!is_intobject(v)) { +X err_badarg(); +X return -1; +X } +X *(short*)addr = getintvalue(v); +X break; +X case T_INT: +X if (!is_intobject(v)) { +X err_badarg(); +X return -1; +X } +X *(int*)addr = getintvalue(v); +X break; +X case T_LONG: +X if (!is_intobject(v)) { +X err_badarg(); +X return -1; +X } +X *(long*)addr = getintvalue(v); +X break; +X case T_FLOAT: +X if (is_intobject(v)) +X *(float*)addr = getintvalue(v); +X else if (is_floatobject(v)) +X *(float*)addr = getfloatvalue(v); +X else { +X err_badarg(); +X return -1; +X } +X break; +X case T_DOUBLE: +X if (is_intobject(v)) +X *(double*)addr = getintvalue(v); +X else if (is_floatobject(v)) +X *(double*)addr = getfloatvalue(v); +X else { +X err_badarg(); +X return -1; +X } +X break; +X case T_OBJECT: +X XDECREF(*(object **)addr); +X XINCREF(v); +X *(object **)addr = v; +X break; +X default: +X err_setstr(SystemError, "bad memberlist type"); +X return -1; +X } +X return 0; +X } +X } +X +X err_setstr(NameError, name); +X return -1; +X} +EOF +fi +if test -s 'src/xxobject.c' +then echo '*** I will not over-write existing file src/xxobject.c' +else +echo 'x - src/xxobject.c' +sed 's/^X//' > 'src/xxobject.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Use this file as a template to start implementing a new object type. +X If your objects will be called foobar, start by copying this file to +X foobarobject.c, changing all occurrences of xx to foobar and all +X occurrences of Xx by Foobar. You will probably want to delete all +X references to 'x_attr' and add your own types of attributes +X instead. Maybe you want to name your local variables other than +X 'xp'. If your object type is needed in other files, you'll have to +X create a file "foobarobject.h"; see intobject.h for an example. */ +X +X +X/* Xx objects */ +X +X#include "allobjects.h" +X +Xtypedef struct { +X OB_HEAD +X object *x_attr; /* Attributes dictionary */ +X} xxobject; +X +Xextern typeobject Xxtype; /* Really static, forward */ +X +X#define is_xxobject(v) ((v)->ob_type == &Xxtype) +X +Xstatic xxobject * +Xnewxxobject(arg) +X object *arg; +X{ +X xxobject *xp; +X xp = NEWOBJ(xxobject, &Xxtype); +X if (xp == NULL) +X return NULL; +X xp->x_attr = NULL; +X return xp; +X} +X +X/* Xx methods */ +X +Xstatic void +Xxx_dealloc(xp) +X xxobject *xp; +X{ +X XDECREF(xp->x_attr); +X DEL(xp); +X} +X +Xstatic object * +Xxx_demo(self, args) +X xxobject *self; +X object *args; +X{ +X if (!getnoarg(args)) +X return NULL; +X INCREF(None); +X return None; +X} +X +Xstatic struct methodlist xx_methods[] = { +X "demo", xx_demo, +X {NULL, NULL} /* sentinel */ +X}; +X +Xstatic object * +Xxx_getattr(xp, name) +X xxobject *xp; +X char *name; +X{ +X if (xp->x_attr != NULL) { +X object *v = dictlookup(xp->x_attr, name); +X if (v != NULL) { +X INCREF(v); +X return v; +X } +X } +X return findmethod(xx_methods, (object *)xp, name); +X} +X +Xstatic int +Xxx_setattr(xp, name, v) +X xxobject *xp; +X char *name; +X object *v; +X{ +X if (xp->x_attr == NULL) { +X xp->x_attr = newdictobject(); +X if (xp->x_attr == NULL) +X return -1; +X } +X if (v == NULL) +X return dictremove(xp->x_attr, name); +X else +X return dictinsert(xp->x_attr, name, v); +X} +X +Xstatic typeobject Xxtype = { +X OB_HEAD_INIT(&Typetype) +X 0, /*ob_size*/ +X "xx", /*tp_name*/ +X sizeof(xxobject), /*tp_size*/ +X 0, /*tp_itemsize*/ +X /* methods */ +X xx_dealloc, /*tp_dealloc*/ +X 0, /*tp_print*/ +X xx_getattr, /*tp_getattr*/ +X xx_setattr, /*tp_setattr*/ +X 0, /*tp_compare*/ +X 0, /*tp_repr*/ +X}; +EOF +fi +echo 'Part 16 out of 21 of pack.out complete.' +exit 0 diff --git a/shar/python-0.9.1-17-21.shar b/shar/python-0.9.1-17-21.shar new file mode 100644 index 0000000..1ab184e --- /dev/null +++ b/shar/python-0.9.1-17-21.shar @@ -0,0 +1,2464 @@ +: This is a shell archive. +: Extract with 'sh this_file'. +: +: Extract part 01 first since it makes all directories +echo 'Start of pack.out, part 17 out of 21:' +if test -s 'demo/sgi/gl/nurbs.py' +then echo '*** I will not over-write existing file demo/sgi/gl/nurbs.py' +else +echo 'x - demo/sgi/gl/nurbs.py' +sed 's/^X//' > 'demo/sgi/gl/nurbs.py' << 'EOF' +X#! /ufs/guido/bin/sgi/python +X +X# Rotate a 3D surface created using NURBS. +X# +X# Press left mouse button to toggle surface trimming. +X# Press ESC to quit. +X# +X# See the GL manual for an explanation of NURBS. +X +Xfrom gl import * +Xfrom GL import * +Xfrom DEVICE import * +X +XTRUE = 1 +XFALSE = 0 +XORDER = 4 +X +Xidmat = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1] +X +Xsurfknots = [-1, -1, -1, -1, 1, 1, 1, 1] +X +Xdef make_ctlpoints(): +X c = [] +X # +X ci = [] +X ci.append(-2.5, -3.7, 1.0) +X ci.append(-1.5, -3.7, 3.0) +X ci.append(1.5, -3.7, -2.5) +X ci.append(2.5, -3.7, -0.75) +X c.append(ci) +X # +X ci = [] +X ci.append(-2.5, -2.0, 3.0) +X ci.append(-1.5, -2.0, 4.0) +X ci.append(1.5, -2.0, -3.0) +X ci.append(2.5, -2.0, 0.0) +X c.append(ci) +X # +X ci = [] +X ci.append(-2.5, 2.0, 1.0) +X ci.append(-1.5, 2.0, 0.0) +X ci.append(1.5, 2.0, -1.0) +X ci.append(2.5, 2.0, 2.0) +X c.append(ci) +X # +X ci = [] +X ci.append(-2.5, 2.7, 1.25) +X ci.append(-1.5, 2.7, 0.1) +X ci.append(1.5, 2.7, -0.6) +X ci.append(2.5, 2.7, 0.2) +X c.append(ci) +X # +X return c +X +Xctlpoints = make_ctlpoints() +X +Xtrimknots = [0., 0., 0., 1., 1., 2., 2., 3., 3., 4., 4., 4.] +X +Xdef make_trimpoints(): +X c = [] +X c.append(1.0, 0.0, 1.0) +X c.append(1.0, 1.0, 1.0) +X c.append(0.0, 2.0, 2.0) +X c.append(-1.0, 1.0, 1.0) +X c.append(-1.0, 0.0, 1.0) +X c.append(-1.0, -1.0, 1.0) +X c.append(0.0, -2.0, 2.0) +X c.append(1.0, -1.0, 1.0) +X c.append(1.0, 0.0, 1.0) +X return c +X +Xtrimpoints = make_trimpoints() +X +Xdef main(): +X init_windows() +X setup_queue() +X make_lights() +X init_view() +X # +X set_scene() +X setnurbsproperty( N_ERRORCHECKING, 1.0 ) +X setnurbsproperty( N_PIXEL_TOLERANCE, 50.0 ) +X trim_flag = 0 +X draw_trim_surface(trim_flag) +X # +X while 1: +X while qtest(): +X dev, val = qread() +X if dev = ESCKEY: +X return +X elif dev = WINQUIT: +X dglclose(-1) # this for DGL only +X return +X elif dev = REDRAW: +X reshapeviewport() +X set_scene() +X draw_trim_surface(trim_flag) +X elif dev = LEFTMOUSE: +X if val: +X trim_flag = (not trim_flag) +X set_scene() +X draw_trim_surface(trim_flag) +X +Xdef init_windows(): +X foreground() +X #prefposition(0, 500, 0, 500) +X wid = winopen('nurbs') +X wintitle('NURBS Surface') +X doublebuffer() +X RGBmode() +X gconfig() +X lsetdepth(0x000, 0x7fffff) +X zbuffer( TRUE ) +X +Xdef setup_queue(): +X qdevice(ESCKEY) +X qdevice(REDRAW) +X qdevice(RIGHTMOUSE) +X qdevice(WINQUIT) +X qdevice(LEFTMOUSE) #trimming +X +Xdef init_view(): +X mmode(MPROJECTION) +X ortho( -4., 4., -4., 4., -4., 4. ) +X # +X mmode(MVIEWING) +X loadmatrix(idmat) +X # +X lmbind(MATERIAL, 1) +X +Xdef set_scene(): +X lmbind(MATERIAL, 0) +X RGBcolor(150,150,150) +X lmbind(MATERIAL, 1) +X clear() +X zclear() +X # +X rotate( 100, 'y' ) +X rotate( 100, 'z' ) +X +Xdef draw_trim_surface(trim_flag): +X bgnsurface() +X nurbssurface(surfknots, surfknots, ctlpoints, ORDER, ORDER, N_XYZ) +X if trim_flag: +X bgntrim() +X nurbscurve(trimknots, trimpoints, ORDER-1, N_STW) +X endtrim() +X endsurface() +X swapbuffers() +X +Xdef make_lights(): +X lmdef(DEFLMODEL,1,[]) +X lmdef(DEFLIGHT,1,[]) +X # +X # define material #1 +X # +X a = [] +X a = a + [EMISSION, 0.0, 0.0, 0.0] +X a = a + [AMBIENT, 0.1, 0.1, 0.1] +X a = a + [DIFFUSE, 0.6, 0.3, 0.3] +X a = a + [SPECULAR, 0.0, 0.6, 0.0] +X a = a + [SHININESS, 2.0] +X a = a + [LMNULL] +X lmdef(DEFMATERIAL, 1, a) +X # +X # turn on lighting +X # +X lmbind(LIGHT0, 1) +X lmbind(LMODEL, 1) +X +Xmain() +EOF +chmod +x 'demo/sgi/gl/nurbs.py' +fi +if test -s 'demo/sgi/gl/zrgb.py' +then echo '*** I will not over-write existing file demo/sgi/gl/zrgb.py' +else +echo 'x - demo/sgi/gl/zrgb.py' +sed 's/^X//' > 'demo/sgi/gl/zrgb.py' << 'EOF' +X#! /ufs/guido/bin/sgi/python +X +X# zrgb (Requires Z buffer.) +X# +X# This program demostrates zbuffering 3 intersecting RGB polygons while +X# in doublebuffer mode where, movement of the mouse with the LEFTMOUSE +X# button depressed will, rotate the 3 polygons. This is done by compound +X# rotations allowing continuous screen-oriented rotations. +X# +X# Press the "Esc" key to exit. +X +Xfrom gl import * +Xfrom GL import * +Xfrom DEVICE import * +X +X +Xobjmat=[1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0] +X +Xidmat=[1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0] +X +Xdef main() : +X # +X # old and new mouse position +X # +X # +X mode = 0 +X omx = 0 +X mx = 0 +X omy = 0 +X my = 0 +X # +X initialize () +X # +X draw_scene (objmat) +X # +X while (1) : +X # +X dev, val = qread() +X # +X if dev = ESCKEY : +X if val : +X break +X # exit when key is going up, not down +X # this avoids the scenario where a window +X # underneath this program's window +X # would otherwise "eat up" the up- +X # event of the Esc key being released +X return +X # +X elif dev = REDRAW : +X reshapeviewport() +X draw_scene(objmat) +X # +X elif dev = LEFTMOUSE: +X omx = mx +X omy = my +X if val : +X mode = 1 +X else : +X mode = 0 +X elif dev = MOUSEX : +X omx = mx +X mx = val +X #print omx, mx +X objmat = update_scene(objmat,mx,my,omx,omy,mode) +X # +X elif dev = MOUSEY : +X omy = my +X my = val +X #print omy, my +X objmat = update_scene(objmat,mx,my,omx,omy,mode) +X # +X +X +Xdef initialize () : +X # +X foreground () +X keepaspect(5, 4) +X w = winopen('Zbuffered RGB') +X # +X doublebuffer() +X RGBmode() +X gconfig() +X zbuffer(1) +X lsetdepth(0x0, 0x7FFFFF) +X # +X qdevice(ESCKEY) +X qdevice(LEFTMOUSE) +X qdevice(MOUSEX) +X qdevice(MOUSEY) +X +Xdef update_scene (mat, mx, my, omx, omy, mode) : +X # +X if mode = 1 : +X mat = orient(mat, mx, my, omx, omy) +X draw_scene(mat) +X return mat +X +Xdef orient (mat, mx, my, omx, omy) : +X # +X # +X pushmatrix() +X loadmatrix(idmat) +X # +X if mx - omx : rot (float (mx - omx), 'y') +X if omy - my : rot (float (omy - my), 'x') +X # +X multmatrix(mat) +X mat = getmatrix() +X # +X # +X popmatrix() +X # +X return mat +X +Xdef draw_scene (mat) : +X RGBcolor(40, 100, 200) +X clear() +X zclear() +X # +X perspective(400, 1.25, 30.0, 60.0) +X translate(0.0, 0.0, -40.0) +X multmatrix(mat) +X # +X # skews original view to show all polygons +X # +X rotate(-580, 'y') +X draw_polys() +X # +X swapbuffers() +X +Xpolygon1 = [(-10.0,-10.0,0.0),(10.0,-10.0,0.0),(-10.0,10.0,0.0)] +X +Xpolygon2 = [(0.0,-10.0,-10.0),(0.0,-10.0,10.0),(0.0,5.0,-10.0)] +X +Xpolygon3 = [(-10.0,6.0,4.0),(-10.0,3.0,4.0),(4.0,-9.0,-10.0),(4.0,-6.0,-10.0)] +X +Xdef draw_polys(): +X bgnpolygon() +X cpack(0x0) +X v3f(polygon1[0]) +X cpack(0x007F7F7F) +X v3f(polygon1[1]) +X cpack(0x00FFFFFF) +X v3f(polygon1[2]) +X endpolygon() +X # +X bgnpolygon() +X cpack(0x0000FFFF) +X v3f(polygon2[0]) +X cpack(0x007FFF00) +X v3f(polygon2[1]) +X cpack(0x00FF0000) +X v3f(polygon2[2]) +X endpolygon() +X # +X bgnpolygon() +X cpack(0x0000FFFF) +X v3f(polygon3[0]) +X cpack(0x00FF00FF) +X v3f(polygon3[1]) +X cpack(0x00FF0000) +X v3f(polygon3[2]) +X cpack(0x00FF00FF) +X v3f(polygon3[3]) +X endpolygon() +X +X +Xmain () +EOF +chmod +x 'demo/sgi/gl/zrgb.py' +fi +if test -s 'demo/sgi/gl_panel/flying/flying.s' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/flying/flying.s' +else +echo 'x - demo/sgi/gl_panel/flying/flying.s' +sed 's/^X//' > 'demo/sgi/gl_panel/flying/flying.s' << 'EOF' +X;;; This file was automatically generated by the panel editor. +X;;; If you read it into gnu emacs, it will automagically format itself. +X +X(panel (prop help creator:user-panel-help) +X(prop user-panel #t) +X(label "flying objects") +X(al (pnl_toggle_button (name "table") +X(prop help creator:user-act-help) +X(label "table") +X(x 4.75) +X(y 0.25) +X(downfunc move-then-resize) +X) +X(pnl_toggle_button (name "pyramid") +X(prop help creator:user-act-help) +X(label "pyramid") +X(x 4.75) +X(y 0.75) +X(downfunc move-then-resize) +X) +X(pnl_toggle_button (name "glass") +X(prop help creator:user-act-help) +X(label "glass") +X(x 4.75) +X(y 1.25) +X(downfunc move-then-resize) +X) +X(pnl_toggle_button (name "diamond") +X(prop help creator:user-act-help) +X(label "diamond") +X(x 4.75) +X(y 1.75) +X(downfunc move-then-resize) +X) +X(pnl_toggle_button (name "disk") +X(prop help creator:user-act-help) +X(label "disk") +X(x 4.75) +X(y 2.25) +X(downfunc move-then-resize) +X) +X(pnl_toggle_button (name "icecream") +X(prop help creator:user-act-help) +X(label "ice cream") +X(x 4.75) +X(y 2.75) +X(downfunc move-then-resize) +X) +X(pnl_toggle_button (name "cube") +X(prop help creator:user-act-help) +X(label "cube") +X(x 4.75) +X(y 3.25) +X(val 1) +X(downfunc move-then-resize) +X) +X(pnl_toggle_button (name "cylinder") +X(prop help creator:user-act-help) +X(label "cylinder") +X(x 4.75) +X(y 3.75) +X(downfunc move-then-resize) +X) +X(pnl_toggle_button (name "sphere") +X(prop help creator:user-act-help) +X(label "sphere") +X(x 4.75) +X(y 4.25) +X(downfunc move-then-resize) +X) +X(pnl_button (name "quit") +X(prop help creator:user-act-help) +X(label "quit") +X(x 0.25) +X(y 2.25) +X(w 1.3) +X(h 0.65) +X(labeltype 16) +X(downfunc move-then-resize) +X) +X(pnl_button (name "showall") +X(prop help creator:user-act-help) +X(label "show all") +X(x 3.75) +X(y 3.75) +X(labeltype 8) +X(downfunc move-then-resize) +X) +X(pnl_button (name "shownone") +X(prop help creator:user-act-help) +X(label "show none") +X(x 3.75) +X(y 3.25) +X(labeltype 8) +X(downfunc move-then-resize) +X) +X(pnl_radio_button (name "wire") +X(prop end-of-group #t) +X(prop help creator:user-act-help) +X(label "wire frame") +X(x 0.25) +X(y 4.5) +X(h 0.36) +X(downfunc move-then-resize) +X) +X(pnl_radio_button (name "filled") +X(prop help creator:user-act-help) +X(label "filled") +X(x 0.25) +X(y 4) +X(h 0.36) +X(val 1) +X(downfunc move-then-resize) +X) +X(pnl_radio_button (name "flat") +X(prop end-of-group #t) +X(prop help creator:user-act-help) +X(label "flat shaded") +X(x 0.25) +X(y 0.5) +X(h 0.36) +X(downfunc move-then-resize) +X) +X(pnl_radio_button (name "gouraud") +X(prop help creator:user-act-help) +X(label "gouraud shaded") +X(x 0.25) +X(h 0.36) +X(val 1) +X(downfunc move-then-resize) +X) +X) +X) +X;;; Local Variables: +X;;; mode: scheme +X;;; eval: (save-excursion (goto-char (point-min)) (kill-line 3)) +X;;; eval: (save-excursion (goto-char (point-min)) (replace-regexp "[ \n]*)" ")")) +X;;; eval: (indent-region (point-min) (point-max) nil) +X;;; eval: (progn (kill-line -3) (delete-backward-char 1) (save-buffer)) +X;;; End: +EOF +fi +if test -s 'demo/sgi/gl_panel/flying/objectdef.py' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/flying/objectdef.py' +else +echo 'x - demo/sgi/gl_panel/flying/objectdef.py' +sed 's/^X//' > 'demo/sgi/gl_panel/flying/objectdef.py' << 'EOF' +Xfrom math import * +Xfrom objdict import * +Xfrom gl import * +X +XFUZZY = 0.00001 +X +X# first try - brute force method (ala M.Overmars...) +X +Xdef makespinobject (smooth,rot,n,x1,z1,nx1,nz1,x2,z2,nx2,nz2) : +X object = [] +X dth = 2.0 * pi / float (rot) +X for i in range (0, n) : +X for j in range (0, rot) : +X th = dth * float (j) +X # +X if smooth = 1: +X a1 = th +X a2 =th+dth +X else : +X a1 = th + dth / 2.0 +X a2 = th + dth / 2.0 +X # +X v0 = (x1[i]*sin(th),x1[i]*cos(th),z1[i]) +X n0 = (nx1[i]*sin(a1),nx1[i]*cos(a1),nz1[i]) +X # +X v1 = (x1[i]*sin(th+dth),x1[i]*cos(th+dth),z1[i]) +X n1 = (nx1[i]*sin(a2), nx1[i]*cos(a2), nz1[i]) +X # +X v2 = (x2[i]*sin(th+dth),x2[i]*cos(th+dth),z2[i]) +X n2 = (nx2[i]*sin(a2), nx2[i]*cos(a2), nz2[i]) +X # +X v3 = (x2[i]*sin(th), x2[i]*cos(th), z2[i]) +X n3 = (nx2[i]*sin(a1), nx2[i]*cos(a1), nz2[i]) +X # +X patch = ((v0,n0), (v1,n1), (v2,n2), (v3,n3)) +X #patch = ((n0,v0), (n1,v1), (n2,v2), (n3,v3)) +X # +X if x1[i] < FUZZY : +X patch = patch[1:] +X # +X object.append (patch) +X # +X return object +X +Xdef makesphere (n): +X asin = [] +X acos = [] +X for i in range (0, n-1): +X asin.append (sin((pi/float (n))*(1.0+float (i)))) +X acos.append(cos((pi/float (n))*(1.0+float (i)))) +X # +X x1 = [0.0] + asin +X z1 = [1.0] + acos +X nx1 = [0.0] + asin +X nz1 = [1.0] + acos +X # +X x2 = asin + [0.0] +X z2 = acos + [-1.0] +X nx2 = asin + [0.0] +X nz2 = acos + [-1.0] +X # +X return makespinobject (1,2*n,n,x1,z1,nx1,nz1,x2,z2,nx2,nz2) +X +Xdef makecylinder(n) : +X x1 = [0.0, 1.0, 1.0] +X nx1 = [0.0, 1.0, 0.0] +X z1 = [1.0, 1.0, -1.0] +X nz1 = [1.0, 0.0, -1.0] +X # +X z2 = [1.0, -1.0, -1.0] +X nz2 = [1.0, 0.0, -1.0] +X x2 = [1.0, 1.0, 0.0] +X nx2 = [0.0, 1.0, 0.0] +X # +X return makespinobject(1,2*n,3,x1,z1,nx1,nz1,x2,z2,nx2,nz2) +X +Xdef makecone(n) : +X x1 = [0.0, 1.0, 1.0] +X nx1 = [2.0/sqrt(5.0), 0.0, 0.0] +X z1 = [1.0, -1.0, -1.0] +X nz1 = [1.0/sqrt(5.0), -1.0, -1.0] +X # +X x2 = [1.0, 0.0, 0.0] +X nx2 = [2.0/sqrt(5.0), 0.0, 0.0] +X nz2 = [1.0/sqrt(5.0), -1.0, -1.0] +X z2 = [-1.0, -1.0, -1.0] +X # +X return makespinobject(1,2*n,2,x1,z1,nx1,nz1,x2,z2,nx2,nz2) +X +Xdef makecube() : +X x1 = [0.0, sqrt(2.0), sqrt (2.0)] +X nx1 = [0.0, 1.0, 0.0] +X z1 = [1.0, 1.0, -1.0] +X nz1 = [1.0, 0.0, -1.0] +X # +X x2 = [sqrt(2.0), sqrt(2.0), 0.0] +X nx2 = [0.0, 1.0, 0.0] +X z2 = [1.0, -1.0, -1.0] +X nz2 = [1.0, 0.0, -1.0] +X # +X return makespinobject(0,4,3,x1,z1,nx1,nz1,x2,z2,nx2,nz2) +X +X +Xdef makepyramid() : +X x1 = [0.0, sqrt(2.0), 0.0] +X nx1 = [2.0 / sqrt(5.0), 0.0, 0.0] +X z1 = [1.0, -1.0, 0.0] +X nz1 = [1.0 / sqrt(5.0), -1.0, 0.0] +X # +X x2 = [sqrt(2.0), 0.0, 0.0] +X nx2 = [2.0 / sqrt(5.0), 0.0, 0.0] +X z2 = [-1.0, -1.0, -1.0] +X nz2 = [1.0/sqrt(5.0), -1.0, 0.0] +X # +X return makespinobject(0,4,3,x1,z1,nx1,nz1,x2,z2,nx2,nz2) +X +Xdef makeobjects () : +X cube = makecube() +X sphere = makesphere (6) +X cylinder = makecylinder (6) +X cone = makecone (6) +X pyramid = makepyramid () +X # +X odict = {} +X odict ['cube'] = cube +X odict ['pyramid'] = pyramid +X odict ['sphere'] = sphere +X odict ['cylinder'] = cylinder +X odict ['cone'] = cone +X odict ['diamond'] = cube +X odict ['disk'] = sphere +X # +X return odict +X +X +Xrenderfuncs = [bgnpolygon, endpolygon] +X +Xdef putFunc (funcs) : +X renderfuncs [:] = funcs +X +Xdef drawobject (obj) : +X # +X for patch in obj : +X renderfuncs[0] () +X vnarray (patch) +X renderfuncs[1] () +X +EOF +fi +if test -s 'lib/Split.py' +then echo '*** I will not over-write existing file lib/Split.py' +else +echo 'x - lib/Split.py' +sed 's/^X//' > 'lib/Split.py' << 'EOF' +X# Generic Split implementation. +X# Use as a base class for other splits. +X# Derived classes should at least implement the methods that call +X# unimpl() below: minsize(), getbounds() and setbounds(). +X +XError = 'Split.Error' # Exception +X +Ximport rect +Xfrom util import remove +X +Xclass Split(): +X # +X # Calls from creator +X # NB derived classes may add parameters to create() +X # +X def create(self, parent): +X parent.addchild(self) +X self.parent = parent +X self.children = [] +X self.mouse_interest = [] +X self.timer_interest = [] +X self.mouse_focus = 0 +X return self +X # +X # Downcalls from parent to child +X # +X def destroy(self): +X self.parent = None +X for child in self.children: +X child.destroy() +X del self.children[:] +X del self.mouse_interest[:] +X del self.timer_interest[:] +X self.mouse_focus = None +X # +X def minsize(self, m): return unimpl() +X def getbounds(self): return unimpl() +X def setbounds(self, bounds): unimpl() +X # +X def draw(self, d_detail): +X # (Could avoid calls to children outside the area) +X for child in self.children: +X child.draw(d_detail) +X # +X # Downcalls only made after certain upcalls +X # +X def mouse_down(self, detail): +X if self.mouse_focus: +X self.mouse_focus.mouse_down(detail) +X p = detail[0] +X for child in self.mouse_interest: +X if rect.pointinrect(p, child.getbounds()): +X self.mouse_focus = child +X child.mouse_down(detail) +X def mouse_move(self, detail): +X if self.mouse_focus: +X self.mouse_focus.mouse_move(detail) +X def mouse_up(self, detail): +X if self.mouse_focus: +X self.mouse_focus.mouse_up(detail) +X self.mouse_focus = 0 +X # +X def timer(self): +X for child in self.timer_interest: +X child.timer() +X # +X # Upcalls from child to parent +X # +X def addchild(self, child): +X if child in self.children: +X raise Error, 'addchild: child already inlist' +X self.children.append(child) +X def delchild(self, child): +X if child not in self.children: +X raise Error, 'delchild: child not in list' +X remove(child, self.children) +X if child in self.mouse_interest: +X remove(child, self.mouse_interest) +X if child in self.timer_interest: +X remove(child, self.timer_interest) +X if child = self.mouse_focus: +X self.mouse_focus = 0 +X # +X def need_mouse(self, child): +X if child not in self.mouse_interest: +X self.mouse_interest.append(child) +X self.parent.need_mouse(self) +X def no_mouse(self, child): +X if child in self.mouse_interest: +X remove(child, self.mouse_interest) +X if not self.mouse_interest: +X self.parent.no_mouse(self) +X # +X def need_timer(self, child): +X if child not in self.timer_interest: +X self.timer_interest.append(child) +X self.parent.need_timer(self) +X def no_timer(self, child): +X if child in self.timer_interest: +X remove(child, self.timer_interest) +X if not self.timer_interest: +X self.parent.no_timer(self) +X # +X # The rest are transparent: +X # +X def begindrawing(self): +X return self.parent.begindrawing() +X def beginmeasuring(self): +X return self.parent.beginmeasuring() +X # +X def change(self, area): +X self.parent.change(area) +X def scroll(self, area_vector): +X self.parent.scroll(area_vector) +X def settimer(self, itimer): +X self.parent.settimer(itimer) +EOF +fi +if test -s 'lib/WindowParent.py' +then echo '*** I will not over-write existing file lib/WindowParent.py' +else +echo 'x - lib/WindowParent.py' +sed 's/^X//' > 'lib/WindowParent.py' << 'EOF' +X# A 'WindowParent' is the only module that uses real stdwin functionality. +X# It is the root of the tree. +X# It should have exactly one child when realized. +X +Ximport stdwin +Xfrom stdwinevents import * +X +Xfrom TransParent import ManageOneChild +X +XError = 'WindowParent.Error' # Exception +X +Xclass WindowParent() = ManageOneChild(): +X # +X def create(self, (title, size)): +X self.title = title +X self.size = size # (width, height) +X self._reset() +X return self +X # +X def _reset(self): +X self.child = 0 +X self.win = 0 +X self.itimer = 0 +X self.do_mouse = 0 +X self.do_timer = 0 +X # +X def destroy(self): +X if self.child: self.child.destroy() +X self._reset() +X # +X def need_mouse(self, child): self.do_mouse = 1 +X def no_mouse(self, child): self.do_mouse = 0 +X # +X def need_timer(self, child): self.do_timer = 1 +X def no_timer(self, child): self.do_timer = 0 +X # +X def realize(self): +X if self.win: +X raise Error, 'realize(): called twice' +X if not self.child: +X raise Error, 'realize(): no child' +X size = self.child.minsize(self.beginmeasuring()) +X self.size = max(self.size[0], size[0]), \ +X max(self.size[1], size[1]) +X #stdwin.setdefwinsize(self.size) +X # XXX Compensate stdwin bug: +X stdwin.setdefwinsize(self.size[0]+4, self.size[1]+2) +X self.win = stdwin.open(self.title) +X if self.itimer: +X self.win.settimer(self.itimer) +X bounds = (0, 0), self.win.getwinsize() +X self.child.setbounds(bounds) +X # +X def beginmeasuring(self): +X # Return something with which a child can measure text +X if self.win: +X return self.win.begindrawing() +X else: +X return stdwin +X # +X def begindrawing(self): +X if self.win: +X return self.win.begindrawing() +X else: +X raise Error, 'begindrawing(): not realized yet' +X # +X def change(self, area): +X if self.win: +X self.win.change(area) +X # +X def scroll(self, args): +X if self.win: +X self.win.scroll(args) +X # +X def settimer(self, itimer): +X if self.win: +X self.win.settimer(itimer) +X else: +X self.itimer = itimer +X # +X # Only call dispatch if we have a child +X # +X def dispatch(self, (type, win, detail)): +X if win <> self.win: +X return +X elif type = WE_DRAW: +X d = self.win.begindrawing() +X self.child.draw(d, detail) +X elif type = WE_MOUSE_DOWN: +X if self.do_mouse: self.child.mouse_down(detail) +X elif type = WE_MOUSE_MOVE: +X if self.do_mouse: self.child.mouse_move(detail) +X elif type = WE_MOUSE_UP: +X if self.do_mouse: self.child.mouse_up(detail) +X elif type = WE_TIMER: +X if self.do_timer: self.child.timer() +X elif type = WE_SIZE: +X self.win.change((0, 0), (10000, 10000)) # XXX +X bounds = (0, 0), self.win.getwinsize() +X self.child.setbounds(bounds) +X # +EOF +fi +if test -s 'lib/gwin.py' +then echo '*** I will not over-write existing file lib/gwin.py' +else +echo 'x - lib/gwin.py' +sed 's/^X//' > 'lib/gwin.py' << 'EOF' +X# Module 'gwin' +X# Generic stdwin windows +X +X# This is used as a base class from which to derive other window types. +X# The mainloop() function here is an event dispatcher for all window types. +X +Ximport stdwin +Xfrom stdwinevents import * +X +X# XXX Old version of stdwinevents, should go +Ximport stdwinsupport +XS = stdwinsupport # Shorthand +X +Xwindows = [] # List of open windows +X +X +X# Open a window +X +Xdef open(title): # Open a generic window +X w = stdwin.open(title) +X stdwin.setdefwinsize(0, 0) +X # Set default event handlers +X w.draw = nop +X w.char = nop +X w.mdown = nop +X w.mmove = nop +X w.mup = nop +X w.m2down = m2down +X w.m2up = m2up +X w.size = nop +X w.move = nop +X w.activate = w.deactivate = nop +X w.timer = nop +X # default command handlers +X w.close = close +X w.tab = tab +X w.enter = enter +X w.backspace = backspace +X w.arrow = arrow +X w.kleft = w.kup = w.kright = w.kdown = nop +X windows.append(w) +X return w +X +X +X# Generic event dispatching +X +Xdef mainloop(): # Handle events until no windows left +X while windows: +X treatevent(stdwin.getevent()) +X +Xdef treatevent(e): # Handle a stdwin event +X type, w, detail = e +X if type = S.we_draw: +X w.draw(w, detail) +X elif type = S.we_menu: +X m, item = detail +X m.action[item](w, m, item) +X elif type = S.we_command: +X treatcommand(w, detail) +X elif type = S.we_char: +X w.char(w, detail) +X elif type = S.we_mouse_down: +X if detail[1] > 1: w.m2down(w, detail) +X else: w.mdown(w, detail) +X elif type = S.we_mouse_move: +X w.mmove(w, detail) +X elif type = S.we_mouse_up: +X if detail[1] > 1: w.m2up(w, detail) +X else: w.mup(w, detail) +X elif type = S.we_size: +X w.size(w, w.getwinsize()) +X elif type = S.we_activate: +X w.activate(w) +X elif type = S.we_deactivate: +X w.deactivate(w) +X elif type = S.we_move: +X w.move(w) +X elif type = S.we_timer: +X w.timer(w) +X elif type = WE_CLOSE: +X w.close(w) +X +Xdef treatcommand(w, type): # Handle a we_command event +X if type = S.wc_close: +X w.close(w) +X elif type = S.wc_return: +X w.enter(w) +X elif type = S.wc_tab: +X w.tab(w) +X elif type = S.wc_backspace: +X w.backspace(w) +X elif type in (S.wc_left, S.wc_up, S.wc_right, S.wc_down): +X w.arrow(w, type) +X +X +X# Methods +X +Xdef close(w): # Close method +X for i in range(len(windows)): +X if windows[i] is w: +X del windows[i] +X break +X +Xdef arrow(w, detail): # Arrow key method +X if detail = S.wc_left: +X w.kleft(w) +X elif detail = S.wc_up: +X w.kup(w) +X elif detail = S.wc_right: +X w.kright(w) +X elif detail = S.wc_down: +X w.kdown(w) +X +X +X# Trivial methods +X +Xdef tab(w): w.char(w, '\t') +Xdef enter(w): w.char(w, '\n') # 'return' is a Python reserved word +Xdef backspace(w): w.char(w, '\b') +Xdef m2down(w, detail): w.mdown(w, detail) +Xdef m2up(w, detail): w.mup(w, detail) +Xdef nop(args): pass +EOF +fi +if test -s 'lib/panelparser.py' +then echo '*** I will not over-write existing file lib/panelparser.py' +else +echo 'x - lib/panelparser.py' +sed 's/^X//' > 'lib/panelparser.py' << 'EOF' +X# Module 'parser' +X# +X# Parse S-expressions output by the Panel Editor +X# (which is written in Scheme so it can't help writing S-expressions). +X# +X# See notes at end of file. +X +X +Xwhitespace = ' \t\n' +Xoperators = '()\'' +Xseparators = operators + whitespace + ';' + '"' +X +X +X# Tokenize a string. +X# Return a list of tokens (strings). +X# +Xdef tokenize_string(s): +X tokens = [] +X while s: +X c = s[:1] +X if c in whitespace: +X s = s[1:] +X elif c = ';': +X s = '' +X elif c = '"': +X n = len(s) +X i = 1 +X while i < n: +X c = s[i] +X i = i+1 +X if c = '"': break +X if c = '\\': i = i+1 +X tokens.append(s[:i]) +X s = s[i:] +X elif c in operators: +X tokens.append(c) +X s = s[1:] +X else: +X n = len(s) +X i = 1 +X while i < n: +X if s[i] in separators: break +X i = i+1 +X tokens.append(s[:i]) +X s = s[i:] +X return tokens +X +X +X# Tokenize a whole file (given as file object, not as file name). +X# Return a list of tokens (strings). +X# +Xdef tokenize_file(fp): +X tokens = [] +X while 1: +X line = fp.readline() +X if not line: break +X tokens = tokens + tokenize_string(line) +X return tokens +X +X +X# Exception raised by parse_exr. +X# +Xsyntax_error = 'syntax error' +X +X +X# Parse an S-expression. +X# Input is a list of tokens as returned by tokenize_*(). +X# Return a pair (expr, tokens) +X# where expr is a list representing the s-expression, +X# and tokens contains the remaining tokens. +X# May raise syntax_error. +X# +Xdef parse_expr(tokens): +X if (not tokens) or tokens[0] <> '(': +X raise syntax_error, 'expected "("' +X tokens = tokens[1:] +X expr = [] +X while 1: +X if not tokens: +X raise syntax_error, 'missing ")"' +X if tokens[0] = ')': +X return expr, tokens[1:] +X elif tokens[0] = '(': +X subexpr, tokens = parse_expr(tokens) +X expr.append(subexpr) +X else: +X expr.append(tokens[0]) +X tokens = tokens[1:] +X +X +X# Parse a file (given as file object, not as file name). +X# Return a list of parsed S-expressions found at the top level. +X# +Xdef parse_file(fp): +X tokens = tokenize_file(fp) +X exprlist = [] +X while tokens: +X expr, tokens = parse_expr(tokens) +X exprlist.append(expr) +X return exprlist +X +X +X# EXAMPLE: +X# +X# The input +X# '(hip (hop hur-ray))' +X# +X# passed to tokenize_string() returns the token list +X# ['(', 'hip', '(', 'hop', 'hur-ray', ')', ')'] +X# +X# When this is passed to parse_expr() it returns the expression +X# ['hip', ['hop', 'hur-ray']] +X# plus an empty token list (because there are no tokens left. +X# +X# When a file containing the example is passed to parse_file() it returns +X# a list whose only element is the output of parse_expr() above: +X# [['hip', ['hop', 'hur-ray']]] +X +X +X# TOKENIZING: +X# +X# Comments start with semicolon (;) and continue till the end of the line. +X# +X# Tokens are separated by whitespace, except the following characters +X# always form a separate token (outside strings): +X# ( ) ' +X# Strings are enclosed in double quotes (") and backslash (\) is used +X# as escape character in strings. +EOF +fi +if test -s 'lib/path.py' +then echo '*** I will not over-write existing file lib/path.py' +else +echo 'x - lib/path.py' +sed 's/^X//' > 'lib/path.py' << 'EOF' +X# Module 'path' -- common operations on POSIX pathnames +X +Ximport posix +Ximport stat +X +X +X# Intelligent pathname concatenation. +X# Inserts a '/' unless the first part is empty or already ends in '/'. +X# Ignores the first part altogether if the second part is absolute +X# (begins with '/'). +X# +Xdef cat(a, b): +X if b[:1] = '/': return b +X if a = '' or a[-1:] = '/': return a + b +X return a + '/' + b +X +X +X# Split a path in head (empty or ending in '/') and tail (no '/'). +X# The tail will be empty if the path ends in '/'. +X# +Xdef split(p): +X head, tail = '', '' +X for c in p: +X tail = tail + c +X if c = '/': +X head, tail = head + tail, '' +X return head, tail +X +X +X# Return the tail (basename) part of a path. +X# +Xdef basename(p): +X return split(p)[1] +X +X +X# Return the longest prefix of all list elements. +X# +Xdef commonprefix(m): +X if not m: return '' +X prefix = m[0] +X for item in m: +X for i in range(len(prefix)): +X if prefix[:i+1] <> item[:i+1]: +X prefix = prefix[:i] +X if i = 0: return '' +X break +X return prefix +X +X +X# Does a file/directory exist? +X# +Xdef exists(path): +X try: +X st = posix.stat(path) +X except posix.error: +X return 0 +X return 1 +X +X +X# Is a path a posix directory? +X# +Xdef isdir(path): +X try: +X st = posix.stat(path) +X except posix.error: +X return 0 +X return stat.S_ISDIR(st[stat.ST_MODE]) +X +X +X# Is a path a symbolic link? +X# This will always return false on systems where posix.lstat doesn't exist. +X# +Xdef islink(path): +X try: +X st = posix.lstat(path) +X except (posix.error, NameError): +X return 0 +X return stat.S_ISLNK(st[stat.ST_MODE]) +X +X +X_mounts = [] +X +Xdef _getmounts(): +X import commands, string +X mounts = [] +X data = commands.getoutput('/etc/mount') +X lines = string.splitfields(data, '\n') +X for line in lines: +X words = string.split(line) +X if len(words) >= 3 and words[1] = 'on': +X mounts.append(words[2]) +X return mounts +X +X +X# Is a path a mount point? +X# This only works for normalized, absolute paths, +X# and only if the mount table as printed by /etc/mount is correct. +X# Sorry. +X# +Xdef ismount(path): +X if not _mounts: +X _mounts[:] = _getmounts() +X return path in _mounts +X +X +X# Directory tree walk. +X# For each directory under top (including top itself), +X# func(arg, dirname, filenames) is called, where dirname +X# is the name of the directory and filenames is the list of +X# files (and subdirectories etc.) in the directory. +X# func may modify the filenames list, to implement a filter, +X# or to impose a different order of visiting. +X# +Xdef walk(top, func, arg): +X try: +X names = posix.listdir(top) +X except posix.error: +X return +X func(arg, top, names) +X exceptions = ('.', '..') +X for name in names: +X if name not in exceptions: +X name = cat(top, name) +X if isdir(name): +X walk(name, func, arg) +EOF +fi +if test -s 'lib/string.py' +then echo '*** I will not over-write existing file lib/string.py' +else +echo 'x - lib/string.py' +sed 's/^X//' > 'lib/string.py' << 'EOF' +X# module 'string' -- A collection of string operations +X +X# XXX Some of these operations are incredibly slow and should be built in +X +X# Some strings for ctype-style character classification +Xwhitespace = ' \t\n' +Xlowercase = 'abcdefghijklmnopqrstuvwxyz' +Xuppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +Xletters = lowercase + uppercase +Xdigits = '0123456789' +Xhexdigits = digits + 'abcdef' + 'ABCDEF' +Xoctdigits = '01234567' +X +X# Case conversion helpers +X_caseswap = {} +Xfor i in range(26): +X _caseswap[lowercase[i]] = uppercase[i] +X _caseswap[uppercase[i]] = lowercase[i] +Xdel i +X +X# convert UPPER CASE letters to lower case +Xdef lower(s): +X res = '' +X for c in s: +X if 'A' <= c <= 'Z': c = _caseswap[c] +X res = res + c +X return res +X +X# Convert lower case letters to UPPER CASE +Xdef upper(s): +X res = '' +X for c in s: +X if 'a' <= c <= 'z': c = _caseswap[c] +X res = res + c +X return res +X +X# Swap lower case letters and UPPER CASE +Xdef swapcase(s): +X res = '' +X for c in s: +X if 'a' <= c <= 'z' or 'A' <= c <= 'Z': c = _caseswap[c] +X res = res + c +X return res +X +X# Strip leading and trailing tabs and spaces +Xdef strip(s): +X i, j = 0, len(s) +X while i < j and s[i] in whitespace: i = i+1 +X while i < j and s[j-1] in whitespace: j = j-1 +X return s[i:j] +X +X# Split a string into a list of space/tab-separated words +X# NB: split(s) is NOT the same as splitfields(s, ' ')! +Xdef split(s): +X res = [] +X i, n = 0, len(s) +X while i < n: +X while i < n and s[i] in whitespace: i = i+1 +X if i = n: break +X j = i +X while j < n and s[j] not in whitespace: j = j+1 +X res.append(s[i:j]) +X i = j +X return res +X +X# Split a list into fields separated by a given string +X# NB: splitfields(s, ' ') is NOT the same as split(s)! +Xdef splitfields(s, sep): +X res = [] +X ns = len(s) +X nsep = len(sep) +X i = j = 0 +X while j+nsep <= ns: +X if s[j:j+nsep] = sep: +X res.append(s[i:j]) +X i = j = j + nsep +X else: +X j = j + 1 +X res.append(s[i:]) +X return res +X +X# Find substring +Xindex_error = 'substring not found in string.index' +Xdef index(s, sub): +X n = len(sub) +X for i in range(len(s) + 1 - n): +X if sub = s[i:i+n]: return i +X raise index_error, (s, sub) +X +X# Convert string to integer +Xatoi_error = 'non-numeric argument to string.atoi' +Xdef atoi(str): +X s = str +X if s[:1] in '+-': s = s[1:] +X if not s: raise atoi_error, str +X for c in s: +X if c not in digits: raise atoi_error, str +X return eval(str) +X +X# Left-justify a string +Xdef ljust(s, width): +X n = len(s) +X if n >= width: return s +X return s + ' '*(width-n) +X +X# Right-justify a string +Xdef rjust(s, width): +X n = len(s) +X if n >= width: return s +X return ' '*(width-n) + s +X +X# Center a string +Xdef center(s, width): +X n = len(s) +X if n >= width: return s +X return ' '*((width-n)/2) + s + ' '*(width -(width-n)/2) +X +X# Zero-fill a number, e.g., (12, 3) --> '012' and (-3, 3) --> '-03' +X# Decadent feature: the argument may be a string or a number +X# (Use of this is deprecated; it should be a string as with ljust c.s.) +Xdef zfill(x, width): +X if type(x) = type(''): s = x +X else: s = `x` +X n = len(s) +X if n >= width: return s +X sign = '' +X if s[0] = '-': +X sign, s = '-', s[1:] +X return sign + '0'*(width-n) + s +EOF +fi +if test -s 'src/Grammar' +then echo '*** I will not over-write existing file src/Grammar' +else +echo 'x - src/Grammar' +sed 's/^X//' > 'src/Grammar' << 'EOF' +X# Grammar for Python, version 4 +X +X# Changes compared to version 3: +X# Removed 'dir' statement. +X# Function call argument is a testlist instead of exprlist. +X +X# Changes compared to version 2: +X# The syntax of Boolean operations is changed to use more +X# conventional priorities: or < and < not. +X +X# Changes compared to version 1: +X# modules and scripts are unified; +X# 'quit' is gone (use ^D); +X# empty_stmt is gone, replaced by explicit NEWLINE where appropriate; +X# 'import' and 'def' aren't special any more; +X# added 'from' NAME option on import clause, and '*' to import all; +X# added class definition. +X +X# Start symbols for the grammar: +X# single_input is a single interactive statement; +X# file_input is a module or sequence of commands read from an input file; +X# expr_input is the input for the input() function; +X# eval_input is the input for the eval() function. +X +X# NB: compound_stmt in single_input is followed by extra NEWLINE! +Xsingle_input: NEWLINE | simple_stmt | compound_stmt NEWLINE +Xfile_input: (NEWLINE | stmt)* ENDMARKER +Xexpr_input: testlist NEWLINE +Xeval_input: testlist ENDMARKER +X +Xfuncdef: 'def' NAME parameters ':' suite +Xparameters: '(' [fplist] ')' +Xfplist: fpdef (',' fpdef)* +Xfpdef: NAME | '(' fplist ')' +X +Xstmt: simple_stmt | compound_stmt +Xsimple_stmt: expr_stmt | print_stmt | pass_stmt | del_stmt | flow_stmt | import_stmt +Xexpr_stmt: (exprlist '=')* exprlist NEWLINE +X# For assignments, additional restrictions enforced by the interpreter +Xprint_stmt: 'print' (test ',')* [test] NEWLINE +Xdel_stmt: 'del' exprlist NEWLINE +Xpass_stmt: 'pass' NEWLINE +Xflow_stmt: break_stmt | return_stmt | raise_stmt +Xbreak_stmt: 'break' NEWLINE +Xreturn_stmt: 'return' [testlist] NEWLINE +Xraise_stmt: 'raise' expr [',' expr] NEWLINE +Ximport_stmt: 'import' NAME (',' NAME)* NEWLINE | 'from' NAME 'import' ('*' | NAME (',' NAME)*) NEWLINE +Xcompound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef +Xif_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] +Xwhile_stmt: 'while' test ':' suite ['else' ':' suite] +Xfor_stmt: 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] +Xtry_stmt: 'try' ':' suite (except_clause ':' suite)* ['finally' ':' suite] +Xexcept_clause: 'except' [expr [',' expr]] +Xsuite: simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT +X +Xtest: and_test ('or' and_test)* +Xand_test: not_test ('and' not_test)* +Xnot_test: 'not' not_test | comparison +Xcomparison: expr (comp_op expr)* +Xcomp_op: '<'|'>'|'='|'>' '='|'<' '='|'<' '>'|'in'|'not' 'in'|'is'|'is' 'not' +Xexpr: term (('+'|'-') term)* +Xterm: factor (('*'|'/'|'%') factor)* +Xfactor: ('+'|'-') factor | atom trailer* +Xatom: '(' [testlist] ')' | '[' [testlist] ']' | '{' '}' | '`' testlist '`' | NAME | NUMBER | STRING +Xtrailer: '(' [testlist] ')' | '[' subscript ']' | '.' NAME +Xsubscript: expr | [expr] ':' [expr] +Xexprlist: expr (',' expr)* [','] +Xtestlist: test (',' test)* [','] +X +Xclassdef: 'class' NAME parameters ['=' baselist] ':' suite +Xbaselist: atom arguments (',' atom arguments)* +Xarguments: '(' [testlist] ')' +EOF +fi +if test -s 'src/firstsets.c' +then echo '*** I will not over-write existing file src/firstsets.c' +else +echo 'x - src/firstsets.c' +sed 's/^X//' > 'src/firstsets.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Computation of FIRST stets */ +X +X#include "pgenheaders.h" +X#include "grammar.h" +X#include "token.h" +X +Xextern int debugging; +X +X/* Forward */ +Xstatic void calcfirstset PROTO((grammar *, dfa *)); +X +Xvoid +Xaddfirstsets(g) +X grammar *g; +X{ +X int i; +X dfa *d; +X +X printf("Adding FIRST sets ...\n"); +X for (i = 0; i < g->g_ndfas; i++) { +X d = &g->g_dfa[i]; +X if (d->d_first == NULL) +X calcfirstset(g, d); +X } +X} +X +Xstatic void +Xcalcfirstset(g, d) +X grammar *g; +X dfa *d; +X{ +X int i, j; +X state *s; +X arc *a; +X int nsyms; +X int *sym; +X int nbits; +X static bitset dummy; +X bitset result; +X int type; +X dfa *d1; +X label *l0; +X +X if (debugging) +X printf("Calculate FIRST set for '%s'\n", d->d_name); +X +X if (dummy == NULL) +X dummy = newbitset(1); +X if (d->d_first == dummy) { +X fprintf(stderr, "Left-recursion for '%s'\n", d->d_name); +X return; +X } +X if (d->d_first != NULL) { +X fprintf(stderr, "Re-calculating FIRST set for '%s' ???\n", +X d->d_name); +X } +X d->d_first = dummy; +X +X l0 = g->g_ll.ll_label; +X nbits = g->g_ll.ll_nlabels; +X result = newbitset(nbits); +X +X sym = NEW(int, 1); +X if (sym == NULL) +X fatal("no mem for new sym in calcfirstset"); +X nsyms = 1; +X sym[0] = findlabel(&g->g_ll, d->d_type, (char *)NULL); +X +X s = &d->d_state[d->d_initial]; +X for (i = 0; i < s->s_narcs; i++) { +X a = &s->s_arc[i]; +X for (j = 0; j < nsyms; j++) { +X if (sym[j] == a->a_lbl) +X break; +X } +X if (j >= nsyms) { /* New label */ +X RESIZE(sym, int, nsyms + 1); +X if (sym == NULL) +X fatal("no mem to resize sym in calcfirstset"); +X sym[nsyms++] = a->a_lbl; +X type = l0[a->a_lbl].lb_type; +X if (ISNONTERMINAL(type)) { +X d1 = finddfa(g, type); +X if (d1->d_first == dummy) { +X fprintf(stderr, +X "Left-recursion below '%s'\n", +X d->d_name); +X } +X else { +X if (d1->d_first == NULL) +X calcfirstset(g, d1); +X mergebitset(result, d1->d_first, nbits); +X } +X } +X else if (ISTERMINAL(type)) { +X addbit(result, a->a_lbl); +X } +X } +X } +X d->d_first = result; +X if (debugging) { +X printf("FIRST set for '%s': {", d->d_name); +X for (i = 0; i < nbits; i++) { +X if (testbit(result, i)) +X printf(" %s", labelrepr(&l0[i])); +X } +X printf(" }\n"); +X } +X} +EOF +fi +if test -s 'src/frameobject.h' +then echo '*** I will not over-write existing file src/frameobject.h' +else +echo 'x - src/frameobject.h' +sed 's/^X//' > 'src/frameobject.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Frame object interface */ +X +Xtypedef struct { +X int b_type; /* what kind of block this is */ +X int b_handler; /* where to jump to find handler */ +X int b_level; /* value stack level to pop to */ +X} block; +X +Xtypedef struct _frame { +X OB_HEAD +X struct _frame *f_back; /* previous frame, or NULL */ +X codeobject *f_code; /* code segment */ +X object *f_globals; /* global symbol table (dictobject) */ +X object *f_locals; /* local symbol table (dictobject) */ +X object **f_valuestack; /* malloc'ed array */ +X block *f_blockstack; /* malloc'ed array */ +X int f_nvalues; /* size of f_valuestack */ +X int f_nblocks; /* size of f_blockstack */ +X int f_iblock; /* index in f_blockstack */ +X} frameobject; +X +X +X/* Standard object interface */ +X +Xextern typeobject Frametype; +X +X#define is_frameobject(op) ((op)->ob_type == &Frametype) +X +Xframeobject * newframeobject PROTO( +X (frameobject *, codeobject *, object *, object *, int, int)); +X +X +X/* The rest of the interface is specific for frame objects */ +X +X/* List access macros */ +X +X#ifdef NDEBUG +X#define GETITEM(v, i) GETLISTITEM((listobject *)(v), (i)) +X#define GETITEMNAME(v, i) GETSTRINGVALUE((stringobject *)GETITEM((v), (i))) +X#else +X#define GETITEM(v, i) getlistitem((v), (i)) +X#define GETITEMNAME(v, i) getstringvalue(getlistitem((v), (i))) +X#endif +X +X#define GETUSTRINGVALUE(s) ((unsigned char *)GETSTRINGVALUE(s)) +X +X/* Code access macros */ +X +X#define Getconst(f, i) (GETITEM((f)->f_code->co_consts, (i))) +X#define Getname(f, i) (GETITEMNAME((f)->f_code->co_names, (i))) +X +X +X/* Block management functions */ +X +Xvoid setup_block PROTO((frameobject *, int, int, int)); +Xblock *pop_block PROTO((frameobject *)); +EOF +fi +if test -s 'src/funcobject.c' +then echo '*** I will not over-write existing file src/funcobject.c' +else +echo 'x - src/funcobject.c' +sed 's/^X//' > 'src/funcobject.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Function object implementation */ +X +X#include "allobjects.h" +X +X#include "structmember.h" +X +Xtypedef struct { +X OB_HEAD +X object *func_code; +X object *func_globals; +X} funcobject; +X +Xobject * +Xnewfuncobject(code, globals) +X object *code; +X object *globals; +X{ +X funcobject *op = NEWOBJ(funcobject, &Functype); +X if (op != NULL) { +X INCREF(code); +X op->func_code = code; +X INCREF(globals); +X op->func_globals = globals; +X } +X return (object *)op; +X} +X +Xobject * +Xgetfunccode(op) +X object *op; +X{ +X if (!is_funcobject(op)) { +X err_badcall(); +X return NULL; +X } +X return ((funcobject *) op) -> func_code; +X} +X +Xobject * +Xgetfuncglobals(op) +X object *op; +X{ +X if (!is_funcobject(op)) { +X err_badcall(); +X return NULL; +X } +X return ((funcobject *) op) -> func_globals; +X} +X +X/* Methods */ +X +X#define OFF(x) offsetof(funcobject, x) +X +Xstatic struct memberlist func_memberlist[] = { +X {"func_code", T_OBJECT, OFF(func_code)}, +X {"func_globals",T_OBJECT, OFF(func_globals)}, +X {NULL} /* Sentinel */ +X}; +X +Xstatic object * +Xfunc_getattr(op, name) +X funcobject *op; +X char *name; +X{ +X return getmember((char *)op, func_memberlist, name); +X} +X +Xstatic void +Xfunc_dealloc(op) +X funcobject *op; +X{ +X DECREF(op->func_code); +X DECREF(op->func_globals); +X DEL(op); +X} +X +Xtypeobject Functype = { +X OB_HEAD_INIT(&Typetype) +X 0, +X "function", +X sizeof(funcobject), +X 0, +X func_dealloc, /*tp_dealloc*/ +X 0, /*tp_print*/ +X func_getattr, /*tp_getattr*/ +X 0, /*tp_setattr*/ +X 0, /*tp_compare*/ +X 0, /*tp_repr*/ +X}; +EOF +fi +if test -s 'src/grammar.h' +then echo '*** I will not over-write existing file src/grammar.h' +else +echo 'x - src/grammar.h' +sed 's/^X//' > 'src/grammar.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Grammar interface */ +X +X#include "bitset.h" /* Sigh... */ +X +X/* A label of an arc */ +X +Xtypedef struct _label { +X int lb_type; +X char *lb_str; +X} label; +X +X#define EMPTY 0 /* Label number 0 is by definition the empty label */ +X +X/* A list of labels */ +X +Xtypedef struct _labellist { +X int ll_nlabels; +X label *ll_label; +X} labellist; +X +X/* An arc from one state to another */ +X +Xtypedef struct _arc { +X short a_lbl; /* Label of this arc */ +X short a_arrow; /* State where this arc goes to */ +X} arc; +X +X/* A state in a DFA */ +X +Xtypedef struct _state { +X int s_narcs; +X arc *s_arc; /* Array of arcs */ +X +X /* Optional accelerators */ +X int s_lower; /* Lowest label index */ +X int s_upper; /* Highest label index */ +X int *s_accel; /* Accelerator */ +X int s_accept; /* Nonzero for accepting state */ +X} state; +X +X/* A DFA */ +X +Xtypedef struct _dfa { +X int d_type; /* Non-terminal this represents */ +X char *d_name; /* For printing */ +X int d_initial; /* Initial state */ +X int d_nstates; +X state *d_state; /* Array of states */ +X bitset d_first; +X} dfa; +X +X/* A grammar */ +X +Xtypedef struct _grammar { +X int g_ndfas; +X dfa *g_dfa; /* Array of DFAs */ +X labellist g_ll; +X int g_start; /* Start symbol of the grammar */ +X int g_accel; /* Set if accelerators present */ +X} grammar; +X +X/* FUNCTIONS */ +X +Xgrammar *newgrammar PROTO((int start)); +Xdfa *adddfa PROTO((grammar *g, int type, char *name)); +Xint addstate PROTO((dfa *d)); +Xvoid addarc PROTO((dfa *d, int from, int to, int lbl)); +Xdfa *finddfa PROTO((grammar *g, int type)); +Xchar *typename PROTO((grammar *g, int lbl)); +X +Xint addlabel PROTO((labellist *ll, int type, char *str)); +Xint findlabel PROTO((labellist *ll, int type, char *str)); +Xchar *labelrepr PROTO((label *lb)); +Xvoid translatelabels PROTO((grammar *g)); +X +Xvoid addfirstsets PROTO((grammar *g)); +X +Xvoid addaccellerators PROTO((grammar *g)); +X +Xvoid printgrammar PROTO((grammar *g, FILE *fp)); +Xvoid printnonterminals PROTO((grammar *g, FILE *fp)); +EOF +fi +if test -s 'src/intobject.h' +then echo '*** I will not over-write existing file src/intobject.h' +else +echo 'x - src/intobject.h' +sed 's/^X//' > 'src/intobject.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Integer object interface */ +X +X/* +X123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 +X +Xintobject represents a (long) integer. This is an immutable object; +Xan integer cannot change its value after creation. +X +XThere are functions to create new integer objects, to test an object +Xfor integer-ness, and to get the integer value. The latter functions +Xreturns -1 and sets errno to EBADF if the object is not an intobject. +XNone of the functions should be applied to nil objects. +X +XThe type intobject is (unfortunately) exposed bere so we can declare +XTrueObject and FalseObject below; don't use this. +X*/ +X +Xtypedef struct { +X OB_HEAD +X long ob_ival; +X} intobject; +X +Xextern typeobject Inttype; +X +X#define is_intobject(op) ((op)->ob_type == &Inttype) +X +Xextern object *newintobject PROTO((long)); +Xextern long getintvalue PROTO((object *)); +X +X +X/* +X123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 +X +XFalse and True are special intobjects used by Boolean expressions. +XAll values of type Boolean must point to either of these; but in +Xcontexts where integers are required they are integers (valued 0 and 1). +XHope these macros don't conflict with other people's. +X +XDon't forget to apply INCREF() when returning True or False!!! +X*/ +X +Xextern intobject FalseObject, TrueObject; /* Don't use these directly */ +X +X#define False ((object *) &FalseObject) +X#define True ((object *) &TrueObject) +X +X/* Macro, trading safety for speed */ +X#define GETINTVALUE(op) ((op)->ob_ival) +EOF +fi +if test -s 'src/intrcheck.c' +then echo '*** I will not over-write existing file src/intrcheck.c' +else +echo 'x - src/intrcheck.c' +sed 's/^X//' > 'src/intrcheck.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Check for interrupts */ +X +X#ifdef MSDOS +X +X/* This might work for MS-DOS (untested though): */ +X +Xvoid +Xinitintr() +X{ +X} +X +Xint +Xintrcheck() +X{ +X int interrupted = 0; +X while (kbhit()) { +X if (getch() == '\003') +X interrupted = 1; +X } +X return interrupted; +X} +X +X#define OK +X +X#endif +X +X +X#ifdef THINK_C +X +X/* This is for THINK C 4.0. +X For 3.0, you may have to remove the signal stuff. */ +X +X#include <MacHeaders> +X#include <signal.h> +X#include "sigtype.h" +X +Xstatic int interrupted; +X +Xstatic SIGTYPE +Xintcatcher(sig) +X int sig; +X{ +X interrupted = 1; +X signal(SIGINT, intcatcher); +X} +X +Xvoid +Xinitintr() +X{ +X if (signal(SIGINT, SIG_IGN) != SIG_IGN) +X signal(SIGINT, intcatcher); +X} +X +Xint +Xintrcheck() +X{ +X register EvQElPtr q; +X +X /* This is like THINK C 4.0's <console.h>. +X I'm not sure why FlushEvents must be called from asm{}. */ +X for (q = (EvQElPtr)EventQueue.qHead; q; q = (EvQElPtr)q->qLink) { +X if (q->evtQWhat == keyDown && +X (char)q->evtQMessage == '.' && +X (q->evtQModifiers & cmdKey) != 0) { +X +X asm { +X moveq #keyDownMask,d0 +X _FlushEvents +X } +X interrupted = 1; +X break; +X } +X } +X if (interrupted) { +X interrupted = 0; +X return 1; +X } +X return 0; +X} +X +X#define OK +X +X#endif /* THINK_C */ +X +X +X#ifndef OK +X +X/* Default version -- for real operating systems and for Standard C */ +X +X#include <stdio.h> +X#include <signal.h> +X#include "sigtype.h" +X +Xstatic int interrupted; +X +Xstatic SIGTYPE +Xintcatcher(sig) +X int sig; +X{ +X interrupted = 1; +X signal(SIGINT, intcatcher); +X} +X +Xvoid +Xinitintr() +X{ +X if (signal(SIGINT, SIG_IGN) != SIG_IGN) +X signal(SIGINT, intcatcher); +X} +X +Xint +Xintrcheck() +X{ +X if (!interrupted) +X return 0; +X interrupted = 0; +X return 1; +X} +X +X#endif /* !OK */ +EOF +fi +if test -s 'src/profmain.c' +then echo '*** I will not over-write existing file src/profmain.c' +else +echo 'x - src/profmain.c' +sed 's/^X//' > 'src/profmain.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X#include <stdio.h> +X#include "string.h" +X +X#include "PROTO.h" +X#include "grammar.h" +X#include "node.h" +X#include "parsetok.h" +X#include "graminit.h" +X#include "tokenizer.h" +X#include "errcode.h" +X#include "malloc.h" +X +Xextern int _profile; +X +Xextern grammar gram; /* From graminit.c */ +X +Xint debugging = 1; +X +XFILE *getopenfile() +X{ +X char buf[256]; +X char *p; +X FILE *fp; +X for (;;) { +X fprintf(stderr, "File name: "); +X if (fgets(buf, sizeof buf, stdin) == NULL) { +X fprintf(stderr, "EOF\n"); +X exit(1); +X } +X p = strchr(buf, '\n'); +X if (p != NULL) +X *p = '\0'; +X if ((fp = fopen(buf, "r")) != NULL) +X break; +X fprintf(stderr, "Sorry, try again.\n"); +X } +X return fp; +X} +X +Xmain() +X{ +X FILE *fp; +X _profile = 0; +X fp = getopenfile(); +X#if 0 +X askgo("Start tokenizing"); +X runtokenizer(fp); +X fseek(fp, 0L, 0); +X#endif +X if (!gram.g_accel) +X addaccelerators(&gram); +X askgo("Start parsing"); +X _profile = 1; +X runparser(fp); +X _profile = 0; +X freopen("prof.out", "w", stdout); +X DumpProfile(); +X fflush(stdout); +X exit(0); +X} +X +Xstatic int +Xruntokenizer(fp) +X FILE *fp; +X{ +X struct tok_state *tok; +X tok = tok_setupf(fp, "Tokenizing", "."); +X for (;;) { +X char *a, *b; +X register char *str; +X register int len; +X (void) tok_get(tok, &a, &b); +X if (tok->done != E_OK) +X break; +X len = b - a; +X str = NEW(char, len + 1); +X if (str == NULL) { +X fprintf(stderr, "no mem for next token"); +X break; +X } +X strncpy(str, a, len); +X str[len] = '\0'; +X } +X fprintf(stderr, "done (%d)\n", tok->done); +X} +X +Xstatic +Xrunparser(fp, start) +X FILE *fp; +X{ +X node *n; +X int ret; +X ret = parsefile(fp, &gram, module_input, "Parsing", ".", &n); +X fprintf(stderr, "done (%d)\n", ret); +X#if 0 +X _profile = 0; +X if (ret == E_DONE) +X listtree(n); +X#endif +X} +X +Xstatic int +Xaskgo(prompt) +X char *prompt; +X{ +X char buf[256]; +X fprintf(stderr, "%s: hit return when ready: ", prompt); +X fgets(buf, sizeof buf, stdin); +X} +EOF +fi +if test -s 'src/strtol.c' +then echo '*** I will not over-write existing file src/strtol.c' +else +echo 'x - src/strtol.c' +sed 's/^X//' > 'src/strtol.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* +X** strtol +X** This is a general purpose routine for converting +X** an ascii string to an integer in an arbitrary base. +X** Leading white space is ignored, if 'base' is zero +X** it looks for a leading 0, 0x or 0X to tell which +X** base. If these are absent it defaults to 10. +X** Base must be between 0 and 36. +X** If 'ptr' is non-NULL it will contain a pointer to +X** the end of the scan. +X** Errors due to bad pointers will probably result in +X** exceptions - we don't check for them. +X*/ +X +X#include "ctype.h" +X +Xlong +Xstrtol(str, ptr, base) +Xregister char * str; +Xchar ** ptr; +Xint base; +X{ +X register long result; /* return value of the function */ +X register int c; /* current input character */ +X int minus; /* true if a leading minus was found */ +X +X result = 0; +X minus = 0; +X +X/* catch silly bases */ +X if (base < 0 || base > 36) +X { +X if (ptr) +X *ptr = str; +X return result; +X } +X +X/* skip leading white space */ +X while (*str && isspace(*str)) +X str++; +X +X/* check for optional leading minus sign */ +X if (*str == '-') +X { +X minus = 1; +X str++; +X } +X +X/* check for leading 0 or 0x for auto-base or base 16 */ +X switch (base) +X { +X case 0: /* look for leading 0, 0x or 0X */ +X if (*str == '0') +X { +X str++; +X if (*str == 'x' || *str == 'X') +X { +X str++; +X base = 16; +X } +X else +X base = 8; +X } +X else +X base = 10; +X break; +X +X case 16: /* skip leading 0x or 0X */ +X if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')) +X str += 2; +X break; +X } +X +X/* do the conversion */ +X while (c = *str) +X { +X if (isdigit(c) && c - '0' < base) +X c -= '0'; +X else +X { +X if (isupper(c)) +X c = tolower(c); +X if (c >= 'a' && c <= 'z') +X c -= 'a' - 10; +X else /* non-"digit" character */ +X break; +X if (c >= base) /* non-"digit" character */ +X break; +X } +X result = result * base + c; +X str++; +X } +X +X/* set pointer to point to the last character scanned */ +X if (ptr) +X *ptr = str; +X return minus ? -result : result; +X} +EOF +fi +echo 'Part 17 out of 21 of pack.out complete.' +exit 0 diff --git a/shar/python-0.9.1-18-21.shar b/shar/python-0.9.1-18-21.shar new file mode 100644 index 0000000..6b566e7 --- /dev/null +++ b/shar/python-0.9.1-18-21.shar @@ -0,0 +1,2268 @@ +: This is a shell archive. +: Extract with 'sh this_file'. +: +: Extract part 01 first since it makes all directories +echo 'Start of pack.out, part 18 out of 21:' +if test -s 'demo/sgi/gl/backface.py' +then echo '*** I will not over-write existing file demo/sgi/gl/backface.py' +else +echo 'x - demo/sgi/gl/backface.py' +sed 's/^X//' > 'demo/sgi/gl/backface.py' << 'EOF' +X#! /ufs/guido/bin/sgi/python +X +X# backface +X# +X# draw a cube that can run with backface() turned on or off. +X# cube is moved when LEFTMOUSE is pressed and mouse itself is moved. +X +Xfrom gl import * +Xfrom DEVICE import * +Xfrom GL import * +X +XCUBE_SIZE = 200.0 +XCUBE_OBJ = 1 +X +Xdef main () : +X # +X x = 0 +X y = 0 +X moveit = 0 +X # +X initialize() +X # +X while (1) : +X # +X while (qtest()) : +X dev, val = qread() +X # +X if dev = ESCKEY : +X backface(0) +X return +X # +X elif dev = REDRAW : +X reshapeviewport() +X drawcube(x,y) +X # +X elif dev = LEFTMOUSE : +X # +X # LEFTMOUSE down +X moveit = val +X # +X elif dev = BKEY : +X backface(1) +X drawcube(x,y) +X # +X elif dev = FKEY : +X backface(0) +X drawcube(x,y) +X # +X if moveit : +X x = getvaluator(MOUSEX) +X y = getvaluator(MOUSEY) +X drawcube(x,y) +X +X +Xdef initialize () : +X foreground () +X keepaspect (1, 1) +X gid = winopen('backface') +X winset(gid) +X winconstraints() +X # +X doublebuffer() +X gconfig() +X shademodel(FLAT) +X # +X ortho(-1024.0, 1024.0, -1024.0, 1024.0, -1024.0, 1024.0) +X # +X qdevice(ESCKEY) +X qdevice(REDRAW) +X qdevice(LEFTMOUSE) +X qdevice(BKEY) +X qdevice(FKEY) +X qenter(REDRAW,gid) +X # +X backface(1) +X +X# +X# define a cube +Xdef cube () : +X # +X # front face +X pushmatrix() +X translate(0.0,0.0,CUBE_SIZE) +X color(RED) +X rectf(-CUBE_SIZE,-CUBE_SIZE,CUBE_SIZE,CUBE_SIZE) +X popmatrix() +X # +X # right face +X pushmatrix() +X translate(CUBE_SIZE, 0.0, 0.0) +X rotate(900, 'y') +X color(GREEN) +X rectf(-CUBE_SIZE,-CUBE_SIZE,CUBE_SIZE,CUBE_SIZE) +X popmatrix() +X # +X # back face +X pushmatrix() +X translate(0.0, 0.0, -CUBE_SIZE) +X rotate(1800, 'y') +X color(BLUE) +X rectf(-CUBE_SIZE,-CUBE_SIZE,CUBE_SIZE,CUBE_SIZE) +X popmatrix() +X # +X # left face +X pushmatrix() +X translate(-CUBE_SIZE, 0.0, 0.0) +X rotate(-900, 'y') +X color(CYAN) +X rectf(-CUBE_SIZE,-CUBE_SIZE,CUBE_SIZE,CUBE_SIZE) +X popmatrix() +X # +X # top face +X pushmatrix() +X translate(0.0, CUBE_SIZE, 0.0) +X rotate(-900, 'x') +X color(MAGENTA) +X rectf(-CUBE_SIZE,-CUBE_SIZE,CUBE_SIZE,CUBE_SIZE) +X popmatrix() +X # +X # bottom face +X pushmatrix() +X translate(0.0, -CUBE_SIZE, 0.0) +X rotate(900, 'x') +X color(YELLOW) +X rectf(-CUBE_SIZE,-CUBE_SIZE,CUBE_SIZE,CUBE_SIZE) +X popmatrix() +X +Xdef drawcube(x,y) : +X # +X pushmatrix() +X rotate(2*x, 'x') +X rotate(2*y, 'y') +X color(BLACK) +X clear() +X cube() +X popmatrix() +X swapbuffers() +X +X +Xmain () +EOF +chmod +x 'demo/sgi/gl/backface.py' +fi +if test -s 'demo/sgi/gl/mclock.doc' +then echo '*** I will not over-write existing file demo/sgi/gl/mclock.doc' +else +echo 'x - demo/sgi/gl/mclock.doc' +sed 's/^X//' > 'demo/sgi/gl/mclock.doc' << 'EOF' +XNewsgroups: cwi.sgi +XSubject: Re: new clock +XDistribution: cwi.sgi +XReferences: <[email protected]> +X +XLast week I wrote: +X +X>For your enjoyment I have implemented a colorful clock. +X +XThe clock has now been extended with some new facilities: a menu, an +Xalarm and a gong. These may require some explanation beyond what's in +Xthe usage message. +X +XMenu +X---- +XThe right mouse button now pops up a menu that allows you to turn the +Xseconds hand on or off and to switch the alarm off. +X +XAlarm +X----- +X +XThe left and middle buttons set the alarm. When it is on, the alarm +Xtime is displayed as a time on a 24 hour clock in the bottom left +Xcorner. It is also indicated by two red triangles, corresponding to the +Xlittle (hours) and big (minutes) hand. These hands can be moved around: +Xthe left mouse button moves the minutes hand, the middle button moves +Xthe hourds hand. Watch out for differences of twelve hours (always +Xcheck the digital display); these can be corrected by dragging the hours +Xhand once around the dial. +X +XWhen the alarm goes off, two things happen: a shell command specified on +Xthe command line with the -a option is executed (in the background), and +Xthe clock's colors change every two seconds, for five minutes. You can +Xalso turn the alarm off by using the menu accessible through the right +Xmouse button. +X +XThere is no default command for the -a option; if it is not specified, +Xonly the changing of the colors happens. If you have an 8 ohm speaker +Xconnected to the audio output of your Personal Iris, a suitable command +Xwould be: +X +X mclock -a '/ufs/guido/bin/sgi/play /ufs/guido/lib/sounds/alarm' +X +XGong +X---- +X +XSome people like a clock that makes noises every hour, or even more +Xoften. This is supported by the -g and -G options. With -g you specify +Xa shell command to be executed to sound the gong; with -G you can +Xspecify the interval between gong calls, in seconds (default is one hour). +XThe shell command is executed in the background. It is given two +Xarguments: the hours (on a 24 hour clock!) and the minutes. The +Xexecutable Python script /ufs/guido/bin/sgi/chime is a suitable example. +XAgain, this only works if you have installed a speaker (I bet 8 ohm +Xspeakers are going to be in demand!) +X +X-- +XGuido van Rossum, Centre for Mathematics and Computer Science (CWI), Amsterdam [email protected] or ..!hp4nl!cwi.nl!guido or guido%[email protected] +X"A thing of beauty is a joy till sunrise" +EOF +fi +if test -s 'demo/sgi/gl/mixing.py' +then echo '*** I will not over-write existing file demo/sgi/gl/mixing.py' +else +echo 'x - demo/sgi/gl/mixing.py' +sed 's/^X//' > 'demo/sgi/gl/mixing.py' << 'EOF' +X#! /ufs/guido/bin/sgi/python +X +X# Use Gouraud shading to mix colors. Requires Z-buffer. +X# It changes the color assignments so fast that you see white. +X# Left button pauses, middle rotates the square. ESC to quit. +X# Experiment with a larger window (too slow) or smaller window (really white). +X +Xfrom GL import * +Xfrom gl import * +Ximport DEVICE +Xfrom math import * +X +X# +X# tekenvlak : draw a square. with bgnpolygon +X# +Xdef tekenvlak (vc) : +X bgnpolygon() +X #vcarray (vc) +X for i in vc : +X c3f (i[1]) +X v3f (i[0]) +X endpolygon() +X +X# +X# tekendoos : draw a box +X# +Xdef tekendoos (col) : +X v = [(-5.0,0.0,0.0),(0.0,5.0,0.0),(5.0,0.0,0.0),(0.0,-5.0,0.0)] +X vc = [(v[0],col[0]),(v[1],col[1]),(v[2],col[2]),(v[3],col[1])] +X tekenvlak (vc) +X +X# +X# initialize gl +X# +Xdef initgl () : +X # +X # open window +X # +X foreground () +X keepaspect (1, 1) +X prefposition (100, 500, 100, 500) +X w = winopen ('PYTHON RGB') +X keepaspect (1, 1) +X winconstraints() +X # +X # configure pipeline (2buf, GOURAUD and RGBmode) +X # +X doublebuffer () +X zbuffer (1) +X shademodel (GOURAUD) +X RGBmode () +X gconfig () +X # +X # set viewing +X # +X perspective (900, 1, 1.0, 10.0) +X polarview (10.0, 0, 0, 0) +X # +X # ask for the REDRAW and ESCKEY events +X # +X qdevice(DEVICE.MOUSE2) +X qdevice(DEVICE.MOUSE3) +X qdevice(DEVICE.REDRAW) +X qdevice(DEVICE.ESCKEY) +X +X +X# +X# the color black +X# +Xblack = 0 +X# +X# GoForIT : use 2buf to redraw the object 2n times. index i is used as +X# the (smoothly changing) rotation angle +X# +Xdef GoForIt(i) : +X col = [(255.0,0.0,0.0), (0.0,255.0,0.0), (0.0,0.0,255.0)] +X twist = 0 +X freeze = 1 +X while 1 : +X if freeze <> 0 : +X col[0],col[1],col[2] = col[1],col[2],col[0] +X # +X # clear z-buffer and clear background to light-blue +X # +X zclear() +X cpack (black) +X clear() +X # +X tekendoos (col) +X # +X swapbuffers() +X # +X if qtest() <> 0 : +X dev, val = qread() +X if dev = DEVICE.ESCKEY : +X break +X elif dev = DEVICE.REDRAW : +X reshapeviewport () +X elif dev = DEVICE.MOUSE2 and val <> 0 : +X twist = twist + 30 +X perspective (900, 1, 1.0, 10.0) +X polarview (10.0, 0, 0, twist) +X elif dev = DEVICE.MOUSE3 and val <> 0 : +X freeze = 1 - freeze +X +X +X# the main program +X# +Xdef main () : +X initgl () +X GoForIt (0) +X +X# +X# exec main +X# +Xmain () +EOF +chmod +x 'demo/sgi/gl/mixing.py' +fi +if test -s 'demo/sgi/gl_panel/twoview/observer.s' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/twoview/observer.s' +else +echo 'x - demo/sgi/gl_panel/twoview/observer.s' +sed 's/^X//' > 'demo/sgi/gl_panel/twoview/observer.s' << 'EOF' +X;;; This file was automatically generated by the panel editor. +X;;; If you read it into gnu emacs, it will automagically format itself. +X +X(panel (prop help creator:user-panel-help) +X(prop user-panel #t) +X(label "Observer Control") +X(x 876) +X(y 10) +X(al (pnl_right_arrow_button (name "right") +X(prop help creator:user-act-help) +X(x 3.2) +X(y 2.09) +X(downfunc move-then-resize) +X) +X(pnl_up_double_arrow_button (name "fast_forward") +X(prop help creator:user-act-help) +X(label "step forward") +X(x 2.66) +X(y 3.13) +X(h 0.45) +X(labeltype 4) +X(downfunc move-then-resize) +X) +X(pnl_up_arrow_button (name "forward") +X(prop help creator:user-act-help) +X(x 2.66) +X(y 2.64) +X(downfunc move-then-resize) +X) +X(pnl_down_arrow_button (name "reverse") +X(prop help creator:user-act-help) +X(x 2.66) +X(y 1.49) +X(h 0.45) +X(labeltype 12) +X(downfunc move-then-resize) +X) +X(pnl_down_double_arrow_button (name "fast_reverse") +X(prop help creator:user-act-help) +X(label "step back") +X(x 2.66) +X(y 1) +X(labeltype 12) +X(downfunc move-then-resize) +X) +X(pnl_left_arrow_button (name "left") +X(prop help creator:user-act-help) +X(x 2.11) +X(y 2.09) +X(downfunc move-then-resize) +X) +X(pnl_right_double_arrow_button (name "fast_right") +X(prop help creator:user-act-help) +X(label "turn right") +X(x 3.75) +X(y 2.09) +X(downfunc move-then-resize) +X) +X(pnl_left_double_arrow_button (name "fast_left") +X(prop help creator:user-act-help) +X(label "turn left") +X(x 1.57) +X(y 2.09) +X(labeltype 8) +X(downfunc move-then-resize) +X) +X(pnl_vslider (name "ypos") +X(prop help creator:user-act-help) +X(x 6.25) +X(y 1) +X(w 0.4) +X(h 2.9) +X(val 0.0758) +X(downfunc move-then-resize) +X) +X(pnl_down_arrow_button (name "down") +X(prop help creator:user-act-help) +X(label "eye height") +X(x 6.25) +X(y 0.5) +X(labeltype 12) +X(downfunc move-then-resize) +X) +X(pnl_up_arrow_button (name "up") +X(prop help creator:user-act-help) +X(x 6.25) +X(y 4) +X(downfunc move-then-resize) +X) +X) +X) +X;;; Local Variables: +X;;; mode: scheme +X;;; eval: (save-excursion (goto-char (point-min)) (kill-line 3)) +X;;; eval: (save-excursion (goto-char (point-min)) (replace-regexp "[ \n]*)" ")")) +X;;; eval: (indent-region (point-min) (point-max) nil) +X;;; eval: (progn (kill-line -3) (delete-backward-char 1) (save-buffer)) +X;;; End: +EOF +fi +if test -s 'lib/CSplit.py' +then echo '*** I will not over-write existing file lib/CSplit.py' +else +echo 'x - lib/CSplit.py' +sed 's/^X//' > 'lib/CSplit.py' << 'EOF' +X# A CSplit is a Clock-shaped split: the children are grouped in a circle. +X# The numbering is a little different from a real clock: the 12 o'clock +X# position is called 0, not 12. This is a little easier since Python +X# usually counts from zero. (BTW, there needn't be exactly 12 children.) +X +X +Xfrom math import pi, sin, cos +Xfrom Split import Split +X +Xclass CSplit() = Split(): +X # +X def minsize(self, m): +X # Since things look best if the children are spaced evenly +X # along the circle (and often all children have the same +X # size anyway) we compute the max child size and assume +X # this is each child's size. +X width, height = 0, 0 +X for child in self.children: +X wi, he = child.minsize(m) +X width = max(width, wi) +X height = max(height, he) +X # In approximation, the diameter of the circle we need is +X # (diameter of box) * (#children) / pi. +X # We approximate pi by 3 (so we slightly overestimate +X # our minimal size requirements -- not so bad). +X # Because the boxes stick out of the circle we add the +X # box size to each dimension. +X # Because we really deal with ellipses, do everything +X # separate in each dimension. +X n = len(self.children) +X return width + (width*n + 2)/3, height + (height*n + 2)/3 +X # +X def getbounds(self): +X return self.bounds +X # +X def setbounds(self, bounds): +X self.bounds = bounds +X # Place the children. This involves some math. +X # Compute center positions for children as if they were +X # ellipses with a diameter about 1/N times the +X # circumference of the big ellipse. +X # (There is some rounding involved to make it look +X # reasonable for small and large N alike.) +X # XXX One day Python will have automatic conversions... +X n = len(self.children) +X fn = float(n) +X if n = 0: return +X (left, top), (right, bottom) = bounds +X width, height = right-left, bottom-top +X child_width, child_height = width*3/(n+4), height*3/(n+4) +X half_width, half_height = \ +X float(width-child_width)/2.0, \ +X float(height-child_height)/2.0 +X center_h, center_v = center = (left+right)/2, (top+bottom)/2 +X fch, fcv = float(center_h), float(center_v) +X alpha = 2.0 * pi / fn +X for i in range(n): +X child = self.children[i] +X fi = float(i) +X fh, fv = \ +X fch + half_width*sin(fi*alpha), \ +X fcv - half_height*cos(fi*alpha) +X left, top = \ +X int(fh) - child_width/2, \ +X int(fv) - child_height/2 +X right, bottom = \ +X left + child_width, \ +X top + child_height +X child.setbounds((left, top), (right, bottom)) +X # +EOF +fi +if test -s 'lib/TransParent.py' +then echo '*** I will not over-write existing file lib/TransParent.py' +else +echo 'x - lib/TransParent.py' +sed 's/^X//' > 'lib/TransParent.py' << 'EOF' +X# A class that sits transparently between a parent and one child. +X# First create the parent, then this thing, then the child. +X# Use this as a base class for objects that are almost transparent. +X# Don't use as a base class for parents with multiple children. +X +XError = 'TransParent.Error' # Exception +X +Xclass ManageOneChild(): +X # +X # Upcalls shared with other single-child parents +X # +X def addchild(self, child): +X if self.child: +X raise Error, 'addchild: one child only' +X if not child: +X raise Error, 'addchild: bad child' +X self.child = child +X # +X def delchild(self, child): +X if not self.child: +X raise Error, 'delchild: no child' +X if child <> self.child: +X raise Error, 'delchild: not my child' +X self.child = 0 +X +Xclass TransParent() = ManageOneChild(): +X # +X # Calls from creator +X # NB derived classes may add parameters to create() +X # +X def create(self, parent): +X parent.addchild(self) +X self.parent = parent +X self.child = 0 # No child yet +X # +X # Downcalls from parent to child +X # +X def destroy(self): +X del self.parent +X if self.child: self.child.destroy() +X del self.child +X # +X def minsize(self, m): +X if not self.child: +X return 0, 0 +X else: +X return self.child.minsize(m) +X def getbounds(self, bounds): +X if not self.child: +X raise Error, 'getbounds w/o child' +X else: +X return self.child.getbounds() +X def setbounds(self, bounds): +X if not self.child: +X raise Error, 'setbounds w/o child' +X else: +X self.child.setbounds(bounds) +X def draw(self, args): +X if self.child: +X self.child.draw(args) +X # +X # Downcalls only made after certain upcalls +X # +X def mouse_down(self, detail): +X if self.child: self.child.mouse_down(detail) +X def mouse_move(self, detail): +X if self.child: self.child.mouse_move(detail) +X def mouse_up(self, detail): +X if self.child: self.child.mouse_up(detail) +X # +X def timer(self): +X if self.child: self.child.timer() +X # +X # Upcalls from child to parent +X # +X def need_mouse(self, child): +X self.parent.need_mouse(self) +X def no_mouse(self, child): +X self.parent.no_mouse(self) +X # +X def need_timer(self, child): +X self.parent.need_timer(self) +X def no_timer(self, child): +X self.parent.no_timer(self) +X # +X def begindrawing(self): +X return self.parent.begindrawing() +X def beginmeasuring(self): +X return self.parent.beginmeasuring() +X # +X def change(self, area): +X self.parent.change(area) +X def scroll(self, args): +X self.parent.scroll(args) +X def settimer(self, itimer): +X self.parent.settimer(itimer) +EOF +fi +if test -s 'lib/auds.py' +then echo '*** I will not over-write existing file lib/auds.py' +else +echo 'x - lib/auds.py' +sed 's/^X//' > 'lib/auds.py' << 'EOF' +Ximport audio +X +XRATE = 8192 +X +X# Initialize the audio stuff +Xaudio.setrate(3) +Xaudio.setoutgain(100) # for speaker +X +Xplay = audio.write +X +Xdef samp(n): +X savegain = audio.getoutgain() +X try: +X audio.setoutgain(0) +X x = raw_input('Hit Enter to sample ' + `n` + ' seconds: ') +X return audio.read(n*RATE) +X finally: +X audio.setoutgain(savegain) +X +Xdef echo(s, delay, gain): +X return s[:delay] + audio.add(s[delay:], audio.amplify(s, gain, gain)) +X +Xdef save(s, file): +X f = open(file, 'w') +X f.write(s) +X +Xdef load(file): +X return loadfp(open(file, 'r')) +X +Xdef loadfp(fp): +X s = '' +X while 1: +X buf = fp.read(16*1024) +X if not buf: break +X s = s + buf +X return s +X +Xdef unbias(s): +X if not s: return s +X a = audio.chr2num(s) +X sum = 0 +X for i in a: sum = sum + i +X bias = (sum + len(a)/2) / len(a) +X print 'Bias value:', bias +X if bias: +X for i in range(len(a)): +X a[i] = a[i] - bias +X s = audio.num2chr(a) +X return s +X +X# Stretch by a/b. +X# Think of this as converting the sampling rate from a samples/sec +X# to b samples/sec. Or, if the input is a bytes long, the output +X# will be b bytes long. +X# +Xdef stretch(s, a, b): +X y = audio.chr2num(s) +X m = len(y) +X out = [] +X n = m * b / a +X # i, j will walk through y and out (step 1) +X # ib, ja are i*b, j*a and are kept as close together as possible +X i, ib = 0, 0 +X j, ja = 0, 0 +X for j in range(n): +X ja = ja+a +X while ib < ja: +X i = i+1 +X ib = ib+b +X if i >= m: +X break +X if ib = ja: +X out.append(y[i]) +X else: +X out.append((y[i]*(ja-(ib-b)) + y[i-1]*(ib-ja)) / b) +X return audio.num2chr(out) +X +Xdef sinus(freq): # return a 1-second sine wave +X from math import sin, pi +X factor = 2.0*pi*float(freq)/float(RATE) +X list = range(RATE) +X for i in list: +X list[i] = int(sin(float(i) * factor) * 127.0) +X return audio.num2chr(list) +X +Xdef softclip(s): +X if '\177' not in s and '\200' not in s: +X return s +X num = audio.chr2num(s) +X extremes = (-128, 127) +X for i in range(1, len(num)-1): +X if num[i] in extremes: +X num[i] = (num[i-1] + num[i+1]) / 2 +X return audio.num2chr(num) +X +Xdef demo(): +X gday = load('gday')[1000:6000] +X save(gday, 'gday0') +X gg = [gday] +X for i in range(1, 10): +X for g in gg: play(g) +X g = stretch(gday, 10, 10-i) +X save(g, 'gday' + `i`) +X gg.append(g) +X while 1: +X for g in gg: play(g) +EOF +fi +if test -s 'lib/listwin.py' +then echo '*** I will not over-write existing file lib/listwin.py' +else +echo 'x - lib/listwin.py' +sed 's/^X//' > 'lib/listwin.py' << 'EOF' +X# Module 'listwin' +X# List windows, a subclass of gwin +X +Ximport gwin +Ximport stdwin +X +Xdef maxlinewidth(a): # Compute maximum textwidth of lines in a sequence +X max = 0 +X for line in a: +X width = stdwin.textwidth(line) +X if width > max: max = width +X return max +X +Xdef action(w, string, i, detail): # Default item selection method +X pass +X +Xdef mup(w, detail): # Mouse up method +X (h, v), clicks, button, mask = detail +X i = divmod(v, w.lineheight)[0] +X if 0 <= i < len(w.data): +X w.action(w, w.data[i], i, detail) +X +Xdef draw(w, ((left, top), (right, bottom))): # Text window draw method +X data = w.data +X d = w.begindrawing() +X lh = w.lineheight +X itop = top/lh +X ibot = (bottom-1)/lh + 1 +X if itop < 0: itop = 0 +X if ibot > len(data): ibot = len(data) +X for i in range(itop, ibot): d.text((0, i*lh), data[i]) +X +Xdef open(title, data): # Display a list of texts in a window +X lineheight = stdwin.lineheight() +X h, v = maxlinewidth(data), len(data)*lineheight +X h0, v0 = h + stdwin.textwidth(' '), v + lineheight +X if h0 > stdwin.textwidth(' ')*80: h0 = 0 +X if v0 > stdwin.lineheight()*24: v0 = 0 +X stdwin.setdefwinsize(h0, v0) +X w = gwin.open(title) +X w.setdocsize(h, v) +X w.lineheight = lineheight +X w.data = data +X w.draw = draw +X w.action = action +X w.mup = mup +X return w +EOF +fi +if test -s 'lib/macpath.py' +then echo '*** I will not over-write existing file lib/macpath.py' +else +echo 'x - lib/macpath.py' +sed 's/^X//' > 'lib/macpath.py' << 'EOF' +X# module 'macpath' -- pathname (or -related) operations for the Macintosh +X +Ximport mac +X +Xfrom stat import * +X +X +X# Return true if a path is absolute. +X# On the Mac, relative paths begin with a colon, +X# but as a special case, paths with no colons at all are also relative. +X# Anything else is absolute (the string up to the first colon is the +X# volume name). +X +Xdef isabs(s): +X return ':' in s and s[0] <> ':' +X +X +X# Concatenate two pathnames. +X# The result is equivalent to what the second pathname would refer to +X# if the first pathname were the current directory. +X +Xdef cat(s, t): +X if (not s) or isabs(t): return t +X if t[:1] = ':': t = t[1:] +X if ':' not in s: +X s = ':' + s +X if s[-1:] <> ':': +X s = s + ':' +X return s + t +X +X +X# Split a pathname in two parts: the directory leading up to the final bit, +X# and the basename (the filename, without colons, in that directory). +X# The result (s, t) is such that cat(s, t) yields the original argument. +X +Xdef split(s): +X if ':' not in s: return '', s +X colon = 0 +X for i in range(len(s)): +X if s[i] = ':': colon = i+1 +X return s[:colon], s[colon:] +X +X +X# Normalize a pathname: get rid of '::' sequences by backing up, +X# e.g., 'foo:bar::bletch' becomes 'foo:bletch'. +X# Raise the exception norm_error below if backing up is impossible, +X# e.g., for '::foo'. +X +Xnorm_error = 'macpath.norm_error: path cannot be normalized' +X +Xdef norm(s): +X import string +X if ':' not in s: +X return ':' + s +X f = string.splitfields(s, ':') +X pre = [] +X post = [] +X if not f[0]: +X pre = f[:1] +X f = f[1:] +X if not f[len(f)-1]: +X post = f[-1:] +X f = f[:-1] +X res = [] +X for seg in f: +X if seg: +X res.append(seg) +X else: +X if not res: raise norm_error, 'path starts with ::' +X del res[len(res)-1] +X if not (pre or res): +X raise norm_error, 'path starts with volume::' +X if pre: res = pre + res +X if post: res = res + post +X s = res[0] +X for seg in res[1:]: +X s = s + ':' + seg +X return s +X +X +X# Return true if the pathname refers to an existing directory. +X +Xdef isdir(s): +X try: +X st = mac.stat(s) +X except mac.error: +X return 0 +X return S_ISDIR(st[ST_MODE]) +X +X +X# Return true if the pathname refers to an existing regular file. +X +Xdef isfile(s): +X try: +X st = mac.stat(s) +X except mac.error: +X return 0 +X return S_ISREG(st[ST_MODE]) +X +X +X# Return true if the pathname refers to an existing file or directory. +X +Xdef exists(s): +X try: +X st = mac.stat(s) +X except mac.error: +X return 0 +X return 1 +EOF +fi +if test -s 'lib/textwin.py' +then echo '*** I will not over-write existing file lib/textwin.py' +else +echo 'x - lib/textwin.py' +sed 's/^X//' > 'lib/textwin.py' << 'EOF' +X# Module 'textwin' +X +X# Text windows, a subclass of gwin +X +Ximport stdwin +Ximport stdwinsupport +Ximport gwin +X +XS = stdwinsupport # Shorthand +X +X +Xdef fixsize(w): +X docwidth, docheight = w.text.getrect()[1] +X winheight = w.getwinsize()[1] +X if winheight > docheight: docheight = winheight +X w.setdocsize(0, docheight) +X fixeditmenu(w) +X +Xdef cut(w, m, id): +X s = w.text.getfocustext() +X if s: +X stdwin.setcutbuffer(0, s) +X w.text.replace('') +X fixsize(w) +X +Xdef copy(w, m, id): +X s = w.text.getfocustext() +X if s: +X stdwin.setcutbuffer(0, s) +X fixeditmenu(w) +X +Xdef paste(w, m, id): +X w.text.replace(stdwin.getcutbuffer(0)) +X fixsize(w) +X +Xdef addeditmenu(w): +X m = w.editmenu = w.menucreate('Edit') +X m.action = [] +X m.additem('Cut', 'X') +X m.action.append(cut) +X m.additem('Copy', 'C') +X m.action.append(copy) +X m.additem('Paste', 'V') +X m.action.append(paste) +X +Xdef fixeditmenu(w): +X m = w.editmenu +X f = w.text.getfocus() +X can_copy = (f[0] < f[1]) +X m.enable(1, can_copy) +X if not w.readonly: +X m.enable(0, can_copy) +X m.enable(2, (stdwin.getcutbuffer(0) <> '')) +X +Xdef draw(w, area): # Draw method +X w.text.draw(area) +X +Xdef size(w, newsize): # Size method +X w.text.move((0, 0), newsize) +X fixsize(w) +X +Xdef close(w): # Close method +X del w.text # Break circular ref +X gwin.close(w) +X +Xdef char(w, c): # Char method +X w.text.replace(c) +X fixsize(w) +X +Xdef backspace(w): # Backspace method +X void = w.text.event(S.we_command, w, S.wc_backspace) +X fixsize(w) +X +Xdef arrow(w, detail): # Arrow method +X w.text.arrow(detail) +X fixeditmenu(w) +X +Xdef mdown(w, detail): # Mouse down method +X void = w.text.event(S.we_mouse_down, w, detail) +X fixeditmenu(w) +X +Xdef mmove(w, detail): # Mouse move method +X void = w.text.event(S.we_mouse_move, w, detail) +X +Xdef mup(w, detail): # Mouse up method +X void = w.text.event(S.we_mouse_up, w, detail) +X fixeditmenu(w) +X +Xdef activate(w): # Activate method +X fixeditmenu(w) +X +Xdef open(title, str): # Display a string in a window +X w = gwin.open(title) +X w.readonly = 0 +X w.text = w.textcreate((0, 0), w.getwinsize()) +X w.text.replace(str) +X w.text.setfocus(0, 0) +X addeditmenu(w) +X fixsize(w) +X w.draw = draw +X w.size = size +X w.close = close +X w.mdown = mdown +X w.mmove = mmove +X w.mup = mup +X w.char = char +X w.backspace = backspace +X w.arrow = arrow +X w.activate = activate +X return w +X +Xdef open_readonly(title, str): # Same with char input disabled +X w = open(title, str) +X w.readonly = 1 +X w.char = w.backspace = gwin.nop +X # Disable Cut and Paste menu item; leave Copy alone +X w.editmenu.enable(0, 0) +X w.editmenu.enable(2, 0) +X return w +EOF +fi +if test -s 'lib/zmod.py' +then echo '*** I will not over-write existing file lib/zmod.py' +else +echo 'x - lib/zmod.py' +sed 's/^X//' > 'lib/zmod.py' << 'EOF' +X# module 'zmod' +X +X# Compute properties of mathematical "fields" formed by taking +X# Z/n (the whole numbers modulo some whole number n) and an +X# irreducible polynomial (i.e., a polynomial with only complex zeros), +X# e.g., Z/5 and X**2 + 2. +X# +X# The field is formed by taking all possible linear combinations of +X# a set of d base vectors (where d is the degree of the polynomial). +X# +X# Note that this procedure doesn't yield a field for all combinations +X# of n and p: it may well be that some numbers have more than one +X# inverse and others have none. This is what we check. +X# +X# Remember that a field is a ring where each element has an inverse. +X# A ring has commutative addition and multiplication, a zero and a one: +X# 0*x = x*0 = 0, 0+x = x+0 = x, 1*x = x*1 = x. Also, the distributive +X# property holds: a*(b+c) = a*b + b*c. +X# (XXX I forget if this is an axiom or follows from the rules.) +X +Ximport poly +X +X +X# Example N and polynomial +X +XN = 5 +XP = poly.plus(poly.one(0, 2), poly.one(2, 1)) # 2 + x**2 +X +X +X# Return x modulo y. Returns >= 0 even if x < 0. +X +Xdef mod(x, y): +X return divmod(x, y)[1] +X +X +X# Normalize a polynomial modulo n and modulo p. +X +Xdef norm(a, n, p): +X a = poly.modulo(a, p) +X a = a[:] +X for i in range(len(a)): a[i] = mod(a[i], n) +X a = poly.normalize(a) +X return a +X +X +X# Make a list of all n^d elements of the proposed field. +X +Xdef make_all(mat): +X all = [] +X for row in mat: +X for a in row: +X all.append(a) +X return all +X +Xdef make_elements(n, d): +X if d = 0: return [poly.one(0, 0)] +X sub = make_elements(n, d-1) +X all = [] +X for a in sub: +X for i in range(n): +X all.append(poly.plus(a, poly.one(d-1, i))) +X return all +X +Xdef make_inv(all, n, p): +X x = poly.one(1, 1) +X inv = [] +X for a in all: +X inv.append(norm(poly.times(a, x), n, p)) +X return inv +X +Xdef checkfield(n, p): +X all = make_elements(n, len(p)-1) +X inv = make_inv(all, n, p) +X all1 = all[:] +X inv1 = inv[:] +X all1.sort() +X inv1.sort() +X if all1 = inv1: print 'BINGO!' +X else: +X print 'Sorry:', n, p +X print all +X print inv +X +Xdef rj(s, width): +X if type(s) <> type(''): s = `s` +X n = len(s) +X if n >= width: return s +X return ' '*(width - n) + s +X +Xdef lj(s, width): +X if type(s) <> type(''): s = `s` +X n = len(s) +X if n >= width: return s +X return s + ' '*(width - n) +EOF +fi +if test -s 'src/PROTO.h' +then echo '*** I will not over-write existing file src/PROTO.h' +else +echo 'x - src/PROTO.h' +sed 's/^X//' > 'src/PROTO.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* +XThe macro PROTO(x) is used to put function prototypes in the source. +XThis is defined differently for compilers that support prototypes than +Xfor compilers that don't. It should be used as follows: +X int some_function PROTO((int arg1, char *arg2)); +XA variant FPROTO(x) is used for cases where Standard C allows prototypes +Xbut Think C doesn't (mostly function pointers). +X +XThis file also defines the macro HAVE_PROTOTYPES if and only if +Xthe PROTO() macro expands the prototype. It is also allowed to predefine +XHAVE_PROTOTYPES to force prototypes on. +X*/ +X +X#ifndef PROTO +X +X#ifdef __STDC__ +X#define HAVE_PROTOTYPES +X#endif +X +X#ifdef THINK_C +X#undef HAVE_PROTOTYPES +X#define HAVE_PROTOTYPES +X#endif +X +X#ifdef sgi +X#ifdef mips +X#define HAVE_PROTOTYPES +X#endif +X#endif +X +X#ifdef HAVE_PROTOTYPES +X#define PROTO(x) x +X#else +X#define PROTO(x) () +X#endif +X +X#endif /* PROTO */ +X +X +X/* FPROTO() is for cases where Think C doesn't like prototypes */ +X +X#ifdef THINK_C +X#define FPROTO(arglist) () +X#else /* !THINK_C */ +X#define FPROTO(arglist) PROTO(arglist) +X#endif /* !THINK_C */ +X +X#ifndef HAVE_PROTOTYPES +X#define const /*empty*/ +X#else /* HAVE_PROTOTYPES */ +X#ifdef THINK_C +X#undef const +X#define const /*empty*/ +X#endif /* THINK_C */ +X#endif /* HAVE_PROTOTYPES */ +EOF +fi +if test -s 'src/bitset.c' +then echo '*** I will not over-write existing file src/bitset.c' +else +echo 'x - src/bitset.c' +sed 's/^X//' > 'src/bitset.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Bitset primitives used by the parser generator */ +X +X#include "pgenheaders.h" +X#include "bitset.h" +X +Xbitset +Xnewbitset(nbits) +X int nbits; +X{ +X int nbytes = NBYTES(nbits); +X bitset ss = NEW(BYTE, nbytes); +X +X if (ss == NULL) +X fatal("no mem for bitset"); +X +X ss += nbytes; +X while (--nbytes >= 0) +X *--ss = 0; +X return ss; +X} +X +Xvoid +Xdelbitset(ss) +X bitset ss; +X{ +X DEL(ss); +X} +X +Xint +Xaddbit(ss, ibit) +X bitset ss; +X int ibit; +X{ +X int ibyte = BIT2BYTE(ibit); +X BYTE mask = BIT2MASK(ibit); +X +X if (ss[ibyte] & mask) +X return 0; /* Bit already set */ +X ss[ibyte] |= mask; +X return 1; +X} +X +X#if 0 /* Now a macro */ +Xint +Xtestbit(ss, ibit) +X bitset ss; +X int ibit; +X{ +X return (ss[BIT2BYTE(ibit)] & BIT2MASK(ibit)) != 0; +X} +X#endif +X +Xint +Xsamebitset(ss1, ss2, nbits) +X bitset ss1, ss2; +X int nbits; +X{ +X int i; +X +X for (i = NBYTES(nbits); --i >= 0; ) +X if (*ss1++ != *ss2++) +X return 0; +X return 1; +X} +X +Xvoid +Xmergebitset(ss1, ss2, nbits) +X bitset ss1, ss2; +X int nbits; +X{ +X int i; +X +X for (i = NBYTES(nbits); --i >= 0; ) +X *ss1++ |= *ss2++; +X} +EOF +fi +if test -s 'src/configmac.c' +then echo '*** I will not over-write existing file src/configmac.c' +else +echo 'x - src/configmac.c' +sed 's/^X//' > 'src/configmac.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Configuration using STDWIN on the Mac (THINK_C or MPW) */ +X +X#ifdef THINK_C +X#define USE_STDWIN +X#endif +X +X#ifdef USE_STDWIN +X#include "stdwin.h" +X#endif +X +Xvoid +Xinitargs(p_argc, p_argv) +X int *p_argc; +X char ***p_argv; +X{ +X#ifdef USE_STDWIN +X +X#ifdef THINK_C_3_0 +X wsetstdio(1); +X#else +X /* This printf() statement is really needed only +X to initialize THINK C 4.0's stdio: */ +X printf( +X"Python 4.0, Copyright 1990 Stichting Mathematisch Centrum, Amsterdam\n"); +X#endif +X +X wargs(p_argc, p_argv); +X#endif +X} +X +Xvoid +Xinitcalls() +X{ +X} +X +Xvoid +Xdonecalls() +X{ +X#ifdef USE_STDWIN +X wdone(); +X#endif +X} +X +X#ifndef PYTHONPATH +X/* On the Mac, the search path is a space-separated list of directories */ +X#define PYTHONPATH ": :lib :lib:stdwin :lib:mac :lib:demo" +X#endif +X +Xchar * +Xgetpythonpath() +X{ +X return PYTHONPATH; +X} +X +X +X/* Table of built-in modules. +X These are initialized when first imported. */ +X +X/* Standard modules */ +Xextern void inittime(); +Xextern void initmath(); +Xextern void initregexp(); +X +X/* Mac-specific modules */ +Xextern void initmac(); +X#ifdef USE_STDWIN +Xextern void initstdwin(); +X#endif +X +Xstruct { +X char *name; +X void (*initfunc)(); +X} inittab[] = { +X /* Standard modules */ +X {"time", inittime}, +X {"math", initmath}, +X {"regexp", initregexp}, +X +X /* Mac-specific modules */ +X {"mac", initmac}, +X#ifdef USE_STDWIN +X {"stdwin", initstdwin}, +X#endif +X {0, 0} /* Sentinel */ +X}; +EOF +fi +if test -s 'src/fgetsintr.c' +then echo '*** I will not over-write existing file src/fgetsintr.c' +else +echo 'x - src/fgetsintr.c' +sed 's/^X//' > 'src/fgetsintr.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Interruptable version of fgets(). +X Return < 0 for interrupted, 1 for EOF, 0 for valid input. */ +X +X/* XXX This uses longjmp() from a signal out of fgets(). +X Should use read() instead?! */ +X +X#include "pgenheaders.h" +X +X#include <signal.h> +X#include <setjmp.h> +X +X#include "errcode.h" +X#include "sigtype.h" +X#include "fgetsintr.h" +X +X#ifndef AMOEBA +X#define sig_block() /*empty*/ +X#define sig_unblock() /*empty*/ +X#endif +X +Xstatic jmp_buf jback; +X +Xstatic void catcher PROTO((int)); +X +Xstatic void +Xcatcher(sig) +X int sig; +X{ +X longjmp(jback, 1); +X} +X +Xint +Xfgets_intr(buf, size, fp) +X char *buf; +X int size; +X FILE *fp; +X{ +X int ret; +X SIGTYPE (*sigsave)(); +X +X if (setjmp(jback)) { +X clearerr(fp); +X signal(SIGINT, sigsave); +X#ifdef THINK_C_3_0 +X Set_Echo(1); +X#endif +X return E_INTR; +X } +X +X /* The casts to (SIGTYPE(*)()) are needed by THINK_C only */ +X +X sigsave = signal(SIGINT, (SIGTYPE(*)()) SIG_IGN); +X if (sigsave != (SIGTYPE(*)()) SIG_IGN) +X signal(SIGINT, (SIGTYPE(*)()) catcher); +X +X#ifndef THINK_C +X if (intrcheck()) +X ret = E_INTR; +X else +X#endif +X { +X sig_block(); +X ret = (fgets(buf, size, fp) == NULL) ? E_EOF : E_OK; +X sig_unblock(); +X } +X +X if (sigsave != (SIGTYPE(*)()) SIG_IGN) +X signal(SIGINT, (SIGTYPE(*)()) sigsave); +X return ret; +X} +EOF +fi +if test -s 'src/getcwd.c' +then echo '*** I will not over-write existing file src/getcwd.c' +else +echo 'x - src/getcwd.c' +sed 's/^X//' > 'src/getcwd.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Two PD getcwd() implementations. +X Author: Guido van Rossum, CWI Amsterdam, Jan 1991, <[email protected]>. */ +X +X/* #define NO_GETWD /* Turn this on to popen pwd instead of calling getwd() */ +X +X#include <stdio.h> +X#include <errno.h> +X +Xextern int errno; +X +X#ifndef NO_GETWD +X +X/* Default: Version for BSD systems -- use getwd() */ +X +X#include "sys/param.h" +X +Xextern char *getwd(); +X +Xchar * +Xgetcwd(buf, size) +X char *buf; +X int size; +X{ +X char localbuf[MAXPATHLEN+1]; +X char *ret; +X +X if (size <= 0) { +X errno = EINVAL; +X return NULL; +X } +X ret = getwd(localbuf); +X if (ret != NULL && strlen(localbuf) >= size) { +X errno = ERANGE; +X return NULL; +X } +X if (ret == NULL) { +X errno = EACCES; /* Most likely error */ +X return NULL; +X } +X strncpy(buf, localbuf, size); +X return buf; +X} +X +X#else +X +X/* NO_GETWD defined: Version for backward UNIXes -- popen /bin/pwd */ +X +X#define PWD_CMD "/bin/pwd" +X +Xchar * +Xgetcwd(buf, size) +X char *buf; +X int size; +X{ +X FILE *fp; +X char *p; +X int sts; +X if (size <= 0) { +X errno = EINVAL; +X return NULL; +X } +X if ((fp = popen(PWD_CMD, "r")) == NULL) +X return NULL; +X if (fgets(buf, size, fp) == NULL || (sts = pclose(fp)) != 0) { +X errno = EACCES; /* Most likely error */ +X return NULL; +X } +X for (p = buf; *p != '\n'; p++) { +X if (*p == '\0') { +X errno = ERANGE; +X return NULL; +X } +X } +X *p = '\0'; +X return buf; +X} +X +X#endif +EOF +fi +if test -s 'src/graminit.h' +then echo '*** I will not over-write existing file src/graminit.h' +else +echo 'x - src/graminit.h' +sed 's/^X//' > 'src/graminit.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X#define single_input 256 +X#define file_input 257 +X#define expr_input 258 +X#define eval_input 259 +X#define funcdef 260 +X#define parameters 261 +X#define fplist 262 +X#define fpdef 263 +X#define stmt 264 +X#define simple_stmt 265 +X#define expr_stmt 266 +X#define print_stmt 267 +X#define del_stmt 268 +X#define pass_stmt 269 +X#define flow_stmt 270 +X#define break_stmt 271 +X#define return_stmt 272 +X#define raise_stmt 273 +X#define import_stmt 274 +X#define compound_stmt 275 +X#define if_stmt 276 +X#define while_stmt 277 +X#define for_stmt 278 +X#define try_stmt 279 +X#define except_clause 280 +X#define suite 281 +X#define test 282 +X#define and_test 283 +X#define not_test 284 +X#define comparison 285 +X#define comp_op 286 +X#define expr 287 +X#define term 288 +X#define factor 289 +X#define atom 290 +X#define trailer 291 +X#define subscript 292 +X#define exprlist 293 +X#define testlist 294 +X#define classdef 295 +X#define baselist 296 +X#define arguments 297 +EOF +fi +if test -s 'src/listnode.c' +then echo '*** I will not over-write existing file src/listnode.c' +else +echo 'x - src/listnode.c' +sed 's/^X//' > 'src/listnode.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* List a node on a file */ +X +X#include "pgenheaders.h" +X#include "token.h" +X#include "node.h" +X +X/* Forward */ +Xstatic void list1node PROTO((FILE *, node *)); +X +Xvoid +Xlisttree(n) +X node *n; +X{ +X listnode(stdout, n); +X} +X +Xstatic int level, atbol; +X +Xvoid +Xlistnode(fp, n) +X FILE *fp; +X node *n; +X{ +X level = 0; +X atbol = 1; +X list1node(fp, n); +X} +X +Xstatic void +Xlist1node(fp, n) +X FILE *fp; +X node *n; +X{ +X if (n == 0) +X return; +X if (ISNONTERMINAL(TYPE(n))) { +X int i; +X for (i = 0; i < NCH(n); i++) +X list1node(fp, CHILD(n, i)); +X } +X else if (ISTERMINAL(TYPE(n))) { +X switch (TYPE(n)) { +X case INDENT: +X ++level; +X break; +X case DEDENT: +X --level; +X break; +X default: +X if (atbol) { +X int i; +X for (i = 0; i < level; ++i) +X fprintf(fp, "\t"); +X atbol = 0; +X } +X if (TYPE(n) == NEWLINE) { +X if (STR(n) != NULL) +X fprintf(fp, "%s", STR(n)); +X fprintf(fp, "\n"); +X atbol = 1; +X } +X else +X fprintf(fp, "%s ", STR(n)); +X break; +X } +X } +X else +X fprintf(fp, "? "); +X} +EOF +fi +if test -s 'src/listobject.h' +then echo '*** I will not over-write existing file src/listobject.h' +else +echo 'x - src/listobject.h' +sed 's/^X//' > 'src/listobject.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* List object interface */ +X +X/* +X123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 +X +XAnother generally useful object type is an list of object pointers. +XThis is a mutable type: the list items can be changed, and items can be +Xadded or removed. Out-of-range indices or non-list objects are ignored. +X +X*** WARNING *** setlistitem does not increment the new item's reference +Xcount, but does decrement the reference count of the item it replaces, +Xif not nil. It does *decrement* the reference count if it is *not* +Xinserted in the list. Similarly, getlistitem does not increment the +Xreturned item's reference count. +X*/ +X +Xtypedef struct { +X OB_VARHEAD +X object **ob_item; +X} listobject; +X +Xextern typeobject Listtype; +X +X#define is_listobject(op) ((op)->ob_type == &Listtype) +X +Xextern object *newlistobject PROTO((int size)); +Xextern int getlistsize PROTO((object *)); +Xextern object *getlistitem PROTO((object *, int)); +Xextern int setlistitem PROTO((object *, int, object *)); +Xextern int inslistitem PROTO((object *, int, object *)); +Xextern int addlistitem PROTO((object *, object *)); +Xextern int sortlist PROTO((object *)); +X +X/* Macro, trading safety for speed */ +X#define GETLISTITEM(op, i) ((op)->ob_item[i]) +EOF +fi +if test -s 'src/node.c' +then echo '*** I will not over-write existing file src/node.c' +else +echo 'x - src/node.c' +sed 's/^X//' > 'src/node.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Parse tree node implementation */ +X +X#include "pgenheaders.h" +X#include "node.h" +X +Xnode * +Xnewtree(type) +X int type; +X{ +X node *n = NEW(node, 1); +X if (n == NULL) +X return NULL; +X n->n_type = type; +X n->n_str = NULL; +X n->n_lineno = 0; +X n->n_nchildren = 0; +X n->n_child = NULL; +X return n; +X} +X +X#define XXX 3 /* Node alignment factor to speed up realloc */ +X#define XXXROUNDUP(n) ((n) == 1 ? 1 : ((n) + XXX - 1) / XXX * XXX) +X +Xnode * +Xaddchild(n1, type, str, lineno) +X register node *n1; +X int type; +X char *str; +X int lineno; +X{ +X register int nch = n1->n_nchildren; +X register int nch1 = nch+1; +X register node *n; +X if (XXXROUNDUP(nch) < nch1) { +X n = n1->n_child; +X nch1 = XXXROUNDUP(nch1); +X RESIZE(n, node, nch1); +X if (n == NULL) +X return NULL; +X n1->n_child = n; +X } +X n = &n1->n_child[n1->n_nchildren++]; +X n->n_type = type; +X n->n_str = str; +X n->n_lineno = lineno; +X n->n_nchildren = 0; +X n->n_child = NULL; +X return n; +X} +X +X/* Forward */ +Xstatic void freechildren PROTO((node *)); +X +X +Xvoid +Xfreetree(n) +X node *n; +X{ +X if (n != NULL) { +X freechildren(n); +X DEL(n); +X } +X} +X +Xstatic void +Xfreechildren(n) +X node *n; +X{ +X int i; +X for (i = NCH(n); --i >= 0; ) +X freechildren(CHILD(n, i)); +X if (n->n_child != NULL) +X DEL(n->n_child); +X if (STR(n) != NULL) +X DEL(STR(n)); +X} +EOF +fi +if test -s 'src/stringobject.h' +then echo '*** I will not over-write existing file src/stringobject.h' +else +echo 'x - src/stringobject.h' +sed 's/^X//' > 'src/stringobject.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* String object interface */ +X +X/* +X123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 +X +XType stringobject represents a character string. An extra zero byte is +Xreserved at the end to ensure it is zero-terminated, but a size is +Xpresent so strings with null bytes in them can be represented. This +Xis an immutable object type. +X +XThere are functions to create new string objects, to test +Xan object for string-ness, and to get the +Xstring value. The latter function returns a null pointer +Xif the object is not of the proper type. +XThere is a variant that takes an explicit size as well as a +Xvariant that assumes a zero-terminated string. Note that none of the +Xfunctions should be applied to nil objects. +X*/ +X +X/* NB The type is revealed here only because it is used in dictobject.c */ +X +Xtypedef struct { +X OB_VARHEAD +X char ob_sval[1]; +X} stringobject; +X +Xextern typeobject Stringtype; +X +X#define is_stringobject(op) ((op)->ob_type == &Stringtype) +X +Xextern object *newsizedstringobject PROTO((char *, int)); +Xextern object *newstringobject PROTO((char *)); +Xextern unsigned int getstringsize PROTO((object *)); +Xextern char *getstringvalue PROTO((object *)); +Xextern void joinstring PROTO((object **, object *)); +Xextern int resizestring PROTO((object **, int)); +X +X/* Macro, trading safety for speed */ +X#define GETSTRINGVALUE(op) ((op)->ob_sval) +EOF +fi +if test -s 'src/structmember.h' +then echo '*** I will not over-write existing file src/structmember.h' +else +echo 'x - src/structmember.h' +sed 's/^X//' > 'src/structmember.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Interface to map C struct members to Python object attributes */ +X +X/* The offsetof() macro calculates the offset of a structure member +X in its structure. Unfortunately this cannot be written down +X portably, hence it is provided by a Standard C header file. +X For pre-Standard C compilers, here is a version that usually works +X (but watch out!): */ +X +X#ifndef offsetof +X#define offsetof(type, member) ( (int) & ((type*)0) -> member ) +X#endif +X +X/* An array of memberlist structures defines the name, type and offset +X of selected members of a C structure. These can be read by +X getmember() and set by setmember() (except if their READONLY flag +X is set). The array must be terminated with an entry whose name +X pointer is NULL. */ +X +Xstruct memberlist { +X char *name; +X int type; +X int offset; +X int readonly; +X}; +X +X/* Types */ +X#define T_SHORT 0 +X#define T_INT 1 +X#define T_LONG 2 +X#define T_FLOAT 3 +X#define T_DOUBLE 4 +X#define T_STRING 5 +X#define T_OBJECT 6 +X +X/* Readonly flag */ +X#define READONLY 1 +X#define RO READONLY /* Shorthand */ +X +Xobject *getmember PROTO((char *, struct memberlist *, char *)); +Xint setmember PROTO((char *, struct memberlist *, char *, object *)); +EOF +fi +if test -s 'src/tokenizer.h' +then echo '*** I will not over-write existing file src/tokenizer.h' +else +echo 'x - src/tokenizer.h' +sed 's/^X//' > 'src/tokenizer.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Tokenizer interface */ +X +X#include "token.h" /* For token types */ +X +X#define MAXINDENT 100 /* Max indentation level */ +X +X/* Tokenizer state */ +Xstruct tok_state { +X /* Input state; buf <= cur <= inp <= end */ +X /* NB an entire token must fit in the buffer */ +X char *buf; /* Input buffer */ +X char *cur; /* Next character in buffer */ +X char *inp; /* End of data in buffer */ +X char *end; /* End of input buffer */ +X int done; /* 0 normally, 1 at EOF, -1 after error */ +X FILE *fp; /* Rest of input; NULL if tokenizing a string */ +X int tabsize; /* Tab spacing */ +X int indent; /* Current indentation index */ +X int indstack[MAXINDENT]; /* Stack of indents */ +X int atbol; /* Nonzero if at begin of new line */ +X int pendin; /* Pending indents (if > 0) or dedents (if < 0) */ +X char *prompt, *nextprompt; /* For interactive prompting */ +X int lineno; /* Current line number */ +X}; +X +Xextern struct tok_state *tok_setups PROTO((char *)); +Xextern struct tok_state *tok_setupf PROTO((FILE *, char *ps1, char *ps2)); +Xextern void tok_free PROTO((struct tok_state *)); +Xextern int tok_get PROTO((struct tok_state *, char **, char **)); +EOF +fi +if test -s 'src/tupleobject.h' +then echo '*** I will not over-write existing file src/tupleobject.h' +else +echo 'x - src/tupleobject.h' +sed 's/^X//' > 'src/tupleobject.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Tuple object interface */ +X +X/* +X123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 +X +XAnother generally useful object type is an tuple of object pointers. +XThis is a mutable type: the tuple items can be changed (but not their +Xnumber). Out-of-range indices or non-tuple objects are ignored. +X +X*** WARNING *** settupleitem does not increment the new item's reference +Xcount, but does decrement the reference count of the item it replaces, +Xif not nil. It does *decrement* the reference count if it is *not* +Xinserted in the tuple. Similarly, gettupleitem does not increment the +Xreturned item's reference count. +X*/ +X +Xtypedef struct { +X OB_VARHEAD +X object *ob_item[1]; +X} tupleobject; +X +Xextern typeobject Tupletype; +X +X#define is_tupleobject(op) ((op)->ob_type == &Tupletype) +X +Xextern object *newtupleobject PROTO((int size)); +Xextern int gettuplesize PROTO((object *)); +Xextern object *gettupleitem PROTO((object *, int)); +Xextern int settupleitem PROTO((object *, int, object *)); +X +X/* Macro, trading safety for speed */ +X#define GETTUPLEITEM(op, i) ((op)->ob_item[i]) +EOF +fi +echo 'Part 18 out of 21 of pack.out complete.' +exit 0 diff --git a/shar/python-0.9.1-19-21.shar b/shar/python-0.9.1-19-21.shar new file mode 100644 index 0000000..c52113b --- /dev/null +++ b/shar/python-0.9.1-19-21.shar @@ -0,0 +1,1997 @@ +: This is a shell archive. +: Extract with 'sh this_file'. +: +: Extract part 01 first since it makes all directories +echo 'Start of pack.out, part 19 out of 21:' +if test -s 'demo/scripts/xxci.py' +then echo '*** I will not over-write existing file demo/scripts/xxci.py' +else +echo 'x - demo/scripts/xxci.py' +sed 's/^X//' > 'demo/scripts/xxci.py' << 'EOF' +X#! /ufs/guido/bin/sgi/python +X +X# xxci +X# +X# check in files for which rcsdiff returns nonzero exit status +X +Ximport sys +Ximport posix +Ximport stat +Ximport path +Ximport commands +X +XMAXSIZE = 200*1024 # Files this big must be binaries and are skipped. +X +Xdef getargs(): +X args = sys.argv[1:] +X if args: +X return args +X print 'No arguments, checking almost *' +X for file in posix.listdir('.'): +X if not skipfile(file): +X args.append(file) +X if not args: +X print 'Nothing to do -- exit 1' +X sys.exit(1) +X args.sort() +X return args +X +Xbadnames = ['tags', 'xyzzy'] +Xbadprefixes = ['.', ',', '@', '#', 'o.'] +Xbadsuffixes = \ +X ['~', '.a', '.o', '.old', '.bak', '.orig', '.new', '.prev', '.not'] +X# XXX Should generalize even more to use fnmatch! +X +Xdef skipfile(file): +X if file in badnames or \ +X badprefix(file) or badsuffix(file) or \ +X path.islink(file) or path.isdir(file): +X return 1 +X # Skip huge files -- probably binaries. +X try: +X st = posix.stat(file) +X except posix.error: +X return 1 # Doesn't exist -- skip it +X return st[stat.ST_SIZE] >= MAXSIZE +X +Xdef badprefix(file): +X for bad in badprefixes: +X if file[:len(bad)] = bad: return 1 +X return 0 +X +Xdef badsuffix(file): +X for bad in badsuffixes: +X if file[-len(bad):] = bad: return 1 +X return 0 +X +Xdef go(args): +X for file in args: +X print file + ':' +X if run('rcsdiff -c', file): +X if askyesno('Check in ' + file + ' ? '): +X sts = run('rcs -l', file) # ignored +X # can't use run() here because it's interactive +X sts = posix.system('ci -l ' + file) +X +Xdef run(cmd, file): +X sts, output = commands.getstatusoutput(cmd + commands.mkarg(file)) +X if sts: +X print output +X print 'Exit status', sts +X return sts +X +Xdef askyesno(prompt): +X s = raw_input(prompt) +X return s in ['y', 'yes'] +X +Xgo(getargs()) +EOF +chmod +x 'demo/scripts/xxci.py' +fi +if test -s 'demo/sgi/gl_panel/apanel/apanel.s' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/apanel/apanel.s' +else +echo 'x - demo/sgi/gl_panel/apanel/apanel.s' +sed 's/^X//' > 'demo/sgi/gl_panel/apanel/apanel.s' << 'EOF' +X;;; This file was automatically generated by the panel editor. +X;;; If you read it into gnu emacs, it will automagically format itself. +X +X(panel (prop help creator:user-panel-help) +X(prop user-panel #t) +X(label "Audio Control Panel") +X(x 395) +X(y 69) +X(al (pnl_filled_vslider (name "outputgain") +X(prop help creator:user-act-help) +X(label "output gain") +X(x 6.5) +X(y 0.75) +X(w 0.4) +X(h 4.35) +X(val 0.329) +X(labeltype 13) +X(downfunc move-then-resize) +X) +X(pnl_frame (prop help creator:user-frame-help) +X(x 0.25) +X(y 2.75) +X(w 5.1) +X(h 2.3) +X(downfunc move-then-resize) +X(al (pnl_filled_hslider (name "recordsize") +X(prop help creator:user-act-help) +X(label "recording length") +X(x -0.75) +X(w 3.3) +X(h 0.4) +X(val 0.1) +X(labeltype 11) +X(downfunc move-then-resize) +X) +X(pnl_label (prop help creator:user-act-help) +X(label "(max 10 seconds)") +X(x -0.75) +X(y -0.75) +X(downfunc move-then-resize) +X) +X(pnl_wide_button (name "recordbutton") +X(prop help creator:user-act-help) +X(label "record from microphone...") +X(x -0.75) +X(y 0.75) +X(w 4.7) +X(downfunc move-then-resize) +X) +X) +X) +X(pnl_wide_button (name "playbackbutton") +X(prop help creator:user-act-help) +X(label "playback to speaker") +X(x 0.25) +X(y 2) +X(w 5.15) +X(downfunc move-then-resize) +X) +X(pnl_wide_button (name "quitbutton") +X(prop help creator:user-act-help) +X(label "quit") +X(x 0.25) +X(y 0.25) +X(w 1.75) +X(downfunc move-then-resize) +X) +X) +X) +X;;; Local Variables: +X;;; mode: scheme +X;;; eval: (save-excursion (goto-char (point-min)) (kill-line 3)) +X;;; eval: (save-excursion (goto-char (point-min)) (replace-regexp "[ \n]*)" ")")) +X;;; eval: (indent-region (point-min) (point-max) nil) +X;;; eval: (progn (kill-line -3) (delete-backward-char 1) (save-buffer)) +X;;; End: +EOF +fi +if test -s 'demo/sgi/gl_panel/flying/light.s' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/flying/light.s' +else +echo 'x - demo/sgi/gl_panel/flying/light.s' +sed 's/^X//' > 'demo/sgi/gl_panel/flying/light.s' << 'EOF' +X;;; This file was automatically generated by the panel editor. +X;;; If you read it into gnu emacs, it will automagically format itself. +X +X(panel (prop help creator:user-panel-help) +X(prop user-panel #t) +X(label "Light Sources") +X(al (pnl_hslider (name "X") +X(prop help creator:user-act-help) +X(label "x") +X(y 4) +X(w 3.3) +X(h 0.4) +X(val 0.50) +X(labeltype 0) +X(downfunc move-then-resize) +X) +X(pnl_hslider (name "Y") +X(prop help creator:user-act-help) +X(label "y") +X(y 3.5) +X(w 3.3) +X(h 0.4) +X(val 0.50) +X(labeltype 0) +X(downfunc move-then-resize) +X) +X(pnl_hslider (name "Z") +X(prop help creator:user-act-help) +X(label "z") +X(y 3) +X(w 3.3) +X(h 0.4) +X(val 0.50) +X(labeltype 0) +X(downfunc move-then-resize) +X) +X(pnl_radio_button (name "light2") +X(prop help creator:user-act-help) +X(label "light 2") +X(x 5) +X(y 4) +X(h 0.36) +X(downfunc move-then-resize) +X) +X(pnl_radio_button (name "light1") +X(prop help creator:user-act-help) +X(label "light 1") +X(x 5) +X(y 4.5) +X(h 0.36) +X(downfunc move-then-resize) +X) +X(pnl_toggle_button (name "local") +X(prop help creator:user-act-help) +X(label "local") +X(x 5) +X(y 2.75) +X(downfunc move-then-resize) +X) +X(pnl_filled_hslider (name "B") +X(prop help creator:user-act-help) +X(label "B") +X(w 3.3) +X(h 0.4) +X(labeltype 0) +X(downfunc move-then-resize) +X) +X(pnl_filled_hslider (name "G") +X(prop help creator:user-act-help) +X(label "G") +X(y 0.5) +X(w 3.3) +X(h 0.4) +X(labeltype 0) +X(downfunc move-then-resize) +X) +X(pnl_filled_hslider (name "R") +X(prop help creator:user-act-help) +X(label "R") +X(y 1) +X(w 3.3) +X(h 0.4) +X(labeltype 0) +X(downfunc move-then-resize) +X) +X) +X) +X;;; Local Variables: +X;;; mode: scheme +X;;; eval: (save-excursion (goto-char (point-min)) (kill-line 3)) +X;;; eval: (save-excursion (goto-char (point-min)) (replace-regexp "[ \n]*)" ")")) +X;;; eval: (indent-region (point-min) (point-max) nil) +X;;; eval: (progn (kill-line -3) (delete-backward-char 1) (save-buffer)) +X;;; End: +EOF +fi +if test -s 'demo/sgi/gl_panel/flying/panel.s' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/flying/panel.s' +else +echo 'x - demo/sgi/gl_panel/flying/panel.s' +sed 's/^X//' > 'demo/sgi/gl_panel/flying/panel.s' << 'EOF' +X;;; This file was automatically generated by the panel editor. +X;;; If you read it into gnu emacs, it will automagically format itself. +X +X(panel (prop help creator:user-panel-help) +X(prop user-panel #t) +X(label "Panel Control") +X(x 394) +X(y 622) +X(al (pnl_radio_button (name "button4") +X(prop help creator:user-act-help) +X(y 2.5) +X(h 0.36) +X(downfunc move-then-resize) +X) +X(pnl_radio_button (name "button3") +X(prop help creator:user-act-help) +X(y 3) +X(h 0.36) +X(downfunc move-then-resize) +X) +X(pnl_radio_button (name "button2") +X(prop help creator:user-act-help) +X(y 3.5) +X(h 0.36) +X(downfunc move-then-resize) +X) +X(pnl_radio_button (name "button1") +X(prop help creator:user-act-help) +X(y 4) +X(h 0.36) +X(downfunc move-then-resize) +X) +X(pnl_wide_button (name "title1") +X(prop help creator:user-act-help) +X(x 0.75) +X(y 4.75) +X(w 2.44) +X(downfunc move-then-resize) +X) +X(pnl_wide_button (name "title2") +X(prop help creator:user-act-help) +X(x 3.5) +X(y 4.75) +X(w 2.44) +X(downfunc move-then-resize) +X) +X(pnl_wide_button (name "title3") +X(prop help creator:user-act-help) +X(x 6.25) +X(y 4.75) +X(w 2.44) +X(downfunc move-then-resize) +X) +X(pnl_wide_button (name "title4") +X(prop help creator:user-act-help) +X(x 9) +X(y 4.75) +X(w 2.44) +X(downfunc move-then-resize) +X) +X(pnl_button (name "root") +X(prop help creator:user-act-help) +X(label "R") +X(y 4.75) +X(labeltype 16) +X(downfunc move-then-resize) +X) +X) +X) +X;;; Local Variables: +X;;; mode: scheme +X;;; eval: (save-excursion (goto-char (point-min)) (kill-line 3)) +X;;; eval: (save-excursion (goto-char (point-min)) (replace-regexp "[ \n]*)" ")")) +X;;; eval: (indent-region (point-min) (point-max) nil) +X;;; eval: (progn (kill-line -3) (delete-backward-char 1) (save-buffer)) +X;;; End: +EOF +fi +if test -s 'lib/Abstract.py' +then echo '*** I will not over-write existing file lib/Abstract.py' +else +echo 'x - lib/Abstract.py' +sed 's/^X//' > 'lib/Abstract.py' << 'EOF' +X# Abstract classes for parents and children. +X# +X# Do not use as base class -- this is for documentation only. +X# +X# Note that the tree must be built top down (create the parent, +X# then add the children). +X# +X# Also note that the creation methods are not standardized -- +X# these have extra parameters dependent on the widget type. +X# For historical reasons, button creation methods are called +X# define() while split creation methods are called create(). +X +Xclass AbstractParent(): +X # +X # Upcalls from child to parent +X # +X def addchild(self, child): unimpl() +X def delchild(self, child): unimpl() +X # +X def need_mouse(self, child): unimpl() +X def no_mouse(self, child): unimpl() +X # +X def need_timer(self, child): unimpl() +X def no_timer(self, child): unimpl() +X # +X # XXX need_kbd, no_kbd; focus??? +X # +X def begindrawing(self): return unimpl() +X def beginmeasuring(self): return unimpl() +X # +X def change(self, area): unimpl() +X def scroll(self, (area, (dh, dv))): unimpl() +X def settimer(self, itimer): unimpl() +X +Xclass AbstractChild(): +X # +X # Downcalls from parent to child +X # +X def destroy(self): unimpl() +X # +X def minsize(self, m): return unimpl() +X def getbounds(self): return unimpl() +X def setbounds(self, bounds): unimpl() +X def draw(self, (d, area)): unimpl() +X # +X # Downcalls only made after certain upcalls +X # +X def mouse_down(self, detail): unimpl() +X def mouse_move(self, detail): unimpl() +X def mouse_up(self, detail): unimpl() +X # +X def timer(self): unimpl() +X +X# A "Split" is a child that manages one or more children. +X# (This terminology is due to DEC SRC, except for CSplits.) +X# A child of a split may be another split, a button, a slider, etc. +X# Certain upcalls and downcalls can be handled transparently, but +X# for others (e.g., all geometry related calls) this is not possible. +X +Xclass AbstractSplit() = AbstractChild(), AbstractParent(): +X pass +EOF +fi +if test -s 'lib/StripChart.py' +then echo '*** I will not over-write existing file lib/StripChart.py' +else +echo 'x - lib/StripChart.py' +sed 's/^X//' > 'lib/StripChart.py' << 'EOF' +X# Module 'StripChart' +X +Ximport rect +Xfrom Buttons import LabelAppearance, NoReactivity +X +X# A StripChart doesn't really look like a label but it needs a base class. +X# LabelAppearance allows it to be disabled and hilited. +X +Xclass StripChart() = LabelAppearance(), NoReactivity(): +X # +X def define(self, (parent, scale)): +X self.parent = parent +X parent.addchild(self) +X self.init_appearance() +X self.init_reactivity() +X self.ydata = [] +X self.scale = scale +X self.resetbounds() +X return self +X # +X def setbounds(self, bounds): +X LabelAppearance.setbounds(self, bounds) +X self.resetbounds() +X # +X def resetbounds(self): +X (left, top), (right, bottom) = self.bounds +X self.width = right-left +X self.height = bottom-top +X excess = len(self.ydata) - self.width +X if excess > 0: +X del self.ydata[:excess] +X elif excess < 0: +X while len(self.ydata) < self.width: +X self.ydata.insert(0, 0) +X # +X def append(self, y): +X self.ydata.append(y) +X excess = len(self.ydata) - self.width +X if excess > 0: +X del self.ydata[:excess] +X if self.bounds <> rect.empty: +X self.parent.scroll(self.bounds, (-excess, 0)) +X if self.bounds <> rect.empty: +X (left, top), (right, bottom) = self.bounds +X i = len(self.ydata) +X area = (left+i-1, top), (left+i, bottom) +X self.draw(self.parent.begindrawing(), area) +X # +X def draw(self, (d, area)): +X area = rect.intersect(area, self.bounds) +X if area = rect.empty: +X print 'mt' +X return +X d.cliprect(area) +X d.erase(self.bounds) +X (a_left, a_top), (a_right, a_bottom) = area +X (left, top), (right, bottom) = self.bounds +X height = bottom - top +X i1 = a_left - left +X i2 = a_right - left +X for i in range(max(0, i1), min(len(self.ydata), i2)): +X split = bottom-self.ydata[i]*height/self.scale +X d.paint((left+i, split), (left+i+1, bottom)) +X if not self.enabled: +X self.flipenable(d) +X if self.hilited: +X self.fliphilite(d) +X d.noclip() +EOF +fi +if test -s 'lib/cmp.py' +then echo '*** I will not over-write existing file lib/cmp.py' +else +echo 'x - lib/cmp.py' +sed 's/^X//' > 'lib/cmp.py' << 'EOF' +X# Module 'cmp' +X +X# Efficiently compare files, boolean outcome only (equal / not equal). +X +X# Tricks (used in this order): +X# - Files with identical type, size & mtime are assumed to be clones +X# - Files with different type or size cannot be identical +X# - We keep a cache of outcomes of earlier comparisons +X# - We don't fork a process to run 'cmp' but read the files ourselves +X +Ximport posix +X +Xcache = {} +X +Xdef cmp(f1, f2): # Compare two files, use the cache if possible. +X # Return 1 for identical files, 0 for different. +X # Raise exceptions if either file could not be statted, read, etc. +X s1, s2 = sig(posix.stat(f1)), sig(posix.stat(f2)) +X if s1[0] <> 8 or s2[0] <> 8: +X # Either is a not a plain file -- always report as different +X return 0 +X if s1 = s2: +X # type, size & mtime match -- report same +X return 1 +X if s1[:2] <> s2[:2]: # Types or sizes differ, don't bother +X # types or sizes differ -- report different +X return 0 +X # same type and size -- look in the cache +X key = f1 + ' ' + f2 +X try: +X cs1, cs2, outcome = cache[key] +X # cache hit +X if s1 = cs1 and s2 = cs2: +X # cached signatures match +X return outcome +X # stale cached signature(s) +X except RuntimeError: +X # cache miss +X pass +X # really compare +X outcome = do_cmp(f1, f2) +X cache[key] = s1, s2, outcome +X return outcome +X +Xdef sig(st): # Return signature (i.e., type, size, mtime) from raw stat data +X # 0-5: st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid +X # 6-9: st_size, st_atime, st_mtime, st_ctime +X type = st[0] / 4096 +X size = st[6] +X mtime = st[8] +X return type, size, mtime +X +Xdef do_cmp(f1, f2): # Compare two files, really +X bufsize = 8096 # Could be tuned +X fp1 = open(f1, 'r') +X fp2 = open(f2, 'r') +X while 1: +X b1 = fp1.read(bufsize) +X b2 = fp2.read(bufsize) +X if b1 <> b2: return 0 +X if not b1: return 1 +EOF +fi +if test -s 'lib/commands.py' +then echo '*** I will not over-write existing file lib/commands.py' +else +echo 'x - lib/commands.py' +sed 's/^X//' > 'lib/commands.py' << 'EOF' +X# Module 'commands' +X# +X# Various tools for executing commands and looking at their output and status. +X +Ximport rand +Ximport posix +Ximport stat +Ximport path +X +X +X# Get 'ls -l' status for an object into a string +X# +Xdef getstatus(file): +X return getoutput('ls -ld' + mkarg(file)) +X +X +X# Get the output from a shell command into a string. +X# The exit status is ignored; a trailing newline is stripped. +X# Assume the command will work with ' >tempfile 2>&1' appended. +X# XXX This should use posix.popen() instead, should it exist. +X# +Xdef getoutput(cmd): +X return getstatusoutput(cmd)[1] +X +X +X# Ditto but preserving the exit status. +X# Returns a pair (sts, output) +X# +Xdef getstatusoutput(cmd): +X tmp = '/usr/tmp/wdiff' + `rand.rand()` +X sts = -1 +X try: +X sts = posix.system(cmd + ' >' + tmp + ' 2>&1') +X text = readfile(tmp) +X finally: +X altsts = posix.system('rm -f ' + tmp) +X if text[-1:] = '\n': text = text[:-1] +X return sts, text +X +X +X# Return a string containing a file's contents. +X# +Xdef readfile(fn): +X st = posix.stat(fn) +X size = st[stat.ST_SIZE] +X if not size: return '' +X try: +X fp = open(fn, 'r') +X except: +X raise posix.error, 'readfile(' + fn + '): open failed' +X try: +X return fp.read(size) +X except: +X raise posix.error, 'readfile(' + fn + '): read failed' +X +X +X# Make command argument from directory and pathname (prefix space, add quotes). +X# +Xdef mk2arg(head, x): +X return mkarg(path.cat(head, x)) +X +X +X# Make a shell command argument from a string. +X# Two strategies: enclose in single quotes if it contains none; +X# otherwis, enclose in double quotes and prefix quotable characters +X# with backslash. +X# +Xdef mkarg(x): +X if '\'' not in x: +X return ' \'' + x + '\'' +X s = ' "' +X for c in x: +X if c in '\\$"': +X s = s + '\\' +X s = s + c +X s = s + '"' +X return s +EOF +fi +if test -s 'lib/getopt.py' +then echo '*** I will not over-write existing file lib/getopt.py' +else +echo 'x - lib/getopt.py' +sed 's/^X//' > 'lib/getopt.py' << 'EOF' +X# module getopt -- Standard command line processing. +X +X# Function getopt.getopt() has a different interface but provides the +X# same functionality as the Unix getopt() function. +X +X# It has two arguments: the first should be argv[1:] (it doesn't want +X# the script name), the second the string of option letters as passed +X# to Unix getopt() (i.e., a string of allowable option letters, with +X# options requiring an argument followed by a colon). +X +X# It raises the exception getopt.error with a string argument if it +X# detects an error. +X +X# It returns two items: +X# (1) a list of pairs (option, option_argument) giving the options in +X# the order in which they were specified. (I'd use a dictionary +X# but applications may depend on option order or multiple +X# occurrences.) Boolean options have '' as option_argument. +X# (2) the list of remaining arguments (may be empty). +X +Xerror = 'getopt error' +X +Xdef getopt(args, options): +X list = [] +X while args and args[0][0] = '-' and args[0] <> '-': +X if args[0] = '--': +X args = args[1:] +X break +X optstring, args = args[0][1:], args[1:] +X while optstring <> '': +X opt, optstring = optstring[0], optstring[1:] +X if classify(opt, options): # May raise exception as well +X if optstring = '': +X if not args: +X raise error, 'option -' + opt + ' requires argument' +X optstring, args = args[0], args[1:] +X optarg, optstring = optstring, '' +X else: +X optarg = '' +X list.append('-' + opt, optarg) +X return list, args +X +Xdef classify(opt, options): # Helper to check type of option +X for i in range(len(options)): +X if opt = options[i] <> ':': +X return options[i+1:i+2] = ':' +X raise error, 'option -' + opt + ' not recognized' +EOF +fi +if test -s 'lib/rect.py' +then echo '*** I will not over-write existing file lib/rect.py' +else +echo 'x - lib/rect.py' +sed 's/^X//' > 'lib/rect.py' << 'EOF' +X# Module 'rect'. +X# +X# Operations on rectangles. +X# There is some normalization: all results return the object 'empty' +X# if their result would contain no points. +X +X +X# Exception. +X# +Xerror = 'rect.error' +X +X +X# The empty rectangle. +X# +Xempty = (0, 0), (0, 0) +X +X +X# Check if a rectangle is empty. +X# +Xdef is_empty((left, top), (right, bottom)): +X return left >= right or top >= bottom +X +X +X# Compute the intersection or two or more rectangles. +X# This works with a list or tuple argument. +X# +Xdef intersect(list): +X if not list: raise error, 'intersect called with empty list' +X if is_empty(list[0]): return empty +X (left, top), (right, bottom) = list[0] +X for rect in list[1:]: +X if is_empty(rect): +X return empty +X (l, t), (r, b) = rect +X if left < l: left = l +X if top < t: top = t +X if right > r: right = r +X if bottom > b: bottom = b +X if is_empty((left, top), (right, bottom)): +X return empty +X return (left, top), (right, bottom) +X +X +X# Compute the smallest rectangle containing all given rectangles. +X# This works with a list or tuple argument. +X# +Xdef union(list): +X (left, top), (right, bottom) = empty +X for (l, t), (r, b) in list[1:]: +X if not is_empty((l, t), (r, b)): +X if l < left: left = l +X if t < top: top = t +X if r > right: right = r +X if b > bottom: bottom = b +X res = (left, top), (right, bottom) +X if is_empty(res): +X return empty +X return res +X +X +X# Check if a point is in a rectangle. +X# +Xdef pointinrect((h, v), ((left, top), (right, bottom))): +X return left <= h < right and top <= v < bottom +X +X +X# Return a rectangle that is dh, dv inside another +X# +Xdef inset(((left, top), (right, bottom)), (dh, dv)): +X left = left + dh +X top = top + dv +X right = right - dh +X bottom = bottom - dv +X r = (left, top), (right, bottom) +X if is_empty(r): +X return empty +X else: +X return r +X +X +X# Conversions between rectangles and 'geometry tuples', +X# given as origin (h, v) and dimensions (width, height). +X# +Xdef rect2geom((left, top), (right, bottom)): +X return (left, top), (right-left, bottom-top) +X +Xdef geom2rect((h, v), (width, height)): +X return (h, v), (h+width, v+height) +EOF +fi +if test -s 'lib/selection.py' +then echo '*** I will not over-write existing file lib/selection.py' +else +echo 'x - lib/selection.py' +sed 's/^X//' > 'lib/selection.py' << 'EOF' +X# DAWKINS' BLIND WATCHMAKER -- "METHINKS IT IS LIKE A WEASEL" EXAMPLE +X# +X# Start with a random phrase. Successively: +X# Breed a next generation by copying with small mutations. +X# Choose the member of the next generation that most closely resembles +X# the target phrase to start breeding the next generation. +X# How many generations will it take before the target is reached? +X +Xfrom whrandom import random +X +X# Parameters determining the problem space +XTarget = 'methinks it is like a weasel' +XAlphabet = ' abcdefghijklmnopqrstuvwxyz' +X +X# Parameters to play with +XGenerationSize = 100 +XMutationChance = 1.0/28.0 +X +XIndexSet = range(len(Target)) # Used to speed up loops +X +Xdef choice(sequence): +X n = len(sequence) +X i = int(random() * float(n)) % n +X return sequence[i] +X +Xdef random_phrase(): +X phrase = '' +X for i in IndexSet: +X phrase = phrase + choice(Alphabet) +X return phrase +X +Xdef mutate_phrase(phrase): +X mutant = phrase +X for i in range(int(0.5 + MutationChance*float(len(phrase)))): +X i = choice(IndexSet) +X c = choice(Alphabet) +X mutant = mutant[:i] + c + mutant[i+1:] +X #print `mutant` +X return mutant +X +Xdef matching_factor(phrase): +X factor = 0 +X for i in IndexSet: +X if phrase[i] = Target[i]: factor = factor + 1 +X return factor +X +Xdef breed_generation(phrase): +X generation = [phrase] +X while len(generation) < GenerationSize: +X generation.append(mutate_phrase(phrase)) +X return generation +X +Xdef select_best(generation): +X factor, selected = -1, '' +X for phrase in generation: +X f = matching_factor(phrase) +X if f > factor: +X factor, selected = f, phrase +X return selected +X +Xdef main(): +X gen = 0 +X phrase = random_phrase() +X print gen, `phrase` +X while phrase <> Target: +X next_generation = breed_generation(phrase) +X #print next_generation +X phrase = select_best(next_generation) +X gen = gen+1 +X print gen, `phrase` +X +Xmain() +EOF +fi +if test -s 'lib/statcache.py' +then echo '*** I will not over-write existing file lib/statcache.py' +else +echo 'x - lib/statcache.py' +sed 's/^X//' > 'lib/statcache.py' << 'EOF' +X# Module 'statcache' +X# +X# Maintain a cache of file stats. +X# There are functions to reset the cache or to selectively remove items. +X +Ximport posix +Xfrom stat import * +X +X# The cache. +X# Keys are pathnames, values are `posix.stat' outcomes. +X# +Xcache = {} +X +X +X# Stat a file, possibly out of the cache. +X# +Xdef stat(path): +X if cache.has_key(path): +X return cache[path] +X cache[path] = ret = posix.stat(path) +X return ret +X +X +X# Reset the cache completely. +X# Hack: to reset a global variable, we import this module. +X# +Xdef reset(): +X import statcache +X # Check that we really imported the same module +X if cache is not statcache.cache: +X raise 'sorry, statcache identity crisis' +X statcache.cache = {} +X +X +X# Remove a given item from the cache, if it exists. +X# +Xdef forget(path): +X if cache.has_key(path): +X del cache[path] +X +X +X# Remove all pathnames with a given prefix. +X# +Xdef forget_prefix(prefix): +X n = len(prefix) +X for path in cache.keys(): +X if path[:n] = prefix: +X del cache[path] +X +X +X# Forget about a directory and all entries in it, but not about +X# entries in subdirectories. +X# +Xdef forget_dir(prefix): +X if prefix[-1:] = '/' and prefix <> '/': +X prefix = prefix[:-1] +X forget(prefix) +X if prefix[-1:] <> '/': +X prefix = prefix + '/' +X n = len(prefix) +X for path in cache.keys(): +X if path[:n] = prefix: +X rest = path[n:] +X if rest[-1:] = '/': rest = rest[:-1] +X if '/' not in rest: +X del cache[path] +X +X +X# Remove all pathnames except with a given prefix. +X# Normally used with prefix = '/' after a chdir(). +X# +Xdef forget_except_prefix(prefix): +X n = len(prefix) +X for path in cache.keys(): +X if path[:n] <> prefix: +X del cache[path] +X +X +X# Check for directory. +X# +Xdef isdir(path): +X try: +X st = stat(path) +X except posix.error: +X return 0 +X return S_ISDIR(st[ST_MODE]) +EOF +fi +if test -s 'src/allobjects.h' +then echo '*** I will not over-write existing file src/allobjects.h' +else +echo 'x - src/allobjects.h' +sed 's/^X//' > 'src/allobjects.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* "allobjects.c" -- Source for precompiled header "allobjects.h" */ +X +X#include <stdio.h> +X#include <string.h> +X +X#include "PROTO.h" +X +X#include "object.h" +X#include "objimpl.h" +X +X#include "intobject.h" +X#include "floatobject.h" +X#include "stringobject.h" +X#include "tupleobject.h" +X#include "listobject.h" +X#include "dictobject.h" +X#include "methodobject.h" +X#include "moduleobject.h" +X#include "funcobject.h" +X#include "classobject.h" +X#include "fileobject.h" +X +X#include "errors.h" +X#include "malloc.h" +X +Xextern char *strdup PROTO((const char *)); +EOF +fi +if test -s 'src/bitset.h' +then echo '*** I will not over-write existing file src/bitset.h' +else +echo 'x - src/bitset.h' +sed 's/^X//' > 'src/bitset.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Bitset interface */ +X +X#define BYTE char +X +Xtypedef BYTE *bitset; +X +Xbitset newbitset PROTO((int nbits)); +Xvoid delbitset PROTO((bitset bs)); +X/* int testbit PROTO((bitset bs, int ibit)); /* Now a macro, see below */ +Xint addbit PROTO((bitset bs, int ibit)); /* Returns 0 if already set */ +Xint samebitset PROTO((bitset bs1, bitset bs2, int nbits)); +Xvoid mergebitset PROTO((bitset bs1, bitset bs2, int nbits)); +X +X#define BITSPERBYTE (8*sizeof(BYTE)) +X#define NBYTES(nbits) (((nbits) + BITSPERBYTE - 1) / BITSPERBYTE) +X +X#define BIT2BYTE(ibit) ((ibit) / BITSPERBYTE) +X#define BIT2SHIFT(ibit) ((ibit) % BITSPERBYTE) +X#define BIT2MASK(ibit) (1 << BIT2SHIFT(ibit)) +X#define BYTE2BIT(ibyte) ((ibyte) * BITSPERBYTE) +X +X#define testbit(ss, ibit) (((ss)[BIT2BYTE(ibit)] & BIT2MASK(ibit)) != 0) +EOF +fi +if test -s 'src/cgensupport.h' +then echo '*** I will not over-write existing file src/cgensupport.h' +else +echo 'x - src/cgensupport.h' +sed 's/^X//' > 'src/cgensupport.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Definitions used by cgen output */ +X +Xtypedef char *string; +X +X#define mknewlongobject(x) newintobject(x) +X#define mknewshortobject(x) newintobject((long)x) +X#define mknewfloatobject(x) newfloatobject(x) +X +Xextern object *mknewcharobject PROTO((int c)); +X +Xextern int getiobjectarg PROTO((object *args, int nargs, int i, object **p_a)); +Xextern int getilongarg PROTO((object *args, int nargs, int i, long *p_a)); +Xextern int getishortarg PROTO((object *args, int nargs, int i, short *p_a)); +Xextern int getifloatarg PROTO((object *args, int nargs, int i, float *p_a)); +Xextern int getistringarg PROTO((object *args, int nargs, int i, string *p_a)); +EOF +fi +if test -s 'src/classobject.h' +then echo '*** I will not over-write existing file src/classobject.h' +else +echo 'x - src/classobject.h' +sed 's/^X//' > 'src/classobject.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Class object interface */ +X +X/* +XClasses are really hacked in at the last moment. +XIt should be possible to use other object types as base classes, +Xbut currently it isn't. We'll see if we can fix that later, sigh... +X*/ +X +Xextern typeobject Classtype, Classmembertype, Classmethodtype; +X +X#define is_classobject(op) ((op)->ob_type == &Classtype) +X#define is_classmemberobject(op) ((op)->ob_type == &Classmembertype) +X#define is_classmethodobject(op) ((op)->ob_type == &Classmethodtype) +X +Xextern object *newclassobject PROTO((object *, object *)); +Xextern object *newclassmemberobject PROTO((object *)); +Xextern object *newclassmethodobject PROTO((object *, object *)); +X +Xextern object *classmethodgetfunc PROTO((object *)); +Xextern object *classmethodgetself PROTO((object *)); +EOF +fi +if test -s 'src/compile.h' +then echo '*** I will not over-write existing file src/compile.h' +else +echo 'x - src/compile.h' +sed 's/^X//' > 'src/compile.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Definitions for compiled intermediate code */ +X +X +X/* An intermediate code fragment contains: +X - a string that encodes the instructions, +X - a list of the constants, +X - and a list of the names used. */ +X +Xtypedef struct { +X OB_HEAD +X stringobject *co_code; /* instruction opcodes */ +X object *co_consts; /* list of immutable constant objects */ +X object *co_names; /* list of stringobjects */ +X object *co_filename; /* string */ +X} codeobject; +X +Xextern typeobject Codetype; +X +X#define is_codeobject(op) ((op)->ob_type == &Codetype) +X +X +X/* Public interface */ +Xcodeobject *compile PROTO((struct _node *, char *)); +EOF +fi +if test -s 'src/dictobject.h' +then echo '*** I will not over-write existing file src/dictobject.h' +else +echo 'x - src/dictobject.h' +sed 's/^X//' > 'src/dictobject.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* +XDictionary object type -- mapping from char * to object. +XNB: the key is given as a char *, not as a stringobject. +XThese functions set errno for errors. Functions dictremove() and +Xdictinsert() return nonzero for errors, getdictsize() returns -1, +Xthe others NULL. A successful call to dictinsert() calls INCREF() +Xfor the inserted item. +X*/ +X +Xextern typeobject Dicttype; +X +X#define is_dictobject(op) ((op)->ob_type == &Dicttype) +X +Xextern object *newdictobject PROTO((void)); +Xextern object *dictlookup PROTO((object *dp, char *key)); +Xextern int dictinsert PROTO((object *dp, char *key, object *item)); +Xextern int dictremove PROTO((object *dp, char *key)); +Xextern int getdictsize PROTO((object *dp)); +Xextern char *getdictkey PROTO((object *dp, int i)); +Xextern object *getdictkeys PROTO((object *dp)); +EOF +fi +if test -s 'src/errors.h' +then echo '*** I will not over-write existing file src/errors.h' +else +echo 'x - src/errors.h' +sed 's/^X//' > 'src/errors.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Error handling definitions */ +X +Xvoid err_set PROTO((object *)); +Xvoid err_setval PROTO((object *, object *)); +Xvoid err_setstr PROTO((object *, char *)); +Xint err_occurred PROTO((void)); +Xvoid err_get PROTO((object **, object **)); +Xvoid err_clear PROTO((void)); +X +X/* Predefined exceptions */ +X +Xextern object *RuntimeError; +Xextern object *EOFError; +Xextern object *TypeError; +Xextern object *MemoryError; +Xextern object *NameError; +Xextern object *SystemError; +Xextern object *KeyboardInterrupt; +X +X/* Some more planned for the future */ +X +X#define IndexError RuntimeError +X#define KeyError RuntimeError +X#define ZeroDivisionError RuntimeError +X#define OverflowError RuntimeError +X +X/* Convenience functions */ +X +Xextern int err_badarg PROTO((void)); +Xextern object *err_nomem PROTO((void)); +Xextern object *err_errno PROTO((object *)); +Xextern void err_input PROTO((int)); +X +Xextern void err_badcall PROTO((void)); +EOF +fi +if test -s 'src/grammar1.c' +then echo '*** I will not over-write existing file src/grammar1.c' +else +echo 'x - src/grammar1.c' +sed 's/^X//' > 'src/grammar1.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Grammar subroutines needed by parser */ +X +X#include "pgenheaders.h" +X#include "assert.h" +X#include "grammar.h" +X#include "token.h" +X +X/* Return the DFA for the given type */ +X +Xdfa * +Xfinddfa(g, type) +X grammar *g; +X register int type; +X{ +X register int i; +X register dfa *d; +X +X for (i = g->g_ndfas, d = g->g_dfa; --i >= 0; d++) { +X if (d->d_type == type) +X return d; +X } +X assert(0); +X /* NOTREACHED */ +X} +X +Xchar * +Xlabelrepr(lb) +X label *lb; +X{ +X static char buf[100]; +X +X if (lb->lb_type == ENDMARKER) +X return "EMPTY"; +X else if (ISNONTERMINAL(lb->lb_type)) { +X if (lb->lb_str == NULL) { +X sprintf(buf, "NT%d", lb->lb_type); +X return buf; +X } +X else +X return lb->lb_str; +X } +X else { +X if (lb->lb_str == NULL) +X return tok_name[lb->lb_type]; +X else { +X sprintf(buf, "%.32s(%.32s)", +X tok_name[lb->lb_type], lb->lb_str); +X return buf; +X } +X } +X} +EOF +fi +if test -s 'src/malloc.h' +then echo '*** I will not over-write existing file src/malloc.h' +else +echo 'x - src/malloc.h' +sed 's/^X//' > 'src/malloc.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Lowest-level memory allocation interface */ +X +X#ifdef THINK_C +X#define ANY void +X#ifndef THINK_C_3_0 +X#define HAVE_STDLIB +X#endif +X#endif +X +X#ifdef __STD_C__ +X#define ANY void +X#define HAVE_STDLIB +X#endif +X +X#ifndef ANY +X#define ANY char +X#endif +X +X#ifndef NULL +X#define NULL 0 +X#endif +X +X#define NEW(type, n) ( (type *) malloc((n) * sizeof(type)) ) +X#define RESIZE(p, type, n) \ +X if ((p) == NULL) \ +X (p) = (type *) malloc((n) * sizeof(type)); \ +X else \ +X (p) = (type *) realloc((char *)(p), (n) * sizeof(type)) +X#define DEL(p) free((char *)p) +X#define XDEL(p) if ((p) == NULL) ; else DEL(p) +X +X#ifdef HAVE_STDLIB +X#include <stdlib.h> +X#else +Xextern ANY *malloc PROTO((unsigned int)); +Xextern ANY *calloc PROTO((unsigned int, unsigned int)); +Xextern ANY *realloc PROTO((ANY *, unsigned int)); +Xextern void free PROTO((ANY *)); /* XXX sometimes int on Unix old systems */ +X#endif +EOF +fi +if test -s 'src/node.h' +then echo '*** I will not over-write existing file src/node.h' +else +echo 'x - src/node.h' +sed 's/^X//' > 'src/node.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Parse tree node interface */ +X +Xtypedef struct _node { +X int n_type; +X char *n_str; +X int n_lineno; +X int n_nchildren; +X struct _node *n_child; +X} node; +X +Xextern node *newtree PROTO((int type)); +Xextern node *addchild PROTO((node *n, int type, char *str, int lineno)); +Xextern void freetree PROTO((node *n)); +X +X/* Node access functions */ +X#define NCH(n) ((n)->n_nchildren) +X#define CHILD(n, i) (&(n)->n_child[i]) +X#define TYPE(n) ((n)->n_type) +X#define STR(n) ((n)->n_str) +X +X/* Assert that the type of a node is what we expect */ +X#ifndef DEBUG +X#define REQ(n, type) { /*pass*/ ; } +X#else +X#define REQ(n, type) \ +X { if (TYPE(n) != (type)) { \ +X fprintf(stderr, "FATAL: node type %d, required %d\n", \ +X TYPE(n), type); \ +X abort(); \ +X } } +X#endif +X +Xextern void listtree PROTO((node *)); +Xextern void listnode PROTO((FILE *, node *)); +EOF +fi +if test -s 'src/parser.h' +then echo '*** I will not over-write existing file src/parser.h' +else +echo 'x - src/parser.h' +sed 's/^X//' > 'src/parser.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Parser interface */ +X +X#define MAXSTACK 100 +X +Xtypedef struct _stackentry { +X int s_state; /* State in current DFA */ +X dfa *s_dfa; /* Current DFA */ +X struct _node *s_parent; /* Where to add next node */ +X} stackentry; +X +Xtypedef struct _stack { +X stackentry *s_top; /* Top entry */ +X stackentry s_base[MAXSTACK];/* Array of stack entries */ +X /* NB The stack grows down */ +X} stack; +X +Xtypedef struct { +X struct _stack p_stack; /* Stack of parser states */ +X struct _grammar *p_grammar; /* Grammar to use */ +X struct _node *p_tree; /* Top of parse tree */ +X} parser_state; +X +Xparser_state *newparser PROTO((struct _grammar *g, int start)); +Xvoid delparser PROTO((parser_state *ps)); +Xint addtoken PROTO((parser_state *ps, int type, char *str, int lineno)); +Xvoid addaccelerators PROTO((grammar *g)); +EOF +fi +if test -s 'src/pgenheaders.h' +then echo '*** I will not over-write existing file src/pgenheaders.h' +else +echo 'x - src/pgenheaders.h' +sed 's/^X//' > 'src/pgenheaders.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Include files and extern declarations used by most of the parser. +X This is a precompiled header for THINK C. */ +X +X#include <stdio.h> +X#include <string.h> +X +X#ifdef THINK_C +X/* #define THINK_C_3_0 /*** TURN THIS ON FOR THINK C 3.0 ****/ +X#define label label_ +X#undef label +X#endif +X +X#ifdef THINK_C_3_0 +X#include <proto.h> +X#endif +X +X#ifdef THINK_C +X#ifndef THINK_C_3_0 +X#include <stdlib.h> +X#endif +X#endif +X +X#include "PROTO.h" +X#include "malloc.h" +X +Xextern void fatal PROTO((char *)); +EOF +fi +if test -s 'src/pythonrun.h' +then echo '*** I will not over-write existing file src/pythonrun.h' +else +echo 'x - src/pythonrun.h' +sed 's/^X//' > 'src/pythonrun.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Interfaces to parse and execute pieces of python code */ +X +Xvoid initall PROTO((void)); +X +Xint run PROTO((FILE *, char *)); +X +Xint run_script PROTO((FILE *, char *)); +Xint run_tty_1 PROTO((FILE *, char *)); +Xint run_tty_loop PROTO((FILE *, char *)); +X +Xint parse_string PROTO((char *, int, struct _node **)); +Xint parse_file PROTO((FILE *, char *, int, struct _node **)); +X +Xobject *eval_node PROTO((struct _node *, char *, object *, object *)); +X +Xobject *run_string PROTO((char *, int, object *, object *)); +Xobject *run_file PROTO((FILE *, char *, int, object *, object *)); +Xobject *run_err_node PROTO((int, struct _node *, char *, object *, object *)); +Xobject *run_node PROTO((struct _node *, char *, object *, object *)); +X +Xvoid print_error PROTO((void)); +X +Xvoid goaway PROTO((int)); +EOF +fi +if test -s 'src/regexp.h' +then echo '*** I will not over-write existing file src/regexp.h' +else +echo 'x - src/regexp.h' +sed 's/^X//' > 'src/regexp.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* +X * Definitions etc. for regexp(3) routines. +X * +X * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], +X * not the System V one. +X */ +X +X#define MULTILINE +X +X#define NSUBEXP 10 +Xtypedef struct regexp { +X char *startp[NSUBEXP]; +X char *endp[NSUBEXP]; +X char regstart; /* Internal use only. */ +X char reganch; /* Internal use only. */ +X char *regmust; /* Internal use only. */ +X int regmlen; /* Internal use only. */ +X char program[1]; /* Unwarranted chumminess with compiler. */ +X} regexp; +X +Xextern regexp *regcomp(); +Xextern int regexec(); +X#ifdef MULTILINE +Xextern int reglexec(); +X#endif +Xextern void regsub(); +Xextern void regerror(); +EOF +fi +if test -s 'src/sigtype.h' +then echo '*** I will not over-write existing file src/sigtype.h' +else +echo 'x - src/sigtype.h' +sed 's/^X//' > 'src/sigtype.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* The type of signal handlers is somewhat problematic. +X This file encapsulates my knowledge about it: +X - on the Mac (THINK C), it's int for 3.0, void for 4.0 +X - on other systems, it's usually void, except it's int on vax Ultrix. +X Pass -DSIGTYPE=... to cc if you know better. */ +X +X#ifndef SIGTYPE +X +X#ifdef THINK_C +X +X#ifdef THINK_C_3_0 +X#define SIGTYPE int +X#else +X#define SIGTYPE void +X#endif +X +X#else /* !THINK_C */ +X +X#if defined(vax) && !defined(AMOEBA) +X#define SIGTYPE int +X#else +X#define SIGTYPE void +X#endif +X +X#endif /* !THINK_C */ +X +X#endif /* !SIGTYPE */ +EOF +fi +if test -s 'src/token.h' +then echo '*** I will not over-write existing file src/token.h' +else +echo 'x - src/token.h' +sed 's/^X//' > 'src/token.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Token types */ +X +X#define ENDMARKER 0 +X#define NAME 1 +X#define NUMBER 2 +X#define STRING 3 +X#define NEWLINE 4 +X#define INDENT 5 +X#define DEDENT 6 +X#define LPAR 7 +X#define RPAR 8 +X#define LSQB 9 +X#define RSQB 10 +X#define COLON 11 +X#define COMMA 12 +X#define SEMI 13 +X#define PLUS 14 +X#define MINUS 15 +X#define STAR 16 +X#define SLASH 17 +X#define VBAR 18 +X#define AMPER 19 +X#define LESS 20 +X#define GREATER 21 +X#define EQUAL 22 +X#define DOT 23 +X#define PERCENT 24 +X#define BACKQUOTE 25 +X#define LBRACE 26 +X#define RBRACE 27 +X#define OP 28 +X#define ERRORTOKEN 29 +X#define N_TOKENS 30 +X +X/* Special definitions for cooperation with parser */ +X +X#define NT_OFFSET 256 +X +X#define ISTERMINAL(x) ((x) < NT_OFFSET) +X#define ISNONTERMINAL(x) ((x) >= NT_OFFSET) +X#define ISEOF(x) ((x) == ENDMARKER) +X +X +Xextern char *tok_name[]; /* Token names */ +Xextern int tok_1char PROTO((int)); +EOF +fi +if test -s 'src/typeobject.c' +then echo '*** I will not over-write existing file src/typeobject.c' +else +echo 'x - src/typeobject.c' +sed 's/^X//' > 'src/typeobject.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Type object implementation */ +X +X#include "allobjects.h" +X +X/* Type object implementation */ +X +Xstatic void +Xtype_print(v, fp, flags) +X typeobject *v; +X FILE *fp; +X int flags; +X{ +X fprintf(fp, "<type '%s'>", v->tp_name); +X} +X +Xstatic object * +Xtype_repr(v) +X typeobject *v; +X{ +X char buf[100]; +X sprintf(buf, "<type '%.80s'>", v->tp_name); +X return newstringobject(buf); +X} +X +Xtypeobject Typetype = { +X OB_HEAD_INIT(&Typetype) +X 0, /* Number of items for varobject */ +X "type", /* Name of this type */ +X sizeof(typeobject), /* Basic object size */ +X 0, /* Item size for varobject */ +X 0, /*tp_dealloc*/ +X type_print, /*tp_print*/ +X 0, /*tp_getattr*/ +X 0, /*tp_setattr*/ +X 0, /*tp_compare*/ +X type_repr, /*tp_repr*/ +X}; +EOF +fi +echo 'Part 19 out of 21 of pack.out complete.' +exit 0 diff --git a/shar/python-0.9.1-20-21.shar b/shar/python-0.9.1-20-21.shar new file mode 100644 index 0000000..59df200 --- /dev/null +++ b/shar/python-0.9.1-20-21.shar @@ -0,0 +1,1941 @@ +: This is a shell archive. +: Extract with 'sh this_file'. +: +: Extract part 01 first since it makes all directories +echo 'Start of pack.out, part 20 out of 21:' +if test -s 'demo/scripts/mkreal.py' +then echo '*** I will not over-write existing file demo/scripts/mkreal.py' +else +echo 'x - demo/scripts/mkreal.py' +sed 's/^X//' > 'demo/scripts/mkreal.py' << 'EOF' +X#! /ufs/guido/bin/sgi/python +X +X# mkreal +X# +X# turn a symlink to a directory into a real directory +X +Ximport sys +Ximport posix +Ximport path +Xfrom stat import * +X +Xcat = path.cat +X +Xerror = 'mkreal error' +X +XBUFSIZE = 32*1024 +X +Xdef mkrealfile(name): +X st = posix.stat(name) # Get the mode +X mode = S_IMODE(st[ST_MODE]) +X linkto = posix.readlink(name) # Make sure again it's a symlink +X f_in = open(name, 'r') # This ensures it's a file +X posix.unlink(name) +X f_out = open(name, 'w') +X while 1: +X buf = f_in.read(BUFSIZE) +X if not buf: break +X f_out.write(buf) +X del f_out # Flush data to disk before changing mode +X posix.chmod(name, mode) +X +Xdef mkrealdir(name): +X st = posix.stat(name) # Get the mode +X mode = S_IMODE(st[ST_MODE]) +X linkto = posix.readlink(name) +X files = posix.listdir(name) +X posix.unlink(name) +X posix.mkdir(name, mode) +X posix.chmod(name, mode) +X linkto = cat('..', linkto) +X # +X for file in files: +X if file not in ('.', '..'): +X posix.symlink(cat(linkto, file), cat(name, file)) +X +Xdef main(): +X sys.stdout = sys.stderr +X progname = path.basename(sys.argv[0]) +X args = sys.argv[1:] +X if not args: +X print 'usage:', progname, 'path ...' +X sys.exit(2) +X status = 0 +X for name in args: +X if not path.islink(name): +X print progname+':', name+':', 'not a symlink' +X status = 1 +X else: +X if path.isdir(name): +X mkrealdir(name) +X else: +X mkrealfile(name) +X sys.exit(status) +X +Xmain() +EOF +chmod +x 'demo/scripts/mkreal.py' +fi +if test -s 'demo/scripts/ptags.py' +then echo '*** I will not over-write existing file demo/scripts/ptags.py' +else +echo 'x - demo/scripts/ptags.py' +sed 's/^X//' > 'demo/scripts/ptags.py' << 'EOF' +X#! /ufs/guido/bin/sgi/python +X +X# ptags +X# +XCreate a tags file for Python programs +X# Tagged are: +X# - functions (even inside other defs or classes) +X# - classes +X# - filenames +X# Warns about files it cannot open. +X# No warnings about duplicate tags. +X +Ximport sys +Ximport posix +Ximport path +Ximport string +X +Xkeywords = ['def', 'class'] # If you add keywords, update starts!!! +Xstarts = 'dc' # Starting characters of keywords +X +Xwhitespace = string.whitespace +Xidentchars = string.letters + string.digits + '_' +X +Xtags = [] # Modified! +X +Xdef main(): +X args = sys.argv[1:] +X for file in args: treat_file(file) +X if tags: +X fp = open('tags', 'w') +X tags.sort() +X for s in tags: fp.write(s) +X +Xdef treat_file(file): +X try: +X fp = open(file, 'r') +X except: +X print 'Cannot open', file +X return +X base = path.basename(file) +X if base[-3:] = '.py': base = base[:-3] +X s = base + '\t' + file + '\t' + '1\n' +X tags.append(s) +X while 1: +X line = fp.readline() +X if not line: break +X maketag(line, file) +X +Xdef maketag(line, file): +X i = 0 +X while line[i:i+1] in whitespace: i = i+1 +X if line[i:i+1] not in starts: return +X n = len(line) +X j = i +X while i < n and line[i] not in whitespace: i = i+1 +X if line[j:i] not in keywords: return +X while i < n and line[i] in whitespace: i = i+1 +X j = i +X while i < n and line[i] in identchars: i = i+1 +X name = line[j:i] +X while i < n and line[i] in whitespace: i = i+1 +X if i < n and line[i] = '(': i = i+1 +X s = name + '\t' + file + '\t' + '/^' + line[:i] + '/\n' +X tags.append(s) +X +Xmain() +EOF +chmod +x 'demo/scripts/ptags.py' +fi +if test -s 'demo/sgi/audio/play.py' +then echo '*** I will not over-write existing file demo/sgi/audio/play.py' +else +echo 'x - demo/sgi/audio/play.py' +sed 's/^X//' > 'demo/sgi/audio/play.py' << 'EOF' +X#!/ufs/guido/bin/sgi/python +X +Ximport sys +Ximport audio +X +Ximport string +Ximport getopt +Ximport auds +X +Xdebug = [] +X +XDEF_RATE = 3 +X +Xdef main(): +X # +X gain = 100 +X rate = 0 +X starter = audio.write +X stopper = 0 +X # +X optlist, args = getopt.getopt(sys.argv[1:], 'adg:r:') +X # +X for optname, optarg in optlist: +X if 0: +X pass +X elif optname = '-d': +X debug.append(1) +X elif optname = '-g': +X gain = string.atoi(optarg) +X if not (0 < gain < 256): +X raise optarg.error, '-g gain out of range' +X elif optname = '-r': +X rate = string.atoi(optarg) +X if not (1 <= rate <= 3): +X raise optarg.error, '-r rate out of range' +X elif optname = '-a': +X starter = audio.start_playing +X stopper = audio.wait_playing +X # +X audio.setoutgain(gain) +X audio.setrate(rate) +X # +X if not args: +X play(starter, rate, auds.loadfp(sys.stdin)) +X else: +X real_stopper = 0 +X for file in args: +X if real_stopper: +X real_stopper() +X play(starter, rate, auds.load(file)) +X real_stopper = stopper +X +Xdef play(starter, rate, data): +X magic = data[:4] +X if magic = '0008': +X mrate = 3 +X elif magic = '0016': +X mrate = 2 +X elif magic = '0032': +X mrate = 1 +X else: +X mrate = 0 +X if mrate: +X data = data[4:] +X else: +X mrate = DEF_RATE +X if not rate: rate = mrate +X audio.setrate(rate) +X starter(data) +X +Xtry: +X main() +Xfinally: +X audio.setoutgain(0) +X audio.done() +EOF +chmod +x 'demo/sgi/audio/play.py' +fi +if test -s 'demo/sgi/gl_panel/flying/data.py' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/flying/data.py' +else +echo 'x - demo/sgi/gl_panel/flying/data.py' +sed 's/^X//' > 'demo/sgi/gl_panel/flying/data.py' << 'EOF' +X +X# two string constants +XARROW = '-> ' +XNULL = '' +XZERO = 0 +XONE = 1 +X +X# +X# the color light-blue +X# +Xlightblue = (43,169,255) +X +X +X# +X# a couple of rotation, translation, scaling vectors +X# +Xrts1 = [[3.0,3.1,2.0],[2.2, 1.2, 2.0], [0.8,0.8,0.8]] +Xrts2 = [[3.2,2.6,1.8],[-1.9, 1.2, 1.6], [0.3,0.3,1.0]] +Xrts3 = [[2.2,3.3,1.4], [-1.0, 1.2,-1.5], [0.6,0.6, 0.6]] +Xrts4 = [[4.2,2.1,3.2],[1.2, 1.3, 1.0],[0.5,0.5,0.8]] +Xrts5 = [[1.2,3.3,2.4], [-2.0, 1.4,-2.1], [0.8, 0.8, 0.2]] +Xrts6 = [[3.2,3.6,2.4], [1.1, 1.6, 2.5], [0.8,0.3,0.1]] +Xrts7 = [[2.3,2.7,3.3], [1.1, 2.3, 1.7], [0.6,0.6,0.5]] +Xrts8 = [[4.2,2.1,3.2], [1.2, 1.3, 0.0], [0.5,0.5,0.5]] +X# +Xrts90 = [[4.2,2.1,3.2], [2.0, 0.0, 0.9], [0.3,0.3,1.0]] +Xrts91 = [[4.2,2.1,3.2], [-2.0, 0.0, 0.9], [0.3,0.3,1.0]] +Xrts92 = [[4.2,2.1,3.2], [0.0, 2.0, 0.9], [0.3,0.3,1.0]] +Xrts93 = [[4.2,2.1,3.2], [0.0, -2.0, 0.9], [0.3,0.3,1.0]] +Xrts10 = [[4.2,2.1,3.2], [0.0, 0.0, 0.0], [2.2,2.2,0.2]] +X +X# +X# (composite) object definitions +X# +Xo1 = [['sphere',rts1, 1]] +Xo2 = [['cylinder', rts2, 4]] +Xo3 = [['cube', rts3, 3]] +Xo4 = [['cone', rts4, 2], ['sphere', rts8, 9]] +Xo5 = [['sphere', rts5, 5]] +Xo6 = [['cube', rts6, 6]] +Xo7 = [['pyramid', rts7, 8]] +Xo8 = [['cube', rts10, 9], ['cylinder', rts90, 2], ['cylinder', rts91, 2], ['cylinder', rts92, 2], ['cylinder', rts93, 2]] +EOF +fi +if test -s 'demo/sgi/gl_panel/nurbs/nurbsdata.py' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/nurbs/nurbsdata.py' +else +echo 'x - demo/sgi/gl_panel/nurbs/nurbsdata.py' +sed 's/^X//' > 'demo/sgi/gl_panel/nurbs/nurbsdata.py' << 'EOF' +X# Data used by fancy nurbs demo. +X +XTRUE = 1 +XFALSE = 0 +X +XRED = 0xff +XYELLOW = 0xffff +X +X# +X# nurb order +X# +XORDER = 4 +X +X# +X# identity matrix +X# +Xidmat = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1] +X +X# +X# s and t knots +X# +Xsurfknots = [-1, -1, -1, -1, 1, 1, 1, 1] +X +X# +X# list of list of control points +X# +Xdef make_ctlpoints(): +X c = [] +X # +X ci = [] +X ci.append(-2.5, -3.7, 1.0) +X ci.append(-1.5, -3.7, 3.0) +X ci.append(1.5, -3.7, -2.5) +X ci.append(2.5, -3.7, -0.75) +X c.append(ci) +X # +X ci = [] +X ci.append(-2.5, -2.0, 3.0) +X ci.append(-1.5, -2.0, 4.0) +X ci.append(1.5, -2.0, -3.0) +X ci.append(2.5, -2.0, 0.0) +X c.append(ci) +X # +X ci = [] +X ci.append(-2.5, 2.0, 1.0) +X ci.append(-1.5, 2.0, 0.0) +X ci.append(1.5, 2.0, -1.0) +X ci.append(2.5, 2.0, 2.0) +X c.append(ci) +X # +X ci = [] +X ci.append(-2.5, 2.7, 1.25) +X ci.append(-1.5, 2.7, 0.1) +X ci.append(1.5, 2.7, -0.6) +X ci.append(2.5, 2.7, 0.2) +X c.append(ci) +X # +X return c +X +Xctlpoints = make_ctlpoints () +X +X# +X# trim knots +X# +Xtrimknots = [0., 0., 0., 1., 1., 2., 2., 3., 3., 4., 4., 4.] +X +Xdef make_trimpoints(): +X c = [] +X # +X c.append(1.0, 0.0, 1.0) +X c.append(1.0, 1.0, 1.0) +X c.append(0.0, 2.0, 2.0) +X c.append(-1.0, 1.0, 1.0) +X c.append(-1.0, 0.0, 1.0) +X c.append(-1.0, -1.0, 1.0) +X c.append(0.0, -2.0, 2.0) +X c.append(1.0, -1.0, 1.0) +X c.append(1.0, 0.0, 1.0) +X # +X return c +X +Xtrimpoints = make_trimpoints() +EOF +fi +if test -s 'demo/sgi/gl_panel/twoview/block.py' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/twoview/block.py' +else +echo 'x - demo/sgi/gl_panel/twoview/block.py' +sed 's/^X//' > 'demo/sgi/gl_panel/twoview/block.py' << 'EOF' +X# module 'block' imported by twoview demo. +X +Xfrom gl import n3f, bgnpolygon, varray, endpolygon, lmbind +Xfrom GL import MATERIAL +X +X# Draw a single 2x2x2 block with its center at (0, 0, 0) +X# Arguments are the material indices (0 = don't call lmbind) +X# +Xdef block(m_front, m_back, m_left, m_right, m_top, m_bottom): +X # +X # Distances defining the sides +X # +X x_left = -1.0 +X x_right = 1.0 +X y_top = 1.0 +X y_bottom = -1.0 +X z_front = 1.0 +X z_back = -1.0 +X # +X # Top surface points: A, B, C, D +X # +X A = x_right, y_top, z_front +X B = x_right, y_top, z_back +X C = x_left, y_top, z_back +X D = x_left, y_top, z_front +X # +X # Bottom surface points: E, F, G, H +X # +X E = x_right, y_bottom, z_front +X F = x_right, y_bottom, z_back +X G = x_left, y_bottom, z_back +X H = x_left, y_bottom, z_front +X # +X # Draw front face +X # +X if m_front: lmbind(MATERIAL, m_front) +X n3f(0.0, 0.0, 1.0) +X face(H, E, A, D) +X # +X # Draw back face +X # +X if m_back: lmbind(MATERIAL, m_back) +X n3f(0.0, 0.0, -1.0) +X face(G, F, B, C) +X # +X # Draw left face +X # +X if m_left: lmbind(MATERIAL, m_left) +X n3f(-1.0, 0.0, 0.0) +X face(G, H, D, C) +X # +X # Draw right face +X # +X if m_right: lmbind(MATERIAL, m_right) +X n3f(1.0, 0.0, 0.0) +X face(F, E, A, B) +X # +X # Draw top face +X # +X if m_top: lmbind(MATERIAL, m_top) +X n3f(0.0, 1.0, 0.0) +X face(A, B, C, D) +X # +X # Draw bottom face +X # +X if m_bottom: lmbind(MATERIAL, m_bottom) +X n3f(0.0, -1.0, 0.0) +X face(E, F, G, H) +X +Xdef face(points): +X bgnpolygon() +X varray(points) +X endpolygon() +EOF +fi +if test -s 'demo/sgi/gl_panel/twoview/camera.s' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/twoview/camera.s' +else +echo 'x - demo/sgi/gl_panel/twoview/camera.s' +sed 's/^X//' > 'demo/sgi/gl_panel/twoview/camera.s' << 'EOF' +X;;; This file was automatically generated by the panel editor. +X;;; If you read it into gnu emacs, it will automagically format itself. +X +X(panel (prop help creator:user-panel-help) +X(prop user-panel #t) +X(label "Camera Control") +X(x 1010) +X(y 589) +X(al (pnl_wide_button (name "quitbutton") +X(prop help creator:user-act-help) +X(label "quit") +X(x 3.5) +X(y 1) +X(w 0.94) +X(downfunc move-then-resize) +X) +X(pnl_filled_hslider (name "farclip") +X(prop help creator:user-act-help) +X(label "far clipping plane") +X(x 1.25) +X(y 3.5) +X(w 3.3) +X(h 0.4) +X(val 0.752) +X(downfunc move-then-resize) +X) +X(pnl_filled_hslider (name "nearclip") +X(prop help creator:user-act-help) +X(label "near clipping plane") +X(x 1.25) +X(y 4.5) +X(w 3.3) +X(h 0.4) +X(val 0.17) +X(downfunc move-then-resize) +X) +X(pnl_filled_vslider (name "zoom") +X(prop help creator:user-act-help) +X(label "zoom") +X(x 0.2) +X(y 1.25) +X(w 0.4) +X(h 3.9) +X(val 0.344) +X(downfunc move-then-resize) +X) +X) +X) +X;;; Local Variables: +X;;; mode: scheme +X;;; eval: (save-excursion (goto-char (point-min)) (kill-line 3)) +X;;; eval: (save-excursion (goto-char (point-min)) (replace-regexp "[ \n]*)" ")")) +X;;; eval: (indent-region (point-min) (point-max) nil) +X;;; eval: (progn (kill-line -3) (delete-backward-char 1) (save-buffer)) +X;;; End: +EOF +fi +if test -s 'lib/HVSplit.py' +then echo '*** I will not over-write existing file lib/HVSplit.py' +else +echo 'x - lib/HVSplit.py' +sed 's/^X//' > 'lib/HVSplit.py' << 'EOF' +X# HVSplit contains generic code for HSplit and VSplit. +X# HSplit and VSplit are specializations to either dimension. +X +X# XXX This does not yet stretch/shrink children if there is too much +X# XXX or too little space in the split dimension. +X# XXX (NB There is no interface to ask children for stretch preferences.) +X +Xfrom Split import Split +X +Xclass HVSplit() = Split(): +X # +X def create(self, (parent, hv)): +X # hv is 0 or 1 for HSplit or VSplit +X self = Split.create(self, parent) +X self.hv = hv +X return self +X # +X def minsize(self, m): +X hv, vh = self.hv, 1 - self.hv +X size = [0, 0] +X for c in self.children: +X csize = c.minsize(m) +X if csize[vh] > size[vh]: size[vh] = csize[vh] +X size[hv] = size[hv] + csize[hv] +X return size[0], size[1] +X # +X def getbounds(self): +X return self.bounds +X # +X def setbounds(self, bounds): +X self.bounds = bounds +X hv, vh = self.hv, 1 - self.hv +X mf = self.parent.beginmeasuring +X size = self.minsize(mf()) +X # XXX not yet used! Later for stretching +X maxsize_hv = bounds[1][hv] - bounds[0][hv] +X origin = [self.bounds[0][0], self.bounds[0][1]] +X for c in self.children: +X size = c.minsize(mf()) +X corner = [0, 0] +X corner[vh] = bounds[1][vh] +X corner[hv] = origin[hv] + size[hv] +X c.setbounds((origin[0], origin[1]), \ +X (corner[0], corner[1])) +X origin[hv] = corner[hv] +X # XXX stretch +X # XXX too-small +X # +X +Xclass HSplit() = HVSplit(): +X def create(self, parent): +X return HVSplit.create(self, (parent, 0)) +X +Xclass VSplit() = HVSplit(): +X def create(self, parent): +X return HVSplit.create(self, (parent, 1)) +EOF +fi +if test -s 'lib/dump.py' +then echo '*** I will not over-write existing file lib/dump.py' +else +echo 'x - lib/dump.py' +sed 's/^X//' > 'lib/dump.py' << 'EOF' +X# Module 'dump' +X# +X# Print python code that reconstructs a variable. +X# This only works in certain cases. +X# +X# It works fine for: +X# - ints and floats (except NaNs and other weird things) +X# - strings +X# - compounds and lists, provided it works for all their elements +X# - imported modules, provided their name is the module name +X# +X# It works for top-level dictionaries but not for dictionaries +X# contained in other objects (could be made to work with some hassle +X# though). +X# +X# It does not work for functions (all sorts), classes, class objects, +X# windows, files etc. +X# +X# Finally, objects referenced by more than one name or contained in more +X# than one other object lose their sharing property (this is bad for +X# strings used as exception identifiers, for instance). +X +X# Dump a whole symbol table +X# +Xdef dumpsymtab(dict): +X for key in dict.keys(): +X dumpvar(key, dict[key]) +X +X# Dump a single variable +X# +Xdef dumpvar(name, x): +X import sys +X t = type(x) +X if t = type({}): +X print name, '= {}' +X for key in x.keys(): +X item = x[key] +X if not printable(item): +X print '#', +X print name, '[', `key`, '] =', `item` +X elif t in (type(''), type(0), type(0.0), type([]), type(())): +X if not printable(x): +X print '#', +X print name, '=', `x` +X elif t = type(sys): +X print 'import', name, '#', x +X else: +X print '#', name, '=', x +X +X# check if a value is printable in a way that can be read back with input() +X# +Xdef printable(x): +X t = type(x) +X if t in (type(''), type(0), type(0.0)): +X return 1 +X if t in (type([]), type(())): +X for item in x: +X if not printable(item): +X return 0 +X return 1 +X if x = {}: +X return 1 +X return 0 +EOF +fi +if test -s 'lib/localtime.py' +then echo '*** I will not over-write existing file lib/localtime.py' +else +echo 'x - lib/localtime.py' +sed 's/^X//' > 'lib/localtime.py' << 'EOF' +X# module localtime -- Time conversions +X +Ximport posix +X +Xepoch = 1970 # 1 jan 00:00:00, UCT +Xday0 = 4 # day 0 was a thursday +X +Xday_names = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat') +X +Xmonth_names = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun') +Xmonth_names = month_names + ('Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec') +X +Xmonth_sizes = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) +X +Xdef isleap(year): +X return year % 4 = 0 and (year % 100 <> 0 or year % 400 = 0) +X +Xdef gmtime(secs): # decode time into UCT +X mins, secs = divmod(secs, 60) +X hours, mins = divmod(mins, 60) +X days, hours = divmod(hours, 24) +X wday = (day0 + days) % 7 +X year = epoch +X lp = isleap(year) +X dpy = 365 + lp +X while days >= dpy: +X days = days - dpy +X year = year + 1 +X lp = isleap(year) +X dpy = 365 + lp +X yday = days +X month = 0 +X dpm = month_sizes[month] + (lp and month = 1) +X while days >= dpm: +X days = days - dpm +X month = month + 1 +X dpm = month_sizes[month] + (lp and month = 1) +X return (year, month, days+1, hours, mins, secs, yday, wday) +X +Xdef dd(x): +X s = `x` +X while len(s) < 2: s = '0' + s +X return s +X +Xdef zd(x): +X s = `x` +X while len(s) < 2: s = ' ' + s +X return s +X +Xdef format(year, month, days, hours, mins, secs, yday, wday): +X s = day_names[wday] + ' ' + zd(days) + ' ' + month_names[month] + ' ' +X s = s + dd(hours) + ':' + dd(mins) + ':' + dd(secs) +X return s +EOF +fi +if test -s 'lib/poly.py' +then echo '*** I will not over-write existing file lib/poly.py' +else +echo 'x - lib/poly.py' +sed 's/^X//' > 'lib/poly.py' << 'EOF' +X# module 'poly' -- Polynomials +X +X# A polynomial is represented by a list of coefficients, e.g., +X# [1, 10, 5] represents 1*x**0 + 10*x**1 + 5*x**2 (or 1 + 10x + 5x**2). +X# There is no way to suppress internal zeros; trailing zeros are +X# taken out by normalize(). +X +Xdef normalize(p): # Strip unnecessary zero coefficients +X n = len(p) +X while p: +X if p[n-1]: return p[:n] +X n = n-1 +X return [] +X +Xdef plus(a, b): +X if len(a) < len(b): a, b = b, a # make sure a is the longest +X res = a[:] # make a copy +X for i in range(len(b)): +X res[i] = res[i] + b[i] +X return normalize(res) +X +Xdef minus(a, b): +X if len(a) < len(b): a, b = b, a # make sure a is the longest +X res = a[:] # make a copy +X for i in range(len(b)): +X res[i] = res[i] - b[i] +X return normalize(res) +X +Xdef one(power, coeff): # Representation of coeff * x**power +X res = [] +X for i in range(power): res.append(0) +X return res + [coeff] +X +Xdef times(a, b): +X res = [] +X for i in range(len(a)): +X for j in range(len(b)): +X res = plus(res, one(i+j, a[i]*b[j])) +X return res +X +Xdef power(a, n): # Raise polynomial a to the positive integral power n +X if n = 0: return [1] +X if n = 1: return a +X if n/2*2 = n: +X b = power(a, n/2) +X return times(b, b) +X return times(power(a, n-1), a) +X +Xdef der(a): # First derivative +X res = a[1:] +X for i in range(len(res)): +X res[i] = res[i] * (i+1) +X return res +X +X# Computing a primitive function would require rational arithmetic... +EOF +fi +if test -s 'lib/shutil.py' +then echo '*** I will not over-write existing file lib/shutil.py' +else +echo 'x - lib/shutil.py' +sed 's/^X//' > 'lib/shutil.py' << 'EOF' +X# Module 'shutil' -- utility functions usable in a shell-like program +X +Ximport posix +Ximport path +X +XMODEBITS = 010000 # Lower 12 mode bits +X# Change this to 01000 (9 mode bits) to avoid copying setuid etc. +X +X# Copy data from src to dst +X# +Xdef copyfile(src, dst): +X fsrc = open(src, 'r') +X fdst = open(dst, 'w') +X while 1: +X buf = fsrc.read(16*1024) +X if not buf: break +X fdst.write(buf) +X +X# Copy mode bits from src to dst +X# +Xdef copymode(src, dst): +X st = posix.stat(src) +X mode = divmod(st[0], MODEBITS)[1] +X posix.chmod(dst, mode) +X +X# Copy all stat info (mode bits, atime and mtime) from src to dst +X# +Xdef copystat(src, dst): +X st = posix.stat(src) +X mode = divmod(st[0], MODEBITS)[1] +X posix.chmod(dst, mode) +X posix.utimes(dst, st[7:9]) +X +X# Copy data and mode bits ("cp src dst") +X# +Xdef copy(src, dst): +X copyfile(src, dst) +X copymode(src, dst) +X +X# Copy data and all stat info ("cp -p src dst") +X# +Xdef copy2(src, dst): +X copyfile(src, dst) +X copystat(src, dst) +X +X# Recursively copy a directory tree. +X# The destination must not already exist. +X# +Xdef copytree(src, dst): +X names = posix.listdir(src) +X posix.mkdir(dst, 0777) +X dot_dotdot = '.', '..' +X for name in names: +X if name not in dot_dotdot: +X srcname = path.cat(src, name) +X dstname = path.cat(dst, name) +X #print 'Copying', srcname, 'to', dstname +X try: +X #if path.islink(srcname): +X # linkto = posix.readlink(srcname) +X # posix.symlink(linkto, dstname) +X #elif path.isdir(srcname): +X if path.isdir(srcname): +X copytree(srcname, dstname) +X else: +X copy2(srcname, dstname) +X # XXX What about devices, sockets etc.? +X except posix.error, why: +X print 'Could not copy', srcname, 'to', dstname, +X print '(', why[1], ')' +EOF +fi +if test -s 'lib/stdwinevents.py' +then echo '*** I will not over-write existing file lib/stdwinevents.py' +else +echo 'x - lib/stdwinevents.py' +sed 's/^X//' > 'lib/stdwinevents.py' << 'EOF' +X# Module 'stdwinevents' -- Constants for stdwin event types +X# +X# Suggested usage: +X# from stdwinevents import * +X +X# The function stdwin.getevent() returns a tuple containing: +X# (type, window, detail) +X# where detail may be <no value> or a value depending on type, see below: +X +X# Values for type: +X +XWE_NULL = 0 # not reported -- means 'no event' internally +XWE_ACTIVATE = 1 # detail is <no object> +XWE_CHAR = 2 # detail is the character +XWE_COMMAND = 3 # detail is one of the WC_* constants below +XWE_MOUSE_DOWN = 4 # detail is ((h, v), clicks, button, mask) +XWE_MOUSE_MOVE = 5 # ditto +XWE_MOUSE_UP = 6 # ditto +XWE_MENU = 7 # detail is (menu, item) +XWE_SIZE = 8 # detail is (width, height) [???] +XWE_MOVE = 9 # not reported -- reserved for future use +XWE_DRAW = 10 # detail is ((left, top), (right, bottom)) +XWE_TIMER = 11 # detail is <no object> +XWE_DEACTIVATE = 12 # detail is <no object> +XWE_EXTERN = 13 # detail is <no object> +XWE_KEY = 14 # detail is ??? +XWE_LOST_SEL = 15 # detail is selection number +XWE_CLOSE = 16 # detail is <no object> +X +X# Values for detail when type is WE_COMMAND: +X +XWC_CLOSE = 1 # user hit close box +XWC_LEFT = 2 # left arrow key +XWC_RIGHT = 3 # right arrow key +XWC_UP = 4 # up arrow key +XWC_DOWN = 5 # down arrow key +XWC_CANCEL = 6 # not reported -- turned into KeyboardInterrupt +XWC_BACKSPACE = 7 # backspace key +XWC_TAB = 8 # tab key +XWC_RETURN = 9 # return or enter key +X +X# Selection numbers +X +XWS_CLIPBOARD = 0 +XWS_PRIMARY = 1 +XWS_SECONDARY = 2 +EOF +fi +if test -s 'lib/sunaudio.py' +then echo '*** I will not over-write existing file lib/sunaudio.py' +else +echo 'x - lib/sunaudio.py' +sed 's/^X//' > 'lib/sunaudio.py' << 'EOF' +X# Module 'sunaudio' -- interpret sun audio headers +X +Ximport audio +X +XMAGIC = '.snd' +X +Xerror = 'sunaudio sound header conversion error' +X +X +X# convert a 4-char value to integer +X +Xdef c2i(data): +X if type(data) <> type('') or len(data) <> 4: +X raise error, 'c2i: bad arg (not string[4])' +X bytes = audio.chr2num(data) +X for i in (1, 2, 3): +X if bytes[i] < 0: +X bytes[i] = bytes[i] + 256 +X return ((bytes[0]*256 + bytes[1])*256 + bytes[2])*256 + bytes[3] +X +X +X# read a sound header from an open file +X +Xdef gethdr(fp): +X if fp.read(4) <> MAGIC: +X raise error, 'gethdr: bad magic word' +X hdr_size = c2i(fp.read(4)) +X data_size = c2i(fp.read(4)) +X encoding = c2i(fp.read(4)) +X sample_rate = c2i(fp.read(4)) +X channels = c2i(fp.read(4)) +X excess = hdr_size - 24 +X if excess < 0: +X raise error, 'gethdr: bad hdr_size' +X if excess > 0: +X info = fp.read(excess) +X else: +X info = '' +X return (data_size, encoding, sample_rate, channels, info) +X +X +X# read and print the sound header of a named file +X +Xdef printhdr(file): +X hdr = gethdr(open(file, 'r')) +X data_size, encoding, sample_rate, channels, info = hdr +X while info[-1:] = '\0': +X info = info[:-1] +X print 'File name: ', file +X print 'Data size: ', data_size +X print 'Encoding: ', encoding +X print 'Sample rate:', sample_rate +X print 'Channels: ', channels +X print 'Info: ', `info` +EOF +fi +if test -s 'lib/whrandom.py' +then echo '*** I will not over-write existing file lib/whrandom.py' +else +echo 'x - lib/whrandom.py' +sed 's/^X//' > 'lib/whrandom.py' << 'EOF' +X# WICHMANN-HILL RANDOM NUMBER GENERATOR +X# +X# Wichmann, B. A. & Hill, I. D. (1982) +X# Algorithm AS 183: +X# An efficient and portable pseudo-random number generator +X# Applied Statistics 31 (1982) 188-190 +X# +X# see also: +X# Correction to Algorithm AS 183 +X# Applied Statistics 33 (1984) 123 +X# +X# McLeod, A. I. (1985) +X# A remark on Algorithm AS 183 +X# Applied Statistics 34 (1985),198-200 +X# +X# +X# USE: +X# whrandom.random() yields double precision random numbers +X# uniformly distributed between 0 and 1. +X# +X# whrandom.seed() must be called before whrandom.random() +X# to seed the generator +X +X +X# Translated by Guido van Rossum from C source provided by +X# Adrian Baddeley. +X +X +X# The seed +X# +X_seed = [0, 0, 0] +X +X +X# Set the seed +X# +Xdef seed(x, y, z): +X _seed[:] = [x, y, z] +X +X +X# Return the next random number in the range [0.0 .. 1.0) +X# +Xdef random(): +X from math import floor # floor() function +X # +X [x, y, z] = _seed +X x = 171 * (x % 177) - 2 * (x/177) +X y = 172 * (y % 176) - 35 * (y/176) +X z = 170 * (z % 178) - 63 * (z/178) +X # +X if x < 0: x = x + 30269 +X if y < 0: y = y + 30307 +X if z < 0: z = z + 30323 +X # +X _seed[:] = [x, y, z] +X # +X term = float(x)/30269.0 + float(y)/30307.0 + float(z)/30323.0 +X rand = term - floor(term) +X # +X if rand >= 1.0: rand = 0.0 # floor() inaccuracy? +X # +X return rand +X +X +X# Initialize from the current time +X# +Xdef init(): +X import time +X t = time.time() +X seed(t%256, t/256%256, t/65536%256) +X +X +X# Make sure the generator is preset to a nonzero value +X# +Xinit() +EOF +fi +if test -s 'src/README' +then echo '*** I will not over-write existing file src/README' +else +echo 'x - src/README' +sed 's/^X//' > 'src/README' << 'EOF' +XThis directory contains the source for the Python interpreter. +X +XTo build the interpreter, edit the Makefile, follow the instructions +Xthere, and type "make python". +X +XTo use the interpreter, you must set the environment variable PYTHONPATH +Xto point to the directory containing the standard modules. These are +Xdistributed as a sister directory called 'lib' of this source directory. +XTry importing the module 'testall' to see if everything works. +X +XGood Luck! +EOF +fi +if test -s 'src/asa.h' +then echo '*** I will not over-write existing file src/asa.h' +else +echo 'x - src/asa.h' +sed 's/^X//' > 'src/asa.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Interface for asynchronous audio module */ +X +Xextern int asa_init(void); +Xextern void asa_done(void); +Xextern void asa_start_write(char *, int); +Xextern void asa_start_read(char *, int); +Xextern int asa_poll(void); +Xextern int asa_wait(void); +Xextern int asa_cancel(void); +EOF +fi +if test -s 'src/ceval.h' +then echo '*** I will not over-write existing file src/ceval.h' +else +echo 'x - src/ceval.h' +sed 's/^X//' > 'src/ceval.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Interface to execute compiled code */ +X/* This header depends on "compile.h" */ +X +Xobject *eval_code PROTO((codeobject *, object *, object *, object *)); +X +Xobject *getglobals PROTO((void)); +Xobject *getlocals PROTO((void)); +X +Xvoid printtraceback PROTO((FILE *)); +EOF +fi +if test -s 'src/errcode.h' +then echo '*** I will not over-write existing file src/errcode.h' +else +echo 'x - src/errcode.h' +sed 's/^X//' > 'src/errcode.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Error codes passed around between file input, tokenizer, parser and +X interpreter. This was necessary so we can turn them into Python +X exceptions at a higher level. */ +X +X#define E_OK 10 /* No error */ +X#define E_EOF 11 /* (Unexpected) EOF read */ +X#define E_INTR 12 /* Interrupted */ +X#define E_TOKEN 13 /* Bad token */ +X#define E_SYNTAX 14 /* Syntax error */ +X#define E_NOMEM 15 /* Ran out of memory */ +X#define E_DONE 16 /* Parsing complete */ +X#define E_ERROR 17 /* Execution error */ +EOF +fi +if test -s 'src/fileobject.h' +then echo '*** I will not over-write existing file src/fileobject.h' +else +echo 'x - src/fileobject.h' +sed 's/^X//' > 'src/fileobject.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* File object interface */ +X +Xextern typeobject Filetype; +X +X#define is_fileobject(op) ((op)->ob_type == &Filetype) +X +Xextern object *newfileobject PROTO((char *, char *)); +Xextern object *newopenfileobject PROTO((FILE *, char *, char *)); +Xextern FILE *getfilefile PROTO((object *)); +EOF +fi +if test -s 'src/floatobject.h' +then echo '*** I will not over-write existing file src/floatobject.h' +else +echo 'x - src/floatobject.h' +sed 's/^X//' > 'src/floatobject.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Float object interface */ +X +X/* +Xfloatobject represents a (double precision) floating point number. +X*/ +X +Xtypedef struct { +X OB_HEAD +X double ob_fval; +X} floatobject; +X +Xextern typeobject Floattype; +X +X#define is_floatobject(op) ((op)->ob_type == &Floattype) +X +Xextern object *newfloatobject PROTO((double)); +Xextern double getfloatvalue PROTO((object *)); +X +X/* Macro, trading safety for speed */ +X#define GETFLOATVALUE(op) ((op)->ob_fval) +EOF +fi +if test -s 'src/fmod.c' +then echo '*** I will not over-write existing file src/fmod.c' +else +echo 'x - src/fmod.c' +sed 's/^X//' > 'src/fmod.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Portable fmod(x, y) implementation for systems that don't have it */ +X +X#include <math.h> +X#include <errno.h> +X +Xextern int errno; +X +Xdouble +Xfmod(x, y) +X double x, y; +X{ +X double i, f; +X +X if (y == 0.0) { +X errno = EDOM; +X return 0.0; +X } +X +X /* return f such that x = i*y + f for some integer i +X such that |f| < |y| and f has the same sign as x */ +X +X i = floor(x/y); +X f = x - i*y; +X if ((x < 0.0) != (y < 0.0)) +X f = f-y; +X return f; +X} +EOF +fi +if test -s 'src/funcobject.h' +then echo '*** I will not over-write existing file src/funcobject.h' +else +echo 'x - src/funcobject.h' +sed 's/^X//' > 'src/funcobject.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Function object interface */ +X +Xextern typeobject Functype; +X +X#define is_funcobject(op) ((op)->ob_type == &Functype) +X +Xextern object *newfuncobject PROTO((object *, object *)); +Xextern object *getfunccode PROTO((object *)); +Xextern object *getfuncglobals PROTO((object *)); +EOF +fi +if test -s 'src/import.h' +then echo '*** I will not over-write existing file src/import.h' +else +echo 'x - src/import.h' +sed 's/^X//' > 'src/import.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Module definition and import interface */ +X +Xobject *get_modules PROTO((void)); +Xobject *add_module PROTO((char *name)); +Xobject *import_module PROTO((char *name)); +Xobject *reload_module PROTO((object *m)); +Xvoid doneimport PROTO((void)); +EOF +fi +if test -s 'src/metagrammar.h' +then echo '*** I will not over-write existing file src/metagrammar.h' +else +echo 'x - src/metagrammar.h' +sed 's/^X//' > 'src/metagrammar.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X#define MSTART 256 +X#define RULE 257 +X#define RHS 258 +X#define ALT 259 +X#define ITEM 260 +X#define ATOM 261 +EOF +fi +if test -s 'src/methodobject.h' +then echo '*** I will not over-write existing file src/methodobject.h' +else +echo 'x - src/methodobject.h' +sed 's/^X//' > 'src/methodobject.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Method object interface */ +X +Xextern typeobject Methodtype; +X +X#define is_methodobject(op) ((op)->ob_type == &Methodtype) +X +Xtypedef object *(*method) FPROTO((object *, object *)); +X +Xextern object *newmethodobject PROTO((char *, method, object *)); +Xextern method getmethod PROTO((object *)); +Xextern object *getself PROTO((object *)); +X +Xstruct methodlist { +X char *ml_name; +X method ml_meth; +X}; +X +Xextern object *findmethod PROTO((struct methodlist *, object *, char *)); +EOF +fi +if test -s 'src/modsupport.h' +then echo '*** I will not over-write existing file src/modsupport.h' +else +echo 'x - src/modsupport.h' +sed 's/^X//' > 'src/modsupport.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Module support interface */ +X +Xextern object *initmodule PROTO((char *, struct methodlist *)); +EOF +fi +if test -s 'src/moduleobject.h' +then echo '*** I will not over-write existing file src/moduleobject.h' +else +echo 'x - src/moduleobject.h' +sed 's/^X//' > 'src/moduleobject.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Module object interface */ +X +Xextern typeobject Moduletype; +X +X#define is_moduleobject(op) ((op)->ob_type == &Moduletype) +X +Xextern object *newmoduleobject PROTO((char *)); +Xextern object *getmoduledict PROTO((object *)); +Xextern char *getmodulename PROTO((object *)); +EOF +fi +if test -s 'src/parsetok.h' +then echo '*** I will not over-write existing file src/parsetok.h' +else +echo 'x - src/parsetok.h' +sed 's/^X//' > 'src/parsetok.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Parser-tokenizer link interface */ +X +Xextern int parsestring PROTO((char *, grammar *, int start, node **n_ret)); +Xextern int parsefile PROTO((FILE *, char *, grammar *, int start, +X char *ps1, char *ps2, node **n_ret)); +EOF +fi +if test -s 'src/pgen.h' +then echo '*** I will not over-write existing file src/pgen.h' +else +echo 'x - src/pgen.h' +sed 's/^X//' > 'src/pgen.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Parser generator interface */ +X +Xextern grammar gram; +X +Xextern grammar *meta_grammar PROTO((void)); +Xextern grammar *pgen PROTO((struct _node *)); +EOF +fi +if test -s 'src/regmagic.h' +then echo '*** I will not over-write existing file src/regmagic.h' +else +echo 'x - src/regmagic.h' +sed 's/^X//' > 'src/regmagic.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* +X * The first byte of the regexp internal "program" is actually this magic +X * number; the start node begins in the second byte. +X */ +X#define MAGIC 0234 +EOF +fi +if test -s 'src/sc_errors.h' +then echo '*** I will not over-write existing file src/sc_errors.h' +else +echo 'x - src/sc_errors.h' +sed 's/^X//' > 'src/sc_errors.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X +X#define NoBufSize 1 +X#define TwoBufSize 2 +X#define StackOverflow 3 +X#define StackUnderflow 4 +X#define TypeFailure 5 +X#define RangeError 6 +X#define SizeError 7 +X#define BufferOverflow 8 +X#define NoEndLoop 9 +X#define FlagError 10 +X#define ElementIsNull 11 +X#define TransError 12 +X +Xextern object *err_scerr PROTO((int sc_errno)); +Xextern err_scerrset PROTO((int sc_errno, object *value, char *instr)); +Xextern object *StubcodeError; +EOF +fi +if test -s 'src/stdwinobject.h' +then echo '*** I will not over-write existing file src/stdwinobject.h' +else +echo 'x - src/stdwinobject.h' +sed 's/^X//' > 'src/stdwinobject.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Stdwin object interface */ +X +Xextern typeobject Stdwintype; +X +X#define is_stdwinobject(op) ((op)->ob_type == &Stdwintype) +X +Xextern object *newstdwinobject PROTO((void)); +EOF +fi +if test -s 'src/strdup.c' +then echo '*** I will not over-write existing file src/strdup.c' +else +echo 'x - src/strdup.c' +sed 's/^X//' > 'src/strdup.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X#include "PROTO.h" +X#include "malloc.h" +X#include "string.h" +X +Xchar * +Xstrdup(str) +X const char *str; +X{ +X if (str != NULL) { +X register char *copy = NEW(char, strlen(str) + 1); +X if (copy != NULL) +X return strcpy(copy, str); +X } +X return NULL; +X} +EOF +fi +if test -s 'src/strerror.c' +then echo '*** I will not over-write existing file src/strerror.c' +else +echo 'x - src/strerror.c' +sed 's/^X//' > 'src/strerror.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* PD implementation of strerror() for systems that don't have it. +X Author: Guido van Rossum, CWI Amsterdam, Oct. 1990, <[email protected]>. */ +X +X#include <stdio.h> +X +Xextern int sys_nerr; +Xextern char *sys_errlist[]; +X +Xchar * +Xstrerror(err) +X int err; +X{ +X static char buf[20]; +X if (err >= 0 && err < sys_nerr) +X return sys_errlist[err]; +X sprintf(buf, "Unknown errno %d", err); +X return buf; +X} +X +X#ifdef THINK_C +Xint sys_nerr = 0; +Xchar *sys_errlist[1] = 0; +X#endif +EOF +fi +if test -s 'src/sysmodule.h' +then echo '*** I will not over-write existing file src/sysmodule.h' +else +echo 'x - src/sysmodule.h' +sed 's/^X//' > 'src/sysmodule.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* System module interface */ +X +Xobject *sysget PROTO((char *)); +Xint sysset PROTO((char *, object *)); +XFILE *sysgetfile PROTO((char *, FILE *)); +Xvoid initsys PROTO((void)); +EOF +fi +if test -s 'src/traceback.h' +then echo '*** I will not over-write existing file src/traceback.h' +else +echo 'x - src/traceback.h' +sed 's/^X//' > 'src/traceback.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Traceback interface */ +X +Xint tb_here PROTO((struct _frame *, int, int)); +Xobject *tb_fetch PROTO((void)); +Xint tb_store PROTO((object *)); +Xint tb_print PROTO((object *, FILE *)); +EOF +fi +echo 'Part 20 out of 21 of pack.out complete.' +exit 0 diff --git a/shar/python-0.9.1-21-21.shar b/shar/python-0.9.1-21-21.shar new file mode 100644 index 0000000..5e50481 --- /dev/null +++ b/shar/python-0.9.1-21-21.shar @@ -0,0 +1,1675 @@ +: This is a shell archive. +: Extract with 'sh this_file'. +: +: Extract part 01 first since it makes all directories +echo 'Start of pack.out, part 21 out of 21:' +if test -s 'demo/README' +then echo '*** I will not over-write existing file demo/README' +else +echo 'x - demo/README' +sed 's/^X//' > 'demo/README' << 'EOF' +XThis directory contains various demonstrations of what you can do with +XPython. The demos are grouped sub(sub*)directories according to +Xrequired optional built-in modules. +X +Xscripts Some useful Python scripts that I put in my bin +X directory. No optional built-in modules meeded. +X +Xsgi Demos that only run on Silicon Graphics machines. +X Require the built-in modules 'audio' and/or 'gl'. +X +Xstdwin Demos that use the STDWIN library. Require the 'stdwin' +X built-in module. +X +XWARNING: some scripts are executable and have a first line saying +X +X #! /ufs/guido/bin/sgi/python +X +XThis is unlikely to give good results anywhere else except in my +Xoffice. Edit the first line before installing such scripts; to try +Xthem out, you can just say "python file.py". (The .py suffix is not +Xnecessary in this case, but makes it possible to debug the modules +Xinteractively by importing them.) +EOF +fi +if test -s 'demo/scripts/findlinksto.py' +then echo '*** I will not over-write existing file demo/scripts/findlinksto.py' +else +echo 'x - demo/scripts/findlinksto.py' +sed 's/^X//' > 'demo/scripts/findlinksto.py' << 'EOF' +X#! /ufs/guido/bin/sgi/python +X +X# findlinksto +X# +X# find symbolic links to a given path +X +Ximport posix, path, sys +X +Xdef visit(pattern, dirname, names): +X if path.islink(dirname): +X names[:] = [] +X return +X if path.ismount(dirname): +X print 'descend into', dirname +X n = len(pattern) +X for name in names: +X name = path.cat(dirname, name) +X try: +X linkto = posix.readlink(name) +X if linkto[:n] = pattern: +X print name, '->', linkto +X except posix.error: +X pass +X +Xdef main(pattern, args): +X for dirname in args: +X path.walk(dirname, visit, pattern) +X +Xmain(sys.argv[1], sys.argv[2:]) +EOF +chmod +x 'demo/scripts/findlinksto.py' +fi +if test -s 'demo/scripts/suff.py' +then echo '*** I will not over-write existing file demo/scripts/suff.py' +else +echo 'x - demo/scripts/suff.py' +sed 's/^X//' > 'demo/scripts/suff.py' << 'EOF' +X#! /ufs/guido/bin/sgi/python +X +X# suff +X# +X# show different suffixes amongst arguments +X +Ximport sys +X +Xdef main(): +X files = sys.argv[1:] +X suffixes = {} +X for file in files: +X suff = getsuffix(file) +X if not suffixes.has_key(suff): +X suffixes[suff] = [] +X suffixes[suff].append(file) +X keys = suffixes.keys() +X keys.sort() +X for suff in keys: +X print `suff`, len(suffixes[suff]) +X +Xdef getsuffix(file): +X suff = '' +X for i in range(len(file)): +X if file[i] = '.': +X suff = file[i:] +X return suff +X +Xmain() +EOF +chmod +x 'demo/scripts/suff.py' +fi +if test -s 'demo/sgi/README' +then echo '*** I will not over-write existing file demo/sgi/README' +else +echo 'x - demo/sgi/README' +sed 's/^X//' > 'demo/sgi/README' << 'EOF' +XDemonstrations of Python that use various features of the Silicon +XGraphics IRIS machines. +X +Xaudio Demonstrations of the audio capabilities of the 4D/25. +X Require the built-in module 'audio'. +X +Xaudio_stdwin Window-based demonstrations the audio capabilities of +X the 4D/25. Require the built-in modules 'stdwin' and +X 'audio'. +X +Xgl Demonstrations of the Graphics Library (GL). +X Require the built-in module 'gl'. +X +Xgl_panel Demonstrations of the Panel Library by NASA Ames. +X Require the built-in modules 'gl' and 'pnl'. +EOF +fi +if test -s 'demo/sgi/audio/README' +then echo '*** I will not over-write existing file demo/sgi/audio/README' +else +echo 'x - demo/sgi/audio/README' +sed 's/^X//' > 'demo/sgi/audio/README' << 'EOF' +XPrograms that demonstrate the use of the audio device on the SGI 4D/25. +XThese require the built-in module 'audio'. +X +Xplay Read a sound sample from a file and play it through the +X speaker. Options to set volume, sampling rate etc. +EOF +fi +if test -s 'demo/sgi/audio_stdwin/vumeter.py' +then echo '*** I will not over-write existing file demo/sgi/audio_stdwin/vumeter.py' +else +echo 'x - demo/sgi/audio_stdwin/vumeter.py' +sed 's/^X//' > 'demo/sgi/audio_stdwin/vumeter.py' << 'EOF' +X#! /ufs/guido/bin/sgi/python +X +Ximport audio +Ximport stdwin +X +Xfrom VUMeter import VUMeter +Xfrom WindowParent import WindowParent +Ximport MainLoop +X +XNBUFS=20 +XBUFSIZE = NBUFS*48 +XSCALE=128 +X +Xclass MyVUMeter() = VUMeter(): +X def init_reactivity(self): +X self.parent.need_mouse(self) +X def mouse_down(self, detail): +X if self.enabled: +X self.stop() +X else: +X self.start() +X def mouse_move(self, detail): pass +X def mouse_up(self, detail): pass +X +Xdef main(): +X audio.setrate(3) +X audio.setoutgain(0) +X w = WindowParent().create('VU Meter', (200, 100)) +X v = MyVUMeter().define(w) +X v.start() +X w.realize() +X while 1: +X w.dispatch(stdwin.getevent()) +X +Xmain() +EOF +chmod +x 'demo/sgi/audio_stdwin/vumeter.py' +fi +if test -s 'demo/sgi/gl/README' +then echo '*** I will not over-write existing file demo/sgi/gl/README' +else +echo 'x - demo/sgi/gl/README' +sed 's/^X//' > 'demo/sgi/gl/README' << 'EOF' +XThese demos run only on SGI machines and require the 'gl' built-in module. +XThe demonstrate the abilities of SGI's GL library as well as the ease of +XGL programming in Python. Most demos require the Z-buffer (aka +X24-bitplane) option. +X +Xbackface Demonstrates the 'backface' GL function. +X +Xkites Show 3 flying kites. Demonstrates the rendering speed +X obtainable by Python programs. +X +Xmclock A colorful clock with more options than you can +X remember. Works on 8-bit machines (but allows more +X colors on 24-bit machines). +X +Xmixing Demonstrates the effect of color mixing: through +X frequent color switching it gives the effect of white +X light. +X +Xnurbs A simple demonstration of the 'nurbs' GL functions. +X +Xzrgb Displays a 3-D Gouraud-shaded figure which can be moved +X around with the mouse. +EOF +fi +if test -s 'demo/sgi/gl_panel/README' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/README' +else +echo 'x - demo/sgi/gl_panel/README' +sed 's/^X//' > 'demo/sgi/gl_panel/README' << 'EOF' +XThis directory contains demos that use the Panel Library by NASA Ames. +XThey only run on SGI machines and require the 'pnl' and 'gl' built-in +Xmodules. Each subdirectory contains one demo. +X +Xapanel A trivial user interface to the audio capabilities of +X the 4D/25 (Personal IRIS). Lets you record a sample and +X play it back at different volumes. Requires the 'audio' +X built-in module. +X +Xflying A large demonstration that can display several +X differently shaped objects through space. Control +X panels let you manipulate light sources, material +X properties and drawing modes. +X +Xnurbs A demo of the capabilities of the GL 'nurbs' functions +X that can display the control points. (It was intended +X to let you move these as well, but there was a problem +X with the mapping of mouse movements in a 3-D world.) +X +Xtwoview A demo of GL's transformation primitives. Two views on +X a scene are given, and the position and orientation of a +X viewer in one of the views can be changed through +X various buttons and dials in a control panel. +EOF +fi +if test -s 'demo/sgi/gl_panel/apanel/apanel.py' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/apanel/apanel.py' +else +echo 'x - demo/sgi/gl_panel/apanel/apanel.py' +sed 's/^X//' > 'demo/sgi/gl_panel/apanel/apanel.py' << 'EOF' +X#! /ufs/guido/bin/sgi/python +X +X# A (too) trivial control panel to record a sound sample and play it back. +X# Requires the audio built-in module. +X# Requires the NASA AMES Panel Library. +X +Ximport sys +X +Ximport gl +Ximport panel +X +Xpanel.block(1) +X +Ximport audio +X +Xdef main(): +X gl.foreground() +X gl.noport() +X #gl.prefposition(700, 850, 950, 970) +X wid = gl.winopen('audio demo') +X # +X panels = panel.defpanellist('apanel.s') # XXX +X p = panels[0] +X p.playbackbutton.back = p +X p.recordbutton.back = p +X p.sample = '' +X # +X def quit(a): +X sys.exit(0) +X # +X p.quitbutton.downfunc = quit +X # +X def playback(a): +X p = a.back +X gain = int(255.0*p.outputgain.val) +X a.val = 1.0 +X a.fixact() +X panel.drawpanel() +X audio.setoutgain(gain) +X audio.write(p.sample) +X audio.setoutgain(0) +X a.val = 0.0 +X a.fixact() +X # +X p.playbackbutton.downfunc = playback +X # +X def record(a): +X p = a.back +X size = int(10.0 * 8192.0 * p.recordsize.val) +X a.val = 1.0 +X a.fixact() +X panel.drawpanel() +X audio.setoutgain(0) +X p.sample = audio.read(size) +X a.val = 0.0 +X a.fixact() +X # +X p.recordbutton.downfunc = record +X # +X while 1: +X act = panel.dopanel() +X +Xmain() +EOF +chmod +x 'demo/sgi/gl_panel/apanel/apanel.py' +fi +if test -s 'demo/sgi/gl_panel/flying/material.py' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/flying/material.py' +else +echo 'x - demo/sgi/gl_panel/flying/material.py' +sed 's/^X//' > 'demo/sgi/gl_panel/flying/material.py' << 'EOF' +Ximport light +X +Xdef mkmatdict () : +X m = {} +X m['material 1'] = light.m1 +X m['material 2'] = light.m2 +X m['material 3'] = light.m3 +X m['material 4'] = light.m4 +X m['material 5'] = light.m5 +X m['material 6'] = light.m6 +X m['material 7'] = light.m7 +X m['material 8'] = light.m8 +X m['material 9'] = light.m9 +X # +X return m +X +Xmaterdict = mkmatdict () +X +Xdef mklichtdict () : +X m = {} +X m['light 1'] = light.light1 +X m['light 2'] = light.light2 +X # +X return m +X +Xlichtdict = mklichtdict () +EOF +fi +if test -s 'demo/sgi/gl_panel/flying/objdict.py' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/flying/objdict.py' +else +echo 'x - demo/sgi/gl_panel/flying/objdict.py' +sed 's/^X//' > 'demo/sgi/gl_panel/flying/objdict.py' << 'EOF' +X +Xfrom data import * +X +X# +X#the color light-blue +X# +XLightBlue = lightblue +X +X# the 'object' dictionary contains the strings of the menu items +X# that denote the objects +Xobjects = {} +X +X# object dictionary initialization +Xobjects['sphere'] = [ZERO, o1] +Xobjects['cylinder'] = [ZERO, o2] +Xobjects['cube'] = [ONE, o3] +Xobjects['icecream'] = [ZERO, o4] +Xobjects['disk'] = [ZERO, o5] +Xobjects['diamond'] = [ZERO, o6] +X#objects['glass'] = [ZERO] +Xobjects['pyramid'] = [ZERO, o7] +Xobjects['table'] = [ZERO, o8] +X +X# 'putDict' sets the value of entry 'key' of dictionary 'dict' +Xdef putDict(dict, key, val) : +X dict[key][0] = val +X +X# +X# 'getDict' get the contents of entry i of key 'key' +X# of dictionary 'dict' +X# +Xdef getDict(dict, key, i) : +X return dict[key][i] +X +X# the 'options' dictionary contains the strings of the menu items +X# that denote the options +Xoptions = {} +X +X# option dictionary initialization +Xoptions['wire'] = [ZERO] +Xoptions['filled'] = [ONE] +EOF +fi +if test -s 'demo/sgi/gl_panel/twoview/topview.s' +then echo '*** I will not over-write existing file demo/sgi/gl_panel/twoview/topview.s' +else +echo 'x - demo/sgi/gl_panel/twoview/topview.s' +sed 's/^X//' > 'demo/sgi/gl_panel/twoview/topview.s' << 'EOF' +X;;; This file was automatically generated by the panel editor. +X;;; If you read it into gnu emacs, it will automagically format itself. +X +X(panel (prop help creator:user-panel-help) +X(prop user-panel #t) +X(label "Top View Control") +X(x 1020) +X(y 287) +X(al (pnl_hslider (name "xpos") +X(prop help creator:user-act-help) +X(label "X") +X(x 2) +X(y 0.5) +X(w 3.85) +X(h 0.4) +X(val 0.5) +X(downfunc move-then-resize) +X) +X(pnl_vslider (name "zpos") +X(prop help creator:user-act-help) +X(label "Z") +X(x 1.25) +X(y 1.3) +X(w 0.4) +X(h 3.6) +X(val 0.5) +X(downfunc move-then-resize) +X) +X(pnl_dial (name "direction") +X(prop help creator:user-act-help) +X(label "looking direction") +X(x 2.15) +X(y 1.4) +X(w 3.5) +X(h 3.45) +X(val 0.5) +X(downfunc move-then-resize) +X) +X) +X) +X;;; Local Variables: +X;;; mode: scheme +X;;; eval: (save-excursion (goto-char (point-min)) (kill-line 3)) +X;;; eval: (save-excursion (goto-char (point-min)) (replace-regexp "[ \n]*)" ")")) +X;;; eval: (indent-region (point-min) (point-max) nil) +X;;; eval: (progn (kill-line -3) (delete-backward-char 1) (save-buffer)) +X;;; End: +EOF +fi +if test -s 'doc/README' +then echo '*** I will not over-write existing file doc/README' +else +echo 'x - doc/README' +sed 's/^X//' > 'doc/README' << 'EOF' +XThis directory contains the LaTeX source to the Python documentation. +XThe documentation is not all finished, but good enough to get you +Xstarted. +X +XThe following are the important latex source files: +X +X tut.tex A tutorial +X mod.tex The library reference +X +XThey both read the style option file "myformat.sty". +X +XYou can use the Makefile to format, preview and print the documents. +XType "make tut" or "make mod" to preview either document with xdvi. +XType "make print" to print them both (this only works if your print +Xspooler is set up just like mine...), or "make all" to create postscript +Xfiles that you can you can print using your local printing commands. +XType "make clean" to get rid of all the intermediate files produced by +Xthe latex process, and other junk files. +X +XYou can just as well ignore the Makefile; all you really need is: +X latex tut +X latex tut +X dvips tut | lpr +Xand similar for the "mod" document. +EOF +fi +if test -s 'doc/SetClass.py' +then echo '*** I will not over-write existing file doc/SetClass.py' +else +echo 'x - doc/SetClass.py' +sed 's/^X//' > 'doc/SetClass.py' << 'EOF' +Xclass Set(): +X def new(self): +X self.elements = [] +X return self +X def add(self, e): +X if e not in self.elements: +X self.elements.append(e) +X def remove(self, e): +X if e in self.elements: +X for i in range(len(self.elements)): +X if self.elements[i] = e: +X del self.elements[i] +X break +X def is_element(self, e): +X return e in self.elements +X def size(self): +X return len(self.elements) +EOF +fi +if test -s 'doc/fibo.py' +then echo '*** I will not over-write existing file doc/fibo.py' +else +echo 'x - doc/fibo.py' +sed 's/^X//' > 'doc/fibo.py' << 'EOF' +X# Fibonacci numbers demo +X +Xdef fib(n): # write Fibonacci series up to n +X a, b = 0, 1 +X while b <= n: +X print b, +X a, b = b, a+b +X +Xdef fib2(n): # return Fibonacci series up to n +X ret = [] +X a, b = 0, 1 +X while b <= n: +X ret.append(b) +X a, b = b, a+b +X return ret +EOF +fi +if test -s 'doc/mod.tex' +then echo '*** I will not over-write existing file doc/mod.tex' +else +echo 'x - doc/mod.tex' +sed 's/^X//' > 'doc/mod.tex' << 'EOF' +X% Format this file with latex. +X +X%\documentstyle[garamond,11pt,myformat]{article} +X\documentstyle[11pt,myformat]{article} +X +X% A command to force the text after an item to start on a new line +X\newcommand{\itembreak}{ +X \mbox{}\\*[0mm] +X} +X +X% A command to define a function item +X\newcommand{\funcitem}[2]{\item[#1(#2)]} +X +X% A command to define an exception item +X\newcommand{\excitem}[2]{ +X\item[#1 = {\tt '#2'}] +X\itembreak +X} +X +X\title{\bf +X Python Library Reference \\ +X (DRAFT) +X} +X +X\author{ +X Guido van Rossum \\ +X Dept. CST, CWI, Kruislaan 413 \\ +X 1098 SJ Amsterdam, The Netherlands \\ +X E-mail: {\tt [email protected]} +X} +X +X\begin{document} +X +X\pagenumbering{roman} +X +X\maketitle +X +X\begin{abstract} +X +X\noindent +XThis document describes the built-in types, exceptions and functions and +Xthe standard modules that come with the {\Python} system. +XIt assumes basic knowledge about the {\Python} language. +XFor an informal introduction to the language, see the Tutorial document. +XThe Language Reference document (XXX not yet existing) +Xgives a more formal reference to the language. +X +X\end{abstract} +X +X\pagebreak +X +X\tableofcontents +X +X\pagebreak +X +X\pagenumbering{arabic} +X +X\input{mod1.tex} +X\input{mod2.tex} +X\input{mod3.tex} +X +X\end{document} +EOF +fi +if test -s 'doc/myformat.sty' +then echo '*** I will not over-write existing file doc/myformat.sty' +else +echo 'x - doc/myformat.sty' +sed 's/^X//' > 'doc/myformat.sty' << 'EOF' +X% Style parameters and macros used by all documents here +X +X% Page lay-out parameters +X\textwidth = 160mm +X\textheight = 240mm +X\topmargin = -11mm +X\oddsidemargin = 0mm +X\evensidemargin = 0mm +X%\parindent = 0mm +X +X% Frequently used system names +X\newcommand{\Python}{Python} % Sometimes I want this italicized +X\newcommand{\UNIX}{U{\sc nix}} +X +X% Variable used by begin code command +X\newlength{\codewidth} +X +X\newcommand{\bcode}{ +X % Calculate the text width for the minipage: +X \setlength{\codewidth}{\linewidth} +X \addtolength{\codewidth}{-\parindent} +X % +X \vspace{3mm} +X \par +X \indent +X \begin{minipage}[t]{\codewidth} +X} +X +X\newcommand{\ecode}{ +X \end{minipage} +X \vspace{3mm} +X \par +X \noindent +X} +EOF +fi +if test -s 'doc/pytry' +then echo '*** I will not over-write existing file doc/pytry' +else +echo 'x - doc/pytry' +sed 's/^X//' > 'doc/pytry' << 'EOF' +XTMP=/usr/tmp/pytry$$ +Xtrap 'rm -f $TMP; exit 1' 1 2 3 13 14 15 +X +Xcat $* >$TMP +X +X( +X cat $TMP +X +X sed ' +X s/^>>> // +X s/^>>>$// +X s/^\.\.\. // +X s/^\.\.\.$// +X ' $TMP | +X python +X +X echo '>>> ' +X) 2>&1 +X +Xrm $TMP +EOF +chmod +x 'doc/pytry' +fi +if test -s 'lib/Histogram.py' +then echo '*** I will not over-write existing file lib/Histogram.py' +else +echo 'x - lib/Histogram.py' +sed 's/^X//' > 'lib/Histogram.py' << 'EOF' +X# Module 'Histogram' +X +Xfrom Buttons import * +X +X# A Histogram displays a histogram of numeric data. +X# +Xclass HistogramAppearance() = LabelAppearance(), Define(): +X # +X def define(self, parent): +X Define.define(self, (parent, '')) +X self.ydata = [] +X self.scale = (0, 100) +X return self +X # +X def setdata(self, (ydata, scale)): +X self.ydata = ydata +X self.scale = scale # (min, max) +X self.parent.change(self.bounds) +X # +X def drawpict(self, d): +X (left, top), (right, bottom) = self.bounds +X min, max = self.scale +X size = max-min +X width, height = right-left, bottom-top +X ydata = self.ydata +X npoints = len(ydata) +X v1 = top + height # constant +X h1 = left # changed in loop +X for i in range(npoints): +X h0 = h1 +X v0 = top + height - (ydata[i]-min)*height/size +X h1 = left + (i+1) * width/npoints +X d.paint((h0, v0), (h1, v1)) +X # +X +Xclass Histogram() = NoReactivity(), HistogramAppearance(): pass +EOF +fi +if test -s 'lib/Soundogram.py' +then echo '*** I will not over-write existing file lib/Soundogram.py' +else +echo 'x - lib/Soundogram.py' +sed 's/^X//' > 'lib/Soundogram.py' << 'EOF' +X# Module 'Soundogram' +X +Ximport audio +Xfrom Histogram import Histogram +X +Xclass Soundogram() = Histogram(): +X # +X def define(self, (win, chunk)): +X width, height = corner = win.getwinsize() +X bounds = (0, 0), corner +X self.chunk = chunk +X self.step = (len(chunk)-1)/(width/2+1) + 1 +X ydata = _make_ydata(chunk, self.step) +X return Histogram.define(self, (win, bounds, ydata, (0, 128))) +X # +X def setchunk(self, chunk): +X self.chunk = chunk +X self.recompute() +X # +X def recompute(self): +X (left, top), (right, bottom) = self.bounds +X width = right - left +X self.step = (len(chunk)-1)/width + 1 +X ydata = _make_ydata(chunk, self.step) +X self.setdata(ydata, (0, 128)) +X # +X +X +Xdef _make_ydata(chunk, step): +X ydata = [] +X for i in range(0, len(chunk), step): +X piece = audio.chr2num(chunk[i:i+step]) +X mi, ma = min(piece), max(piece) +X y = max(abs(mi), abs(ma)) +X ydata.append(y) +X return ydata +EOF +fi +if test -s 'lib/TestCSplit.py' +then echo '*** I will not over-write existing file lib/TestCSplit.py' +else +echo 'x - lib/TestCSplit.py' +sed 's/^X//' > 'lib/TestCSplit.py' << 'EOF' +X# TestCSplit +X +Ximport stdwin +Xfrom stdwinevents import WE_CLOSE +Xfrom WindowParent import WindowParent +Xfrom Buttons import PushButton +X +Xdef main(n): +X from CSplit import CSplit +X +X the_window = WindowParent().create('TestCSplit', (0, 0)) +X the_csplit = CSplit().create(the_window) +X +X for i in range(n): +X the_child = PushButton().define(the_csplit) +X the_child.settext(`(i+n-1)%n+1`) +X +X the_window.realize() +X +X while 1: +X the_event = stdwin.getevent() +X if the_event[0] = WE_CLOSE: break +X the_window.dispatch(the_event) +X the_window.destroy() +X +Xmain(12) +EOF +fi +if test -s 'lib/VUMeter.py' +then echo '*** I will not over-write existing file lib/VUMeter.py' +else +echo 'x - lib/VUMeter.py' +sed 's/^X//' > 'lib/VUMeter.py' << 'EOF' +X# Module 'VUMeter' +X +Ximport audio +Xfrom StripChart import StripChart +X +XK = 1024 +XRates = [0, 32*K, 16*K, 8*K] +X +Xclass VUMeter() = StripChart(): +X # +X # Override define() and timer() methods +X # +X def define(self, parent): +X self = StripChart.define(self, (parent, 128)) +X self.parent.need_timer(self) +X self.sampling = 0 +X self.rate = 3 +X self.enable(0) +X return self +X # +X def timer(self): +X if self.sampling: +X chunk = audio.wait_recording() +X self.sampling = 0 +X nums = audio.chr2num(chunk) +X ampl = max(abs(min(nums)), abs(max(nums))) +X self.append(ampl) +X if self.enabled and not self.sampling: +X audio.setrate(self.rate) +X size = Rates[self.rate]/10 +X size = size/48*48 +X audio.start_recording(size) +X self.sampling = 1 +X if self.sampling: +X self.parent.settimer(1) +X # +X # New methods: start() and stop() +X # +X def stop(self): +X if self.sampling: +X chunk = audio.stop_recording() +X self.sampling = 0 +X self.enable(0) +X # +X def start(self): +X self.enable(1) +X self.timer() +EOF +fi +if test -s 'lib/anywin.py' +then echo '*** I will not over-write existing file lib/anywin.py' +else +echo 'x - lib/anywin.py' +sed 's/^X//' > 'lib/anywin.py' << 'EOF' +X# Module 'anywin' +X# Open a file or directory in a window +X +Ximport dirwin +Ximport filewin +Ximport path +X +Xdef open(name): +X print 'opening', name, '...' +X if path.isdir(name): +X w = dirwin.open(name) +X else: +X w = filewin.open(name) +X return w +EOF +fi +if test -s 'lib/dircache.py' +then echo '*** I will not over-write existing file lib/dircache.py' +else +echo 'x - lib/dircache.py' +sed 's/^X//' > 'lib/dircache.py' << 'EOF' +X# Module 'dircache' +X# +X# Return a sorted list of the files in a POSIX directory, using a cache +X# to avoid reading the directory more often than necessary. +X# Also contains a subroutine to append slashes to directories. +X +Ximport posix +Ximport path +X +Xcache = {} +X +Xdef listdir(path): # List directory contents, using cache +X try: +X cached_mtime, list = cache[path] +X del cache[path] +X except RuntimeError: +X cached_mtime, list = -1, [] +X try: +X mtime = posix.stat(path)[8] +X except posix.error: +X return [] +X if mtime <> cached_mtime: +X try: +X list = posix.listdir(path) +X except posix.error: +X return [] +X list.sort() +X cache[path] = mtime, list +X return list +X +Xopendir = listdir # XXX backward compatibility +X +Xdef annotate(head, list): # Add '/' suffixes to directories +X for i in range(len(list)): +X if path.isdir(path.cat(head, list[i])): +X list[i] = list[i] + '/' +EOF +fi +if test -s 'lib/dirwin.py' +then echo '*** I will not over-write existing file lib/dirwin.py' +else +echo 'x - lib/dirwin.py' +sed 's/^X//' > 'lib/dirwin.py' << 'EOF' +X# Module 'dirwin' +X +X# Directory windows, a subclass of listwin +X +Ximport gwin +Ximport listwin +Ximport anywin +Ximport path +Ximport dircache +X +Xdef action(w, string, i, detail): +X (h, v), clicks, button, mask = detail +X if clicks = 2: +X name = path.cat(w.name, string) +X try: +X w2 = anywin.open(name) +X w2.parent = w +X except posix.error, why: +X stdwin.message('Can\'t open ' + name + ': ' + why[1]) +X +Xdef open(name): +X name = path.cat(name, '') +X list = dircache.opendir(name)[:] +X list.sort() +X dircache.annotate(name, list) +X w = listwin.open(name, list) +X w.name = name +X w.action = action +X return w +EOF +fi +if test -s 'lib/fact.py' +then echo '*** I will not over-write existing file lib/fact.py' +else +echo 'x - lib/fact.py' +sed 's/^X//' > 'lib/fact.py' << 'EOF' +X# Factorize numbers -- slow, could use a table of all primes <= 2*16 +X +Ximport sys +Ximport math +X +Xerror = 'fact.error' # exception +X +Xdef fact(n): +X if n < 1: raise error # fact() argument should be >= 1 +X if n = 1: return [] # special case +X res = [] +X _fact(n, 2, res) +X return res +X +Xdef _fact(n, lowest, res): +X highest = int(math.sqrt(float(n+1))) +X for i in range(lowest, highest+1): +X if n%i = 0: +X res.append(i) +X _fact(n/i, i, res) +X break +X else: +X res.append(n) +X +Xdef main(): +X if len(sys.argv) > 1: +X for arg in sys.argv[1:]: +X n = eval(arg) +X print n, fact(n) +X else: +X try: +X while 1: +X print fact(input()) +X except EOFError: +X pass +X +Xmain() +EOF +fi +if test -s 'lib/filewin.py' +then echo '*** I will not over-write existing file lib/filewin.py' +else +echo 'x - lib/filewin.py' +sed 's/^X//' > 'lib/filewin.py' << 'EOF' +X# Module 'filewin' +X# File windows, a subclass of textwin (which is a subclass of gwin) +X +Ximport textwin +Xfrom util import readfile +X +X +X# FILE WINDOW +X +Xdef open_readonly(fn): # Open a file window +X w = textwin.open_readonly(fn, readfile(fn)) +X w.fn = fn +X return w +X +Xdef open(fn): # Open a file window +X w = textwin.open(fn, readfile(fn)) +X w.fn = fn +X return w +EOF +fi +if test -s 'lib/fnmatch.py' +then echo '*** I will not over-write existing file lib/fnmatch.py' +else +echo 'x - lib/fnmatch.py' +sed 's/^X//' > 'lib/fnmatch.py' << 'EOF' +X# module 'fnmatch' -- filename matching with shell patterns +X +X# XXX [] patterns are not supported (but recognized) +X +Xdef fnmatch(name, pat): +X if '*' in pat or '?' in pat or '[' in pat: +X return fnmatch1(name, pat) +X return name = pat +X +Xdef fnmatch1(name, pat): +X for i in range(len(pat)): +X c = pat[i] +X if c = '*': +X restpat = pat[i+1:] +X if '*' in restpat or '?' in restpat or '[' in restpat: +X for i in range(i, len(name)): +X if fnmatch1(name[i:], restpat): +X return 1 +X return 0 +X else: +X return name[len(name)-len(restpat):] = restpat +X elif c = '?': +X if len(name) <= i : return 0 +X elif c = '[': +X return 0 # XXX +X else: +X if name[i:i+1] <> c: +X return 0 +X return 1 +X +Xdef fnmatchlist(names, pat): +X res = [] +X for name in names: +X if fnmatch(name, pat): res.append(name) +X return res +EOF +fi +if test -s 'lib/glob.py' +then echo '*** I will not over-write existing file lib/glob.py' +else +echo 'x - lib/glob.py' +sed 's/^X//' > 'lib/glob.py' << 'EOF' +X# Module 'glob' -- filename globbing. +X +Ximport posix +Ximport path +Ximport fnmatch +X +Xdef glob(pathname): +X if not has_magic(pathname): return [pathname] +X dirname, basename = path.split(pathname) +X if dirname[-1:] = '/' and dirname <> '/': +X dirname = dirname[:-1] +X if has_magic(dirname): +X list = glob(dirname) +X else: +X list = [dirname] +X if not has_magic(basename): +X result = [] +X for dirname in list: +X if basename or path.isdir(dirname): +X name = path.cat(dirname, basename) +X if path.exists(name): +X result.append(name) +X else: +X result = [] +X for dirname in list: +X sublist = glob1(dirname, basename) +X for name in sublist: +X result.append(path.cat(dirname, name)) +X return result +X +Xdef glob1(dirname, pattern): +X if not dirname: dirname = '.' +X try: +X names = posix.listdir(dirname) +X except posix.error: +X return [] +X result = [] +X for name in names: +X if name[0] <> '.' or pattern[0] = '.': +X if fnmatch.fnmatch(name, pattern): result.append(name) +X return result +X +Xdef has_magic(s): +X return '*' in s or '?' in s or '[' in s +EOF +fi +if test -s 'lib/grep.py' +then echo '*** I will not over-write existing file lib/grep.py' +else +echo 'x - lib/grep.py' +sed 's/^X//' > 'lib/grep.py' << 'EOF' +X# 'grep' +X +Ximport regexp +Ximport string +X +Xdef grep(expr, filename): +X prog = regexp.compile(expr) +X fp = open(filename, 'r') +X lineno = 0 +X while 1: +X line = fp.readline() +X if not line: break +X lineno = lineno + 1 +X res = prog.exec(line) +X if res: +X #print res +X start, end = res[0] +X if line[-1:] = '\n': line = line[:-1] +X prefix = string.rjust(`lineno`, 3) + ': ' +X print prefix + line +X if 0: +X line = line[:start] +X if '\t' not in line: +X prefix = ' ' * (len(prefix) + start) +X else: +X prefix = ' ' * len(prefix) +X for c in line: +X if c <> '\t': c = ' ' +X prefix = prefix + c +X if start = end: prefix = prefix + '\\' +X else: prefix = prefix + '^'*(end-start) +X print prefix +EOF +fi +if test -s 'lib/maccache.py' +then echo '*** I will not over-write existing file lib/maccache.py' +else +echo 'x - lib/maccache.py' +sed 's/^X//' > 'lib/maccache.py' << 'EOF' +X# Module 'maccache' +X# +X# Maintain a cache of listdir(), isdir(), isfile() or exists() outcomes. +X +Ximport mac +Ximport macpath +X +X +X# The cache. +X# Keys are absolute pathnames; +X# values are 0 (nothing), 1 (file) or [...] (dir). +X# +Xcache = {} +X +X +X# Current working directory. +X# +Xcwd = mac.getcwd() +X +X +X# Constants. +X# +XNONE = 0 +XFILE = 1 +XLISTTYPE = type([]) +X +Xdef _stat(name): +X name = macpath.cat(cwd, name) +X if cache.has_key(name): +X return cache[name] +X if macpath.isfile(name): +X cache[name] = FILE +X return FILE +X try: +X list = mac.listdir(name) +X except: +X cache[name] = NONE +X return NONE +X cache[name] = list +X if name[-1:] = ':': cache[name[:-1]] = list +X else: cache[name+':'] = list +X return list +X +Xdef isdir(name): +X st = _stat(name) +X return type(st) = LISTTYPE +X +Xdef isfile(name): +X st = _stat(name) +X return st = FILE +X +Xdef exists(name): +X st = _stat(name) +X return st <> NONE +X +Xdef listdir(name): +X st = _stat(name) +X if type(st) = LISTTYPE: +X return st +X else: +X raise RuntimeError, 'list non-directory' +EOF +fi +if test -s 'lib/macglob.py' +then echo '*** I will not over-write existing file lib/macglob.py' +else +echo 'x - lib/macglob.py' +sed 's/^X//' > 'lib/macglob.py' << 'EOF' +X# Module 'macglob' -- version of 'glob' for the Macintosh. +X +X# XXX At least one bug is left: a pattern like '*:' is treated +X# XXX as a relative pathname (and returns as if it was ':*:'). +X +Ximport mac +Ximport macpath +Ximport fnmatch +X +Xdef glob(pathname): +X if not has_magic(pathname): return [pathname] +X dirname, basename = macpath.split(pathname) +X if has_magic(dirname): +X if dirname[-1:] = ':': dirname = dirname[:-1] +X list = glob(dirname) +X else: +X list = [dirname] +X if not has_magic(basename): +X result = [] +X for dirname in list: +X if basename or macpath.isdir(dirname): +X name = macpath.cat(dirname, basename) +X if macpath.exists(name): +X result.append(name) +X else: +X result = [] +X for dirname in list: +X sublist = glob1(dirname, basename) +X for name in sublist: +X result.append(macpath.cat(dirname, name)) +X return result +X +Xdef glob1(dirname, pattern): +X if not dirname: dirname = ':' +X try: +X names = mac.listdir(dirname) +X except mac.error: +X return [] +X result = [] +X for name in names: +X if name[0] <> '.' or pattern[0] = '.': +X if fnmatch.fnmatch(name, pattern): result.append(name) +X return result +X +Xdef has_magic(s): +X return '*' in s or '?' in s or '[' in s +EOF +fi +if test -s 'lib/minmax.py' +then echo '*** I will not over-write existing file lib/minmax.py' +else +echo 'x - lib/minmax.py' +sed 's/^X//' > 'lib/minmax.py' << 'EOF' +X# Module 'minmax' +X# These are now built in functions. +X# For compatibility, we export the builtins +X +Xmin = min +Xmax = max +EOF +fi +if test -s 'lib/packmail.py' +then echo '*** I will not over-write existing file lib/packmail.py' +else +echo 'x - lib/packmail.py' +sed 's/^X//' > 'lib/packmail.py' << 'EOF' +X# Module 'packmail' -- create a shell script out of some files. +X +Ximport mac +Ximport macpath +Xfrom stat import ST_MTIME +X +X# Pack one file +Xdef pack(outfp, file, name): +X fp = open(file, 'r') +X outfp.write('sed "s/^X//" >' + name + ' <<"!"\n') +X while 1: +X line = fp.readline() +X if not line: break +X if line[-1:] <> '\n': +X line = line + '\n' +X outfp.write('X' + line) +X outfp.write('!\n') +X +X# Pack some files from a directory +Xdef packsome(outfp, dirname, names): +X for name in names: +X print name +X file = macpath.cat(dirname, name) +X pack(outfp, file, name) +X +X# Pack all files from a directory +Xdef packall(outfp, dirname): +X names = mac.listdir(dirname) +X names.sort() +X packsome(outfp, dirname, names) +X +X# Pack all files from a directory that are not older than a give one +Xdef packnotolder(outfp, dirname, oldest): +X names = mac.listdir(dirname) +X oldest = macpath.cat(dirname, oldest) +X st = mac.stat(oldest) +X mtime = st[ST_MTIME] +X todo = [] +X for name in names: +X print name, '...', +X st = mac.stat(macpath.cat(dirname, name)) +X if st[ST_MTIME] >= mtime: +X print 'Yes.' +X todo.append(name) +X else: +X print 'No.' +X todo.sort() +X packsome(outfp, dirname, todo) +EOF +fi +if test -s 'lib/rand.py' +then echo '*** I will not over-write existing file lib/rand.py' +else +echo 'x - lib/rand.py' +sed 's/^X//' > 'lib/rand.py' << 'EOF' +X# Module 'rand' +X +Ximport whrandom +X +Xdef srand(seed): +X whrandom.seed(seed%256, seed/256%256, seed/65536%256) +X +Xdef rand(): +X return int(whrandom.random() * 32768.0) % 32768 +X +Xdef choice(seq): +X return seq[rand() % len(seq)] +EOF +fi +if test -s 'lib/stat.py' +then echo '*** I will not over-write existing file lib/stat.py' +else +echo 'x - lib/stat.py' +sed 's/^X//' > 'lib/stat.py' << 'EOF' +X# Module 'stat' +X +X# Defines constants and functions for interpreting stat/lstat struct +X# as returned by posix.stat() and posix.lstat() (if it exists). +X +X# XXX This module may have to be adapted for UNIXoid systems whose +X# <sys/stat.h> deviates from AT&T or BSD UNIX; their S_IF* constants +X# may differ. +X +X# Suggested usage: from stat import * +X +X# Tuple indices for stat struct members +X +XST_MODE = 0 +XST_INO = 1 +XST_DEV = 2 +XST_NLINK = 3 +XST_UID = 4 +XST_GID = 5 +XST_SIZE = 6 +XST_ATIME = 7 +XST_MTIME = 8 +XST_CTIME = 9 +X +Xdef S_IMODE(mode): +X return mode%4096 +Xdef S_IFMT(mode): +X return mode - mode%4096 +X +XS_IFDIR = 0040000 +XS_IFCHR = 0020000 +XS_IFBLK = 0060000 +XS_IFREG = 0100000 +XS_IFIFO = 0010000 +XS_IFLNK = 0120000 +XS_IFSOCK = 0140000 +X +Xdef S_ISDIR(mode): +X return S_IFMT(mode) = S_IFDIR +X +Xdef S_ISCHR(mode): +X return S_IFMT(mode) = S_IFCHR +X +Xdef S_ISBLK(mode): +X return S_IFMT(mode) = S_IFBLK +X +Xdef S_ISREG(mode): +X return S_IFMT(mode) = S_IFREG +X +Xdef S_ISFIFO(mode): +X return S_IFMT(mode) = S_IFIFO +X +Xdef S_ISLNK(mode): +X return S_IFMT(mode) = S_IFLNK +X +Xdef S_ISSOCK(mode): +X return S_IFMT(mode) = S_IFSOCK +EOF +fi +if test -s 'lib/stdwinsupport.py' +then echo '*** I will not over-write existing file lib/stdwinsupport.py' +else +echo 'x - lib/stdwinsupport.py' +sed 's/^X//' > 'lib/stdwinsupport.py' << 'EOF' +X# Module 'stdwinsupport' +X +Ximport stdwin +X +Xeventnames = ['null', 'activate', 'char', 'command'] +Xeventnames = eventnames + ['mouse_down', 'mouse_move', 'mouse_up', 'menu'] +Xeventnames = eventnames + ['size', 'move', 'draw', 'timer', 'deactivate'] +X +Xwe_null = 0 +Xwe_activate = 1 +Xwe_char = 2 +Xwe_command = 3 +Xwe_mouse_down = 4 +Xwe_mouse_move = 5 +Xwe_mouse_up = 6 +Xwe_menu = 7 +Xwe_size = 8 +Xwe_move = 9 +Xwe_draw = 10 +Xwe_timer = 11 +Xwe_deactivate = 12 +X +Xcommandnames = ['?', 'close', 'left', 'right', 'up', 'down', 'cancel'] +Xcommandnames = commandnames + ['backspace', 'tab', 'return'] +X +Xwc_close = 1 +Xwc_left = 2 +Xwc_right = 3 +Xwc_up = 4 +Xwc_down = 5 +Xwc_cancel = 6 # not reported -- turned into KeyboardInterrupt +Xwc_backspace = 7 +Xwc_tab = 8 +Xwc_return = 9 +EOF +fi +if test -s 'lib/util.py' +then echo '*** I will not over-write existing file lib/util.py' +else +echo 'x - lib/util.py' +sed 's/^X//' > 'lib/util.py' << 'EOF' +X# Module 'util' -- some useful functions that don't fit elsewhere +X +X +X# Remove an item from a list. +X# No complaints if it isn't in the list at all. +X# If it occurs more than once, remove the first occurrence. +X# +Xdef remove(item, list): +X for i in range(len(list)): +X if list[i] = item: +X del list[i] +X break +X +X +X# Return a string containing a file's contents. +X# +Xdef readfile(fn): +X return readopenfile(open(fn, 'r')) +X +X +X# Read an open file until EOF. +X# +Xdef readopenfile(fp): +X BUFSIZE = 512*8 +X data = '' +X while 1: +X buf = fp.read(BUFSIZE) +X if not buf: break +X data = data + buf +X return data +EOF +fi +if test -s 'src/To.do' +then echo '*** I will not over-write existing file src/To.do' +else +echo 'x - src/To.do' +sed 's/^X//' > 'src/To.do' << 'EOF' +X- return better errors for file objects (also check read/write allowed, etc.) +X +X- introduce more specific exceptions (e.g., zero divide, index failure, ...) +X +X- why do reads from stdin fail when I suspend the process? +X +X- introduce macros to set/inspect errno for syscalls, to support things +X like getoserr() +X +X- fix interrupt handling (interruptable system calls should call +X intrcheck() to clear the interrupt status) +EOF +fi +if test -s 'src/assert.h' +then echo '*** I will not over-write existing file src/assert.h' +else +echo 'x - src/assert.h' +sed 's/^X//' > 'src/assert.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X#define assert(e) { if (!(e)) { printf("Assertion failed\n"); abort(); } } +EOF +fi +if test -s 'src/bltinmodule.h' +then echo '*** I will not over-write existing file src/bltinmodule.h' +else +echo 'x - src/bltinmodule.h' +sed 's/^X//' > 'src/bltinmodule.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X/* Built-in module interface */ +X +Xextern object *getbuiltin PROTO((char *)); +EOF +fi +if test -s 'src/fgetsintr.h' +then echo '*** I will not over-write existing file src/fgetsintr.h' +else +echo 'x - src/fgetsintr.h' +sed 's/^X//' > 'src/fgetsintr.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +Xextern int fgets_intr PROTO((char *, int, FILE *)); +EOF +fi +if test -s 'src/rltokenizer.c' +then echo '*** I will not over-write existing file src/rltokenizer.c' +else +echo 'x - src/rltokenizer.c' +sed 's/^X//' > 'src/rltokenizer.c' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X#define USE_READLINE +X#include "tokenizer.c" +EOF +fi +if test -s 'src/stubcode.h' +then echo '*** I will not over-write existing file src/stubcode.h' +else +echo 'x - src/stubcode.h' +sed 's/^X//' > 'src/stubcode.h' << 'EOF' +X/*********************************************************** +XCopyright 1991 by Stichting Mathematisch Centrum, Amsterdam, The +XNetherlands. +X +X All Rights Reserved +X +XPermission to use, copy, modify, and distribute this software and its +Xdocumentation for any purpose and without fee is hereby granted, +Xprovided that the above copyright notice appear in all copies and that +Xboth that copyright notice and this permission notice appear in +Xsupporting documentation, and that the names of Stichting Mathematisch +XCentrum or CWI not be used in advertising or publicity pertaining to +Xdistribution of the software without specific, written prior permission. +X +XSTICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +XTHIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +XFITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +XFOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +XWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +XACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +XOF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +X +X******************************************************************/ +X +X +X#define CAP 0 +X#define STUBC 1 +X#define NAME 2 +EOF +fi +echo 'Part 21 out of 21 of pack.out complete.' +exit 0 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 = 100; + if (intrcheck()) { + err_set(KeyboardInterrupt); + why = WHY_EXCEPTION; + tb_here(f, INSTR_OFFSET(), lineno); + break; + } + } + + /* Extract opcode and argument */ + + opcode = NEXTOP(); + if (HAS_ARG(opcode)) + oparg = NEXTARG(); + +#ifdef TRACE + /* Instruction tracing */ + + if (trace) { + if (HAS_ARG(opcode)) { + printf("%d: %d, %d\n", + (int) (INSTR_OFFSET() - 3), + opcode, oparg); + } + else { + printf("%d: %d\n", + (int) (INSTR_OFFSET() - 1), opcode); + } + } +#endif + + /* Main switch on opcode */ + + switch (opcode) { + + /* BEWARE! + It is essential that any operation that fails sets either + x to NULL, err to nonzero, or why to anything but WHY_NOT, + and that no operation that succeeds does this! */ + + /* case STOP_CODE: this is an error! */ + + case POP_TOP: + v = POP(); + DECREF(v); + break; + + case ROT_TWO: + v = POP(); + w = POP(); + PUSH(v); + PUSH(w); + break; + + case ROT_THREE: + v = POP(); + w = POP(); + x = POP(); + PUSH(v); + PUSH(x); + PUSH(w); + break; + + case DUP_TOP: + v = TOP(); + INCREF(v); + PUSH(v); + break; + + case UNARY_POSITIVE: + v = POP(); + x = pos(v); + DECREF(v); + PUSH(x); + break; + + case UNARY_NEGATIVE: + v = POP(); + x = neg(v); + DECREF(v); + PUSH(x); + break; + + case UNARY_NOT: + v = POP(); + x = not(v); + DECREF(v); + PUSH(x); + break; + + case UNARY_CONVERT: + v = POP(); + x = reprobject(v); + DECREF(v); + PUSH(x); + break; + + case UNARY_CALL: + v = POP(); + if (is_classmethodobject(v) || is_funcobject(v)) + x = call_function(v, (object *)NULL); + else + x = call_builtin(v, (object *)NULL); + DECREF(v); + PUSH(x); + break; + + case BINARY_MULTIPLY: + w = POP(); + v = POP(); + x = mul(v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case BINARY_DIVIDE: + w = POP(); + v = POP(); + x = divide(v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case BINARY_MODULO: + w = POP(); + v = POP(); + x = rem(v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case BINARY_ADD: + w = POP(); + v = POP(); + x = add(v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case BINARY_SUBTRACT: + w = POP(); + v = POP(); + x = sub(v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case BINARY_SUBSCR: + w = POP(); + v = POP(); + x = apply_subscript(v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case BINARY_CALL: + w = POP(); + v = POP(); + if (is_classmethodobject(v) || is_funcobject(v)) + x = call_function(v, w); + else + x = call_builtin(v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case SLICE+0: + case SLICE+1: + case SLICE+2: + case SLICE+3: + if ((opcode-SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + x = apply_slice(u, v, w); + DECREF(u); + XDECREF(v); + XDECREF(w); + PUSH(x); + break; + + case STORE_SLICE+0: + case STORE_SLICE+1: + case STORE_SLICE+2: + case STORE_SLICE+3: + if ((opcode-STORE_SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-STORE_SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + t = POP(); + err = assign_slice(u, v, w, t); /* u[v:w] = t */ + DECREF(t); + DECREF(u); + XDECREF(v); + XDECREF(w); + break; + + case DELETE_SLICE+0: + case DELETE_SLICE+1: + case DELETE_SLICE+2: + case DELETE_SLICE+3: + if ((opcode-DELETE_SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-DELETE_SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + err = assign_slice(u, v, w, (object *)NULL); + /* del u[v:w] */ + DECREF(u); + XDECREF(v); + XDECREF(w); + break; + + case STORE_SUBSCR: + w = POP(); + v = POP(); + u = POP(); + /* v[w] = u */ + err = assign_subscript(v, w, u); + DECREF(u); + DECREF(v); + DECREF(w); + break; + + case DELETE_SUBSCR: + w = POP(); + v = POP(); + /* del v[w] */ + err = assign_subscript(v, w, (object *)NULL); + DECREF(v); + DECREF(w); + break; + + case PRINT_EXPR: + v = POP(); + fp = sysgetfile("stdout", stdout); + /* Print value except if procedure result */ + if (v != None) { + flushline(); + printobject(v, fp, 0); + fprintf(fp, "\n"); + } + DECREF(v); + break; + + case PRINT_ITEM: + v = POP(); + fp = sysgetfile("stdout", stdout); + if (needspace) + fprintf(fp, " "); + if (is_stringobject(v)) { + char *s = getstringvalue(v); + int len = getstringsize(v); + fwrite(s, 1, len, fp); + if (len > 0 && s[len-1] == '\n') + needspace = 0; + else + needspace = 1; + } + else { + printobject(v, fp, 0); + needspace = 1; + } + DECREF(v); + break; + + case PRINT_NEWLINE: + fp = sysgetfile("stdout", stdout); + fprintf(fp, "\n"); + needspace = 0; + break; + + case BREAK_LOOP: + why = WHY_BREAK; + break; + + case RAISE_EXCEPTION: + v = POP(); + w = POP(); + if (!is_stringobject(w)) + err_setstr(TypeError, + "exceptions must be strings"); + else + err_setval(w, v); + DECREF(v); + DECREF(w); + why = WHY_EXCEPTION; + break; + + case LOAD_LOCALS: + v = f->f_locals; + INCREF(v); + PUSH(v); + break; + + case RETURN_VALUE: + retval = POP(); + why = WHY_RETURN; + break; + + case REQUIRE_ARGS: + if (EMPTY()) { + err_setstr(TypeError, + "function expects argument(s)"); + why = WHY_EXCEPTION; + } + break; + + case REFUSE_ARGS: + if (!EMPTY()) { + err_setstr(TypeError, + "function expects no argument(s)"); + why = WHY_EXCEPTION; + } + break; + + case BUILD_FUNCTION: + v = POP(); + x = newfuncobject(v, f->f_globals); + DECREF(v); + PUSH(x); + break; + + case POP_BLOCK: + { + block *b = pop_block(f); + while (STACK_LEVEL() > b->b_level) { + v = POP(); + DECREF(v); + } + } + break; + + case END_FINALLY: + v = POP(); + if (is_intobject(v)) { + why = (enum why_code) getintvalue(v); + if (why == WHY_RETURN) + retval = POP(); + } + else if (is_stringobject(v)) { + w = POP(); + err_setval(v, w); + DECREF(w); + w = POP(); + tb_store(w); + DECREF(w); + why = WHY_RERAISE; + } + else if (v != None) { + err_setstr(SystemError, + "'finally' pops bad exception"); + why = WHY_EXCEPTION; + } + DECREF(v); + break; + + case BUILD_CLASS: + w = POP(); + v = POP(); + x = build_class(v, w); + PUSH(x); + DECREF(v); + DECREF(w); + break; + + case STORE_NAME: + name = GETNAME(oparg); + v = POP(); + err = dictinsert(f->f_locals, name, v); + DECREF(v); + break; + + case DELETE_NAME: + name = GETNAME(oparg); + if ((err = dictremove(f->f_locals, name)) != 0) + err_setstr(NameError, name); + break; + + case UNPACK_TUPLE: + v = POP(); + if (!is_tupleobject(v)) { + err_setstr(TypeError, "unpack non-tuple"); + why = WHY_EXCEPTION; + } + else if (gettuplesize(v) != oparg) { + err_setstr(RuntimeError, + "unpack tuple of wrong size"); + why = WHY_EXCEPTION; + } + else { + for (; --oparg >= 0; ) { + w = gettupleitem(v, oparg); + INCREF(w); + PUSH(w); + } + } + DECREF(v); + break; + + case UNPACK_LIST: + v = POP(); + if (!is_listobject(v)) { + err_setstr(TypeError, "unpack non-list"); + why = WHY_EXCEPTION; + } + else if (getlistsize(v) != oparg) { + err_setstr(RuntimeError, + "unpack list of wrong size"); + why = WHY_EXCEPTION; + } + else { + for (; --oparg >= 0; ) { + w = getlistitem(v, oparg); + INCREF(w); + PUSH(w); + } + } + DECREF(v); + break; + + case STORE_ATTR: + name = GETNAME(oparg); + v = POP(); + u = POP(); + err = setattr(v, name, u); /* v.name = u */ + DECREF(v); + DECREF(u); + break; + + case DELETE_ATTR: + name = GETNAME(oparg); + v = POP(); + err = setattr(v, name, (object *)NULL); + /* del v.name */ + DECREF(v); + break; + + case LOAD_CONST: + x = GETCONST(oparg); + INCREF(x); + PUSH(x); + break; + + case LOAD_NAME: + name = GETNAME(oparg); + x = dictlookup(f->f_locals, name); + if (x == NULL) { + x = dictlookup(f->f_globals, name); + if (x == NULL) + x = getbuiltin(name); + } + if (x == NULL) + err_setstr(NameError, name); + else + INCREF(x); + PUSH(x); + break; + + case BUILD_TUPLE: + x = newtupleobject(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { + w = POP(); + err = settupleitem(x, oparg, w); + if (err != 0) + break; + } + PUSH(x); + } + break; + + case BUILD_LIST: + x = newlistobject(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { + w = POP(); + err = setlistitem(x, oparg, w); + if (err != 0) + break; + } + PUSH(x); + } + break; + + case BUILD_MAP: + x = newdictobject(); + PUSH(x); + break; + + case LOAD_ATTR: + name = GETNAME(oparg); + v = POP(); + x = getattr(v, name); + DECREF(v); + PUSH(x); + break; + + case COMPARE_OP: + w = POP(); + v = POP(); + x = cmp_outcome((enum cmp_op)oparg, v, w); + DECREF(v); + DECREF(w); + PUSH(x); + break; + + case IMPORT_NAME: + name = GETNAME(oparg); + x = import_module(name); + XINCREF(x); + PUSH(x); + break; + + case IMPORT_FROM: + name = GETNAME(oparg); + v = TOP(); + err = import_from(f->f_locals, v, name); + break; + + case JUMP_FORWARD: + JUMPBY(oparg); + break; + + case JUMP_IF_FALSE: + if (!testbool(TOP())) + JUMPBY(oparg); + break; + + case JUMP_IF_TRUE: + if (testbool(TOP())) + JUMPBY(oparg); + break; + + case JUMP_ABSOLUTE: + JUMPTO(oparg); + break; + + case FOR_LOOP: + /* for v in s: ... + On entry: stack contains s, i. + On exit: stack contains s, i+1, s[i]; + but if loop exhausted: + s, i are popped, and we jump */ + w = POP(); /* Loop index */ + v = POP(); /* Sequence object */ + u = loop_subscript(v, w); + if (u != NULL) { + PUSH(v); + x = newintobject(getintvalue(w)+1); + PUSH(x); + DECREF(w); + PUSH(u); + } + else { + DECREF(v); + DECREF(w); + /* A NULL can mean "s exhausted" + but also an error: */ + if (err_occurred()) + why = WHY_EXCEPTION; + else + JUMPBY(oparg); + } + break; + + case SETUP_LOOP: + case SETUP_EXCEPT: + case SETUP_FINALLY: + setup_block(f, opcode, INSTR_OFFSET() + oparg, + STACK_LEVEL()); + break; + + case SET_LINENO: +#ifdef TRACE + if (trace) + printf("--- Line %d ---\n", oparg); +#endif + lineno = oparg; + break; + + default: + fprintf(stderr, + "XXX lineno: %d, opcode: %d\n", + lineno, opcode); + err_setstr(SystemError, "eval_code: unknown opcode"); + why = WHY_EXCEPTION; + break; + + } /* switch */ + + + /* Quickly continue if no error occurred */ + + if (why == WHY_NOT) { + if (err == 0 && x != NULL) + continue; /* Normal, fast path */ + why = WHY_EXCEPTION; + x = None; + err = 0; + } + +#ifndef NDEBUG + /* Double-check exception status */ + + if (why == WHY_EXCEPTION || why == WHY_RERAISE) { + if (!err_occurred()) { + fprintf(stderr, "XXX ghost error\n"); + err_setstr(SystemError, "ghost error"); + why = WHY_EXCEPTION; + } + } + else { + if (err_occurred()) { + fprintf(stderr, "XXX undetected error\n"); + why = WHY_EXCEPTION; + } + } +#endif + + /* Log traceback info if this is a real exception */ + + if (why == WHY_EXCEPTION) { + int lasti = INSTR_OFFSET() - 1; + if (HAS_ARG(opcode)) + lasti -= 2; + tb_here(f, lasti, lineno); + } + + /* For the rest, treat WHY_RERAISE as WHY_EXCEPTION */ + + if (why == WHY_RERAISE) + why = WHY_EXCEPTION; + + /* Unwind stacks if a (pseudo) exception occurred */ + + while (why != WHY_NOT && f->f_iblock > 0) { + block *b = pop_block(f); + while (STACK_LEVEL() > b->b_level) { + v = POP(); + XDECREF(v); + } + if (b->b_type == SETUP_LOOP && why == WHY_BREAK) { + why = WHY_NOT; + JUMPTO(b->b_handler); + break; + } + if (b->b_type == SETUP_FINALLY || + b->b_type == SETUP_EXCEPT && + why == WHY_EXCEPTION) { + if (why == WHY_EXCEPTION) { + object *exc, *val; + err_get(&exc, &val); + if (val == NULL) { + val = None; + INCREF(val); + } + v = tb_fetch(); + /* Make the raw exception data + available to the handler, + so a program can emulate the + Python main loop. Don't do + this for 'finally'. */ + if (b->b_type == SETUP_EXCEPT) { +#if 0 /* Oops, this breaks too many things */ + sysset("exc_traceback", v); +#endif + sysset("exc_value", val); + sysset("exc_type", exc); + err_clear(); + } + PUSH(v); + PUSH(val); + PUSH(exc); + } + else { + if (why == WHY_RETURN) + PUSH(retval); + v = newintobject((long)why); + PUSH(v); + } + why = WHY_NOT; + JUMPTO(b->b_handler); + break; + } + } /* unwind stack */ + + /* End the loop if we still have an error (or return) */ + + if (why != WHY_NOT) + break; + + } /* main loop */ + + /* Pop remaining stack entries */ + + while (!EMPTY()) { + v = POP(); + XDECREF(v); + } + + /* Restore previous frame and release the current one */ + + current_frame = f->f_back; + DECREF(f); + + if (why == WHY_RETURN) + return retval; + else + return NULL; +} diff --git a/src/ceval.h b/src/ceval.h new file mode 100644 index 0000000..7f57738 --- /dev/null +++ b/src/ceval.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 to execute compiled code */ +/* This header depends on "compile.h" */ + +object *eval_code PROTO((codeobject *, object *, object *, object *)); + +object *getglobals PROTO((void)); +object *getlocals PROTO((void)); + +void printtraceback PROTO((FILE *)); diff --git a/src/cgen b/src/cgen new file mode 100644 index 0000000..c2f0d0c --- /dev/null +++ b/src/cgen @@ -0,0 +1,458 @@ +# Python script to parse cstubs file for gl and generate C stubs. +# usage: python cgen <cstubs >glmodule.c +# +# XXX BUG return arrays generate wrong code +# XXX need to change error returns into gotos to free mallocked arrays + + +import string +import sys + + +# Function to print to stderr +# +def err(args): + savestdout = sys.stdout + try: + sys.stdout = sys.stderr + for i in args: + print i, + print + finally: + sys.stdout = savestdout + + +# The set of digits that form a number +# +digits = '0123456789' + + +# Function to extract a string of digits from the front of the string. +# Returns the leading string of digits and the remaining string. +# If no number is found, returns '' and the original string. +# +def getnum(s): + n = '' + while s and s[0] in digits: + n = n + s[0] + s = s[1:] + return n, s + + +# Function to check if a string is a number +# +def isnum(s): + if not s: return 0 + for c in s: + if not c in digits: return 0 + return 1 + + +# Allowed function return types +# +return_types = ['void', 'short', 'long'] + + +# Allowed function argument types +# +arg_types = ['char', 'string', 'short', 'float', 'long', 'double'] + + +# Need to classify arguments as follows +# simple input variable +# simple output variable +# input array +# output array +# input giving size of some array +# +# Array dimensions can be specified as follows +# constant +# argN +# constant * argN +# retval +# constant * retval +# +# The dimensions given as constants * something are really +# arrays of points where points are 2- 3- or 4-tuples +# +# We have to consider three lists: +# python input arguments +# C stub arguments (in & out) +# python output arguments (really return values) +# +# There is a mapping from python input arguments to the input arguments +# of the C stub, and a further mapping from C stub arguments to the +# python return values + + +# Exception raised by checkarg() and generate() +# +arg_error = 'bad arg' + + +# Function to check one argument. +# Arguments: the type and the arg "name" (really mode plus subscript). +# Raises arg_error if something's wrong. +# Return type, mode, factor, rest of subscript; factor and rest may be empty. +# +def checkarg(type, arg): + # + # Turn "char *x" into "string x". + # + if type = 'char' and arg[0] = '*': + type = 'string' + arg = arg[1:] + # + # Check that the type is supported. + # + if type not in arg_types: + raise arg_error, ('bad type', type) + # + # Split it in the mode (first character) and the rest. + # + mode, rest = arg[:1], arg[1:] + # + # The mode must be 's' for send (= input) or 'r' for return argument. + # + if mode not in ('r', 's'): + raise arg_error, ('bad arg mode', mode) + # + # Is it a simple argument: if so, we are done. + # + if not rest: + return type, mode, '', '' + # + # Not a simple argument; must be an array. + # The 'rest' must be a subscript enclosed in [ and ]. + # The subscript must be one of the following forms, + # otherwise we don't handle it (where N is a number): + # N + # argN + # retval + # N*argN + # N*retval + # + if rest[:1] <> '[' or rest[-1:] <> ']': + raise arg_error, ('subscript expected', rest) + sub = rest[1:-1] + # + # Is there a leading number? + # + num, sub = getnum(sub) + if num: + # There is a leading number + if not sub: + # The subscript is just a number + return type, mode, num, '' + if sub[:1] = '*': + # There is a factor prefix + sub = sub[1:] + else: + raise arg_error, ('\'*\' expected', sub) + if sub = 'retval': + # size is retval -- must be a reply argument + if mode <> 'r': + raise arg_error, ('non-r mode with [retval]', mode) + elif sub[:3] <> 'arg' or not isnum(sub[3:]): + raise arg_error, ('bad subscript', sub) + # + return type, mode, num, sub + + +# List of functions for which we have generated stubs +# +functions = [] + + +# Generate the stub for the given function, using the database of argument +# information build by successive calls to checkarg() +# +def generate(type, func, database): + # + # Check that we can handle this case: + # no variable size reply arrays yet + # + n_in_args = 0 + n_out_args = 0 + # + for a_type, a_mode, a_factor, a_sub in database: + if a_mode = 's': + n_in_args = n_in_args + 1 + elif a_mode = 'r': + n_out_args = n_out_args + 1 + else: + # Can't happen + raise arg_error, ('bad a_mode', a_mode) + if (a_mode = 'r' and a_sub) or a_sub = 'retval': + e = 'Function', func, 'too complicated:' + err(e + (a_type, a_mode, a_factor, a_sub)) + print '/* XXX Too complicated to generate code for */' + return + # + functions.append(func) + # + # Stub header + # + print + print 'static object *' + print 'gl_' + func + '(self, args)' + print '\tobject *self;' + print '\tobject *args;' + print '{' + # + # Declare return value if any + # + if type <> 'void': + print '\t' + type, 'retval;' + # + # Declare arguments + # + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + print '\t' + a_type, + if a_sub: + print '*', + print 'arg' + `i+1`, + if a_factor and not a_sub: + print '[', a_factor, ']', + print ';' + # + # Find input arguments derived from array sizes + # + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode = 's' and a_sub[:3] = 'arg' and isnum(a_sub[3:]): + # Sending a variable-length array + n = eval(a_sub[3:]) + if 1 <= n <= len(database): + b_type, b_mode, b_factor, b_sub = database[n-1] + if b_mode = 's': + database[n-1] = b_type, 'i', a_factor, `i` + n_in_args = n_in_args - 1 + # + # Assign argument positions in the Python argument list + # + in_pos = [] + i_in = 0 + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode = 's': + in_pos.append(i_in) + i_in = i_in + 1 + else: + in_pos.append(-1) + # + # Get input arguments + # + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode = 'i': + # + # Implicit argument; + # a_factor is divisor if present, + # a_sub indicates which arg (`database index`) + # + j = eval(a_sub) + print '\tif', + print '(!geti' + a_type + 'arraysize(args,', + print `n_in_args` + ',', + print `in_pos[j]` + ',', + print '&arg' + `i+1` + '))' + print '\t\treturn NULL;' + if a_factor: + print '\targ' + `i+1`, + print '= arg' + `i+1`, + print '/', a_factor + ';' + elif a_mode = 's': + if a_sub: # Allocate memory for varsize array + print '\tif ((arg' + `i+1`, '=', + print 'NEW(' + a_type + ',', + if a_factor: print a_factor, '*', + print a_sub, ')) == NULL)' + print '\t\treturn err_nomem();' + print '\tif', + if a_factor or a_sub: # Get a fixed-size array array + print '(!geti' + a_type + 'array(args,', + print `n_in_args` + ',', + print `in_pos[i]` + ',', + if a_factor: print a_factor, + if a_factor and a_sub: print '*', + if a_sub: print a_sub, + print ', arg' + `i+1` + '))' + else: # Get a simple variable + print '(!geti' + a_type + 'arg(args,', + print `n_in_args` + ',', + print `in_pos[i]` + ',', + print '&arg' + `i+1` + '))' + print '\t\treturn NULL;' + # + # Begin of function call + # + if type <> 'void': + print '\tretval =', func + '(', + else: + print '\t' + func + '(', + # + # Argument list + # + for i in range(len(database)): + if i > 0: print ',', + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode = 'r' and not a_factor: + print '&', + print 'arg' + `i+1`, + # + # End of function call + # + print ');' + # + # Free varsize arrays + # + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode = 's' and a_sub: + print '\tDEL(arg' + `i+1` + ');' + # + # Return + # + if n_out_args: + # + # Multiple return values -- construct a tuple + # + if type <> 'void': + n_out_args = n_out_args + 1 + if n_out_args = 1: + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode = 'r': + break + else: + raise arg_error, 'expected r arg not found' + print '\treturn', + print mkobject(a_type, 'arg' + `i+1`) + ';' + else: + print '\t{ object *v = newtupleobject(', + print n_out_args, ');' + print '\t if (v == NULL) return NULL;' + i_out = 0 + if type <> 'void': + print '\t settupleitem(v,', + print `i_out` + ',', + print mkobject(type, 'retval') + ');' + i_out = i_out + 1 + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode = 'r': + print '\t settupleitem(v,', + print `i_out` + ',', + s = mkobject(a_type, 'arg' + `i+1`) + print s + ');' + i_out = i_out + 1 + print '\t return v;' + print '\t}' + else: + # + # Simple function return + # Return None or return value + # + if type = 'void': + print '\tINCREF(None);' + print '\treturn None;' + else: + print '\treturn', mkobject(type, 'retval') + ';' + # + # Stub body closing brace + # + print '}' + + +# Subroutine to return a function call to mknew<type>object(<arg>) +# +def mkobject(type, arg): + return 'mknew' + type + 'object(' + arg + ')' + + +# Input line number +lno = 0 + + +# Input is divided in two parts, separated by a line containing '%%'. +# <part1> -- literally copied to stdout +# <part2> -- stub definitions + +# Variable indicating the current input part. +# +part = 1 + +# Main loop over the input +# +while 1: + try: + line = raw_input() + except EOFError: + break + # + lno = lno+1 + words = string.split(line) + # + if part = 1: + # + # In part 1, copy everything literally + # except look for a line of just '%%' + # + if words = ['%%']: + part = part + 1 + else: + # + # Look for names of manually written + # stubs: a single percent followed by the name + # of the function in Python. + # The stub name is derived by prefixing 'gl_'. + # + if words and words[0][0] = '%': + func = words[0][1:] + if (not func) and words[1:]: + func = words[1] + if func: + functions.append(func) + else: + print line + elif not words: + pass # skip empty line + elif words[0] = '#include': + print line + elif words[0][:1] = '#': + pass # ignore comment + elif words[0] not in return_types: + err('Line', lno, ': bad return type :', words[0]) + elif len(words) < 2: + err('Line', lno, ': no funcname :', line) + else: + if len(words) % 2 <> 0: + err('Line', lno, ': odd argument list :', words[2:]) + else: + database = [] + try: + for i in range(2, len(words), 2): + x = checkarg(words[i], words[i+1]) + database.append(x) + print + print '/*', + for w in words: print w, + print '*/' + generate(words[0], words[1], database) + except arg_error, msg: + err('Line', lno, ':', msg) + + +print +print 'static struct methodlist gl_methods[] = {' +for func in functions: + print '\t{"' + func + '", gl_' + func + '},' +print '\t{NULL, NULL} /* Sentinel */' +print '};' +print +print 'initgl()' +print '{' +print '\tinitmodule("gl", gl_methods);' +print '}' diff --git a/src/cgensupport.c b/src/cgensupport.c new file mode 100644 index 0000000..91adb2a --- /dev/null +++ b/src/cgensupport.c @@ -0,0 +1,393 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Functions used by cgen output */ + +#include <stdio.h> + +#include "PROTO.h" +#include "object.h" +#include "intobject.h" +#include "floatobject.h" +#include "stringobject.h" +#include "tupleobject.h" +#include "listobject.h" +#include "methodobject.h" +#include "moduleobject.h" +#include "modsupport.h" +#include "import.h" +#include "cgensupport.h" +#include "errors.h" + + +/* Functions to construct return values */ + +object * +mknewcharobject(c) + int c; +{ + char ch[1]; + ch[0] = c; + return newsizedstringobject(ch, 1); +} + +/* Functions to extract arguments. + These needs to know the total number of arguments supplied, + since the argument list is a tuple only of there is more than + one argument. */ + +int +getiobjectarg(args, nargs, i, p_arg) + register object *args; + int nargs, i; + object **p_arg; +{ + if (nargs != 1) { + if (args == NULL || !is_tupleobject(args) || + nargs != gettuplesize(args) || + i < 0 || i >= nargs) { + return err_badarg(); + } + else { + args = gettupleitem(args, i); + } + } + if (args == NULL) { + return err_badarg(); + } + *p_arg = args; + return 1; +} + +int +getilongarg(args, nargs, i, p_arg) + register object *args; + int nargs, i; + long *p_arg; +{ + if (nargs != 1) { + if (args == NULL || !is_tupleobject(args) || + nargs != gettuplesize(args) || + i < 0 || i >= nargs) { + return err_badarg(); + } + args = gettupleitem(args, i); + } + if (args == NULL || !is_intobject(args)) { + return err_badarg(); + } + *p_arg = getintvalue(args); + return 1; +} + +int +getishortarg(args, nargs, i, p_arg) + register object *args; + int nargs, i; + short *p_arg; +{ + long x; + if (!getilongarg(args, nargs, i, &x)) + return 0; + *p_arg = x; + return 1; +} + +static int +extractdouble(v, p_arg) + register object *v; + double *p_arg; +{ + if (v == NULL) { + /* Fall through to error return at end of function */ + } + else if (is_floatobject(v)) { + *p_arg = GETFLOATVALUE((floatobject *)v); + return 1; + } + else if (is_intobject(v)) { + *p_arg = GETINTVALUE((intobject *)v); + return 1; + } + return err_badarg(); +} + +static int +extractfloat(v, p_arg) + register object *v; + float *p_arg; +{ + if (v == NULL) { + /* Fall through to error return at end of function */ + } + else if (is_floatobject(v)) { + *p_arg = GETFLOATVALUE((floatobject *)v); + return 1; + } + else if (is_intobject(v)) { + *p_arg = GETINTVALUE((intobject *)v); + return 1; + } + return err_badarg(); +} + +int +getifloatarg(args, nargs, i, p_arg) + register object *args; + int nargs, i; + float *p_arg; +{ + object *v; + float x; + if (!getiobjectarg(args, nargs, i, &v)) + return 0; + if (!extractfloat(v, &x)) + return 0; + *p_arg = x; + return 1; +} + +int +getistringarg(args, nargs, i, p_arg) + object *args; + int nargs, i; + string *p_arg; +{ + object *v; + if (!getiobjectarg(args, nargs, i, &v)) + return NULL; + if (!is_stringobject(v)) { + return err_badarg(); + } + *p_arg = getstringvalue(v); + return 1; +} + +int +getichararg(args, nargs, i, p_arg) + object *args; + int nargs, i; + char *p_arg; +{ + string x; + if (!getistringarg(args, nargs, i, &x)) + return 0; + if (x[0] == '\0' || x[1] != '\0') { + /* Not exactly one char */ + return err_badarg(); + } + *p_arg = x[0]; + return 1; +} + +int +getilongarraysize(args, nargs, i, p_arg) + object *args; + int nargs, i; + long *p_arg; +{ + object *v; + if (!getiobjectarg(args, nargs, i, &v)) + return 0; + if (is_tupleobject(v)) { + *p_arg = gettuplesize(v); + return 1; + } + if (is_listobject(v)) { + *p_arg = getlistsize(v); + return 1; + } + return err_badarg(); +} + +int +getishortarraysize(args, nargs, i, p_arg) + object *args; + int nargs, i; + short *p_arg; +{ + long x; + if (!getilongarraysize(args, nargs, i, &x)) + return 0; + *p_arg = x; + return 1; +} + +/* XXX The following four are too similar. Should share more code. */ + +int +getilongarray(args, nargs, i, n, p_arg) + object *args; + int nargs, i; + int n; + long *p_arg; /* [n] */ +{ + object *v, *w; + if (!getiobjectarg(args, nargs, i, &v)) + return 0; + if (is_tupleobject(v)) { + if (gettuplesize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = gettupleitem(v, i); + if (!is_intobject(w)) { + return err_badarg(); + } + p_arg[i] = getintvalue(w); + } + return 1; + } + else if (is_listobject(v)) { + if (getlistsize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = getlistitem(v, i); + if (!is_intobject(w)) { + return err_badarg(); + } + p_arg[i] = getintvalue(w); + } + return 1; + } + else { + return err_badarg(); + } +} + +int +getishortarray(args, nargs, i, n, p_arg) + object *args; + int nargs, i; + int n; + short *p_arg; /* [n] */ +{ + object *v, *w; + if (!getiobjectarg(args, nargs, i, &v)) + return 0; + if (is_tupleobject(v)) { + if (gettuplesize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = gettupleitem(v, i); + if (!is_intobject(w)) { + return err_badarg(); + } + p_arg[i] = getintvalue(w); + } + return 1; + } + else if (is_listobject(v)) { + if (getlistsize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = getlistitem(v, i); + if (!is_intobject(w)) { + return err_badarg(); + } + p_arg[i] = getintvalue(w); + } + return 1; + } + else { + return err_badarg(); + } +} + +int +getidoublearray(args, nargs, i, n, p_arg) + object *args; + int nargs, i; + int n; + double *p_arg; /* [n] */ +{ + object *v, *w; + if (!getiobjectarg(args, nargs, i, &v)) + return 0; + if (is_tupleobject(v)) { + if (gettuplesize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = gettupleitem(v, i); + if (!extractdouble(w, &p_arg[i])) + return 0; + } + return 1; + } + else if (is_listobject(v)) { + if (getlistsize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = getlistitem(v, i); + if (!extractdouble(w, &p_arg[i])) + return 0; + } + return 1; + } + else { + return err_badarg(); + } +} + +int +getifloatarray(args, nargs, i, n, p_arg) + object *args; + int nargs, i; + int n; + float *p_arg; /* [n] */ +{ + object *v, *w; + if (!getiobjectarg(args, nargs, i, &v)) + return 0; + if (is_tupleobject(v)) { + if (gettuplesize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = gettupleitem(v, i); + if (!extractfloat(w, &p_arg[i])) + return 0; + } + return 1; + } + else if (is_listobject(v)) { + if (getlistsize(v) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + w = getlistitem(v, i); + if (!extractfloat(w, &p_arg[i])) + return 0; + } + return 1; + } + else { + return err_badarg(); + } +} diff --git a/src/cgensupport.h b/src/cgensupport.h new file mode 100644 index 0000000..a056f5d --- /dev/null +++ b/src/cgensupport.h @@ -0,0 +1,39 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Definitions used by cgen output */ + +typedef char *string; + +#define mknewlongobject(x) newintobject(x) +#define mknewshortobject(x) newintobject((long)x) +#define mknewfloatobject(x) newfloatobject(x) + +extern object *mknewcharobject PROTO((int c)); + +extern int getiobjectarg PROTO((object *args, int nargs, int i, object **p_a)); +extern int getilongarg PROTO((object *args, int nargs, int i, long *p_a)); +extern int getishortarg PROTO((object *args, int nargs, int i, short *p_a)); +extern int getifloatarg PROTO((object *args, int nargs, int i, float *p_a)); +extern int getistringarg PROTO((object *args, int nargs, int i, string *p_a)); diff --git a/src/classobject.c b/src/classobject.c new file mode 100644 index 0000000..fc32889 --- /dev/null +++ b/src/classobject.c @@ -0,0 +1,298 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Class object implementation */ + +#include "allobjects.h" + +#include "structmember.h" + +typedef struct { + OB_HEAD + object *cl_bases; /* A tuple */ + object *cl_methods; /* A dictionary */ +} classobject; + +object * +newclassobject(bases, methods) + object *bases; /* NULL or tuple of classobjects! */ + object *methods; +{ + classobject *op; + op = NEWOBJ(classobject, &Classtype); + if (op == NULL) + return NULL; + if (bases != NULL) + INCREF(bases); + op->cl_bases = bases; + INCREF(methods); + op->cl_methods = methods; + return (object *) op; +} + +/* Class methods */ + +static void +class_dealloc(op) + classobject *op; +{ + int i; + if (op->cl_bases != NULL) + DECREF(op->cl_bases); + DECREF(op->cl_methods); + free((ANY *)op); +} + +static object * +class_getattr(op, name) + register classobject *op; + register char *name; +{ + register object *v; + v = dictlookup(op->cl_methods, name); + if (v != NULL) { + INCREF(v); + return v; + } + if (op->cl_bases != NULL) { + int n = gettuplesize(op->cl_bases); + int i; + for (i = 0; i < n; i++) { + v = class_getattr(gettupleitem(op->cl_bases, i), name); + if (v != NULL) + return v; + err_clear(); + } + } + err_setstr(NameError, name); + return NULL; +} + +typeobject Classtype = { + OB_HEAD_INIT(&Typetype) + 0, + "class", + sizeof(classobject), + 0, + class_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + class_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; + + +/* We're not done yet: next, we define class member objects... */ + +typedef struct { + OB_HEAD + classobject *cm_class; /* The class object */ + object *cm_attr; /* A dictionary */ +} classmemberobject; + +object * +newclassmemberobject(class) + register object *class; +{ + register classmemberobject *cm; + if (!is_classobject(class)) { + err_badcall(); + return NULL; + } + cm = NEWOBJ(classmemberobject, &Classmembertype); + if (cm == NULL) + return NULL; + INCREF(class); + cm->cm_class = (classobject *)class; + cm->cm_attr = newdictobject(); + if (cm->cm_attr == NULL) { + DECREF(cm); + return NULL; + } + return (object *)cm; +} + +/* Class member methods */ + +static void +classmember_dealloc(cm) + register classmemberobject *cm; +{ + DECREF(cm->cm_class); + if (cm->cm_attr != NULL) + DECREF(cm->cm_attr); + free((ANY *)cm); +} + +static object * +classmember_getattr(cm, name) + register classmemberobject *cm; + register char *name; +{ + register object *v = dictlookup(cm->cm_attr, name); + if (v != NULL) { + INCREF(v); + return v; + } + v = class_getattr(cm->cm_class, name); + if (v == NULL) + return v; /* class_getattr() has set the error */ + if (is_funcobject(v)) { + object *w = newclassmethodobject(v, (object *)cm); + DECREF(v); + return w; + } + DECREF(v); + err_setstr(NameError, name); + return NULL; +} + +static int +classmember_setattr(cm, name, v) + classmemberobject *cm; + char *name; + object *v; +{ + if (v == NULL) + return dictremove(cm->cm_attr, name); + else + return dictinsert(cm->cm_attr, name, v); +} + +typeobject Classmembertype = { + OB_HEAD_INIT(&Typetype) + 0, + "class member", + sizeof(classmemberobject), + 0, + classmember_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + classmember_getattr, /*tp_getattr*/ + classmember_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; + + +/* And finally, here are class method objects */ +/* (Really methods of class members) */ + +typedef struct { + OB_HEAD + object *cm_func; /* The method function */ + object *cm_self; /* The object to which this applies */ +} classmethodobject; + +object * +newclassmethodobject(func, self) + object *func; + object *self; +{ + register classmethodobject *cm; + if (!is_funcobject(func)) { + err_badcall(); + return NULL; + } + cm = NEWOBJ(classmethodobject, &Classmethodtype); + if (cm == NULL) + return NULL; + INCREF(func); + cm->cm_func = func; + INCREF(self); + cm->cm_self = self; + return (object *)cm; +} + +object * +classmethodgetfunc(cm) + register object *cm; +{ + if (!is_classmethodobject(cm)) { + err_badcall(); + return NULL; + } + return ((classmethodobject *)cm)->cm_func; +} + +object * +classmethodgetself(cm) + register object *cm; +{ + if (!is_classmethodobject(cm)) { + err_badcall(); + return NULL; + } + return ((classmethodobject *)cm)->cm_self; +} + +/* Class method methods */ + +#define OFF(x) offsetof(classmethodobject, x) + +static struct memberlist classmethod_memberlist[] = { + {"cm_func", T_OBJECT, OFF(cm_func)}, + {"cm_self", T_OBJECT, OFF(cm_self)}, + {NULL} /* Sentinel */ +}; + +static object * +classmethod_getattr(cm, name) + register classmethodobject *cm; + char *name; +{ + return getmember((char *)cm, classmethod_memberlist, name); +} + +static void +classmethod_dealloc(cm) + register classmethodobject *cm; +{ + DECREF(cm->cm_func); + DECREF(cm->cm_self); + free((ANY *)cm); +} + +typeobject Classmethodtype = { + OB_HEAD_INIT(&Typetype) + 0, + "class method", + sizeof(classmethodobject), + 0, + classmethod_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + classmethod_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; diff --git a/src/classobject.h b/src/classobject.h new file mode 100644 index 0000000..49db837 --- /dev/null +++ b/src/classobject.h @@ -0,0 +1,44 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Class object interface */ + +/* +Classes are really hacked in at the last moment. +It should be possible to use other object types as base classes, +but currently it isn't. We'll see if we can fix that later, sigh... +*/ + +extern typeobject Classtype, Classmembertype, Classmethodtype; + +#define is_classobject(op) ((op)->ob_type == &Classtype) +#define is_classmemberobject(op) ((op)->ob_type == &Classmembertype) +#define is_classmethodobject(op) ((op)->ob_type == &Classmethodtype) + +extern object *newclassobject PROTO((object *, object *)); +extern object *newclassmemberobject PROTO((object *)); +extern object *newclassmethodobject PROTO((object *, object *)); + +extern object *classmethodgetfunc PROTO((object *)); +extern object *classmethodgetself PROTO((object *)); diff --git a/src/compile.c b/src/compile.c new file mode 100644 index 0000000..7904dba --- /dev/null +++ b/src/compile.c @@ -0,0 +1,1772 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Compile an expression node to intermediate code */ + +/* XXX TO DO: + XXX Compute maximum needed stack sizes while compiling + XXX Generate simple jump for break/return outside 'try...finally' + XXX Include function name in code (and module names?) +*/ + +#include "allobjects.h" + +#include "node.h" +#include "token.h" +#include "graminit.h" +#include "compile.h" +#include "opcode.h" +#include "structmember.h" + +#include <ctype.h> + +#define OFF(x) offsetof(codeobject, x) + +static struct memberlist code_memberlist[] = { + {"co_code", T_OBJECT, OFF(co_code)}, + {"co_consts", T_OBJECT, OFF(co_consts)}, + {"co_names", T_OBJECT, OFF(co_names)}, + {"co_filename", T_OBJECT, OFF(co_filename)}, + {NULL} /* Sentinel */ +}; + +static object * +code_getattr(co, name) + codeobject *co; + char *name; +{ + return getmember((char *)co, code_memberlist, name); +} + +static void +code_dealloc(co) + codeobject *co; +{ + XDECREF(co->co_code); + XDECREF(co->co_consts); + XDECREF(co->co_names); + XDECREF(co->co_filename); + DEL(co); +} + +typeobject Codetype = { + OB_HEAD_INIT(&Typetype) + 0, + "code", + sizeof(codeobject), + 0, + code_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + code_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; + +static codeobject *newcodeobject PROTO((object *, object *, object *, char *)); + +static codeobject * +newcodeobject(code, consts, names, filename) + object *code; + object *consts; + object *names; + char *filename; +{ + codeobject *co; + int i; + /* Check argument types */ + if (code == NULL || !is_stringobject(code) || + consts == NULL || !is_listobject(consts) || + names == NULL || !is_listobject(names)) { + err_badcall(); + return NULL; + } + /* Make sure the list of names contains only strings */ + for (i = getlistsize(names); --i >= 0; ) { + object *v = getlistitem(names, i); + if (v == NULL || !is_stringobject(v)) { + err_badcall(); + return NULL; + } + } + co = NEWOBJ(codeobject, &Codetype); + if (co != NULL) { + INCREF(code); + co->co_code = (stringobject *)code; + INCREF(consts); + co->co_consts = consts; + INCREF(names); + co->co_names = names; + if ((co->co_filename = newstringobject(filename)) == NULL) { + DECREF(co); + co = NULL; + } + } + return co; +} + + +/* Data structure used internally */ +struct compiling { + object *c_code; /* string */ + object *c_consts; /* list of objects */ + object *c_names; /* list of strings (names) */ + int c_nexti; /* index into c_code */ + int c_errors; /* counts errors occurred */ + int c_infunction; /* set when compiling a function */ + int c_loops; /* counts nested loops */ + char *c_filename; /* filename of current node */ +}; + +/* Prototypes */ +static int com_init PROTO((struct compiling *, char *)); +static void com_free PROTO((struct compiling *)); +static void com_done PROTO((struct compiling *)); +static void com_node PROTO((struct compiling *, struct _node *)); +static void com_addbyte PROTO((struct compiling *, int)); +static void com_addint PROTO((struct compiling *, int)); +static void com_addoparg PROTO((struct compiling *, int, int)); +static void com_addfwref PROTO((struct compiling *, int, int *)); +static void com_backpatch PROTO((struct compiling *, int)); +static int com_add PROTO((struct compiling *, object *, object *)); +static int com_addconst PROTO((struct compiling *, object *)); +static int com_addname PROTO((struct compiling *, object *)); +static void com_addopname PROTO((struct compiling *, int, node *)); + +static int +com_init(c, filename) + struct compiling *c; + char *filename; +{ + if ((c->c_code = newsizedstringobject((char *)NULL, 0)) == NULL) + goto fail_3; + if ((c->c_consts = newlistobject(0)) == NULL) + goto fail_2; + if ((c->c_names = newlistobject(0)) == NULL) + goto fail_1; + c->c_nexti = 0; + c->c_errors = 0; + c->c_infunction = 0; + c->c_loops = 0; + c->c_filename = filename; + return 1; + + fail_1: + DECREF(c->c_consts); + fail_2: + DECREF(c->c_code); + fail_3: + return 0; +} + +static void +com_free(c) + struct compiling *c; +{ + XDECREF(c->c_code); + XDECREF(c->c_consts); + XDECREF(c->c_names); +} + +static void +com_done(c) + struct compiling *c; +{ + if (c->c_code != NULL) + resizestring(&c->c_code, c->c_nexti); +} + +static void +com_addbyte(c, byte) + struct compiling *c; + int byte; +{ + int len; + if (byte < 0 || byte > 255) { + fprintf(stderr, "XXX compiling bad byte: %d\n", byte); + abort(); + err_setstr(SystemError, "com_addbyte: byte out of range"); + c->c_errors++; + } + if (c->c_code == NULL) + return; + len = getstringsize(c->c_code); + if (c->c_nexti >= len) { + if (resizestring(&c->c_code, len+1000) != 0) { + c->c_errors++; + return; + } + } + getstringvalue(c->c_code)[c->c_nexti++] = byte; +} + +static void +com_addint(c, x) + struct compiling *c; + int x; +{ + com_addbyte(c, x & 0xff); + com_addbyte(c, x >> 8); /* XXX x should be positive */ +} + +static void +com_addoparg(c, op, arg) + struct compiling *c; + int op; + int arg; +{ + com_addbyte(c, op); + com_addint(c, arg); +} + +static void +com_addfwref(c, op, p_anchor) + struct compiling *c; + int op; + int *p_anchor; +{ + /* Compile a forward reference for backpatching */ + int here; + int anchor; + com_addbyte(c, op); + here = c->c_nexti; + anchor = *p_anchor; + *p_anchor = here; + com_addint(c, anchor == 0 ? 0 : here - anchor); +} + +static void +com_backpatch(c, anchor) + struct compiling *c; + int anchor; /* Must be nonzero */ +{ + unsigned char *code = (unsigned char *) getstringvalue(c->c_code); + int target = c->c_nexti; + int lastanchor = 0; + int dist; + int prev; + for (;;) { + /* Make the JUMP instruction at anchor point to target */ + prev = code[anchor] + (code[anchor+1] << 8); + dist = target - (anchor+2); + code[anchor] = dist & 0xff; + code[anchor+1] = dist >> 8; + if (!prev) + break; + lastanchor = anchor; + anchor -= prev; + } +} + +/* Handle constants and names uniformly */ + +static int +com_add(c, list, v) + struct compiling *c; + object *list; + object *v; +{ + int n = getlistsize(list); + int i; + for (i = n; --i >= 0; ) { + object *w = getlistitem(list, i); + if (cmpobject(v, w) == 0) + return i; + } + if (addlistitem(list, v) != 0) + c->c_errors++; + return n; +} + +static int +com_addconst(c, v) + struct compiling *c; + object *v; +{ + return com_add(c, c->c_consts, v); +} + +static int +com_addname(c, v) + struct compiling *c; + object *v; +{ + return com_add(c, c->c_names, v); +} + +static void +com_addopname(c, op, n) + struct compiling *c; + int op; + node *n; +{ + object *v; + int i; + char *name; + if (TYPE(n) == STAR) + name = "*"; + else { + REQ(n, NAME); + name = STR(n); + } + if ((v = newstringobject(name)) == NULL) { + c->c_errors++; + i = 255; + } + else { + i = com_addname(c, v); + DECREF(v); + } + com_addoparg(c, op, i); +} + +static object * +parsenumber(s) + char *s; +{ + extern long strtol(); + extern double atof(); + char *end = s; + long x; + x = strtol(s, &end, 0); + if (*end == '\0') + return newintobject(x); + if (*end == '.' || *end == 'e' || *end == 'E') + return newfloatobject(atof(s)); + err_setstr(RuntimeError, "bad number syntax"); + return NULL; +} + +static object * +parsestr(s) + char *s; +{ + object *v; + int len; + char *buf; + char *p; + int c; + if (*s != '\'') { + err_badcall(); + return NULL; + } + s++; + len = strlen(s); + if (s[--len] != '\'') { + err_badcall(); + return NULL; + } + if (strchr(s, '\\') == NULL) + return newsizedstringobject(s, len); + v = newsizedstringobject((char *)NULL, len); + p = buf = getstringvalue(v); + while (*s != '\0' && *s != '\'') { + if (*s != '\\') { + *p++ = *s++; + continue; + } + s++; + switch (*s++) { + /* XXX This assumes ASCII! */ + case '\\': *p++ = '\\'; break; + case '\'': *p++ = '\''; break; + case 'b': *p++ = '\b'; break; + case 'f': *p++ = '\014'; break; /* FF */ + case 't': *p++ = '\t'; break; + case 'n': *p++ = '\n'; break; + case 'r': *p++ = '\r'; break; + case 'v': *p++ = '\013'; break; /* VT */ + case 'E': *p++ = '\033'; break; /* ESC, not C */ + case 'a': *p++ = '\007'; break; /* BEL, not classic C */ + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + c = s[-1] - '0'; + if ('0' <= *s && *s <= '7') { + c = (c<<3) + *s++ - '0'; + if ('0' <= *s && *s <= '7') + c = (c<<3) + *s++ - '0'; + } + *p++ = c; + break; + case 'x': + if (isxdigit(*s)) { + sscanf(s, "%x", &c); + *p++ = c; + do { + s++; + } while (isxdigit(*s)); + break; + } + /* FALLTHROUGH */ + default: *p++ = '\\'; *p++ = s[-1]; break; + } + } + resizestring(&v, (int)(p - buf)); + return v; +} + +static void +com_list_constructor(c, n) + struct compiling *c; + node *n; +{ + int len; + int i; + object *v, *w; + if (TYPE(n) != testlist) + REQ(n, exprlist); + /* exprlist: expr (',' expr)* [',']; likewise for testlist */ + len = (NCH(n) + 1) / 2; + for (i = 0; i < NCH(n); i += 2) + com_node(c, CHILD(n, i)); + com_addoparg(c, BUILD_LIST, len); +} + +static void +com_atom(c, n) + struct compiling *c; + node *n; +{ + node *ch; + object *v; + int i; + REQ(n, atom); + ch = CHILD(n, 0); + switch (TYPE(ch)) { + case LPAR: + if (TYPE(CHILD(n, 1)) == RPAR) + com_addoparg(c, BUILD_TUPLE, 0); + else + com_node(c, CHILD(n, 1)); + break; + case LSQB: + if (TYPE(CHILD(n, 1)) == RSQB) + com_addoparg(c, BUILD_LIST, 0); + else + com_list_constructor(c, CHILD(n, 1)); + break; + case LBRACE: + com_addoparg(c, BUILD_MAP, 0); + break; + case BACKQUOTE: + com_node(c, CHILD(n, 1)); + com_addbyte(c, UNARY_CONVERT); + break; + case NUMBER: + if ((v = parsenumber(STR(ch))) == NULL) { + c->c_errors++; + i = 255; + } + else { + i = com_addconst(c, v); + DECREF(v); + } + com_addoparg(c, LOAD_CONST, i); + break; + case STRING: + if ((v = parsestr(STR(ch))) == NULL) { + c->c_errors++; + i = 255; + } + else { + i = com_addconst(c, v); + DECREF(v); + } + com_addoparg(c, LOAD_CONST, i); + break; + case NAME: + com_addopname(c, LOAD_NAME, ch); + break; + default: + fprintf(stderr, "node type %d\n", TYPE(ch)); + err_setstr(SystemError, "com_atom: unexpected node type"); + c->c_errors++; + } +} + +static void +com_slice(c, n, op) + struct compiling *c; + node *n; + int op; +{ + if (NCH(n) == 1) { + com_addbyte(c, op); + } + else if (NCH(n) == 2) { + if (TYPE(CHILD(n, 0)) != COLON) { + com_node(c, CHILD(n, 0)); + com_addbyte(c, op+1); + } + else { + com_node(c, CHILD(n, 1)); + com_addbyte(c, op+2); + } + } + else { + com_node(c, CHILD(n, 0)); + com_node(c, CHILD(n, 2)); + com_addbyte(c, op+3); + } +} + +static void +com_apply_subscript(c, n) + struct compiling *c; + node *n; +{ + REQ(n, subscript); + if (NCH(n) == 1 && TYPE(CHILD(n, 0)) != COLON) { + /* It's a single subscript */ + com_node(c, CHILD(n, 0)); + com_addbyte(c, BINARY_SUBSCR); + } + else { + /* It's a slice: [expr] ':' [expr] */ + com_slice(c, n, SLICE); + } +} + +static void +com_call_function(c, n) + struct compiling *c; + node *n; /* EITHER testlist OR ')' */ +{ + if (TYPE(n) == RPAR) { + com_addbyte(c, UNARY_CALL); + } + else { + com_node(c, n); + com_addbyte(c, BINARY_CALL); + } +} + +static void +com_select_member(c, n) + struct compiling *c; + node *n; +{ + com_addopname(c, LOAD_ATTR, n); +} + +static void +com_apply_trailer(c, n) + struct compiling *c; + node *n; +{ + REQ(n, trailer); + switch (TYPE(CHILD(n, 0))) { + case LPAR: + com_call_function(c, CHILD(n, 1)); + break; + case DOT: + com_select_member(c, CHILD(n, 1)); + break; + case LSQB: + com_apply_subscript(c, CHILD(n, 1)); + break; + default: + err_setstr(SystemError, + "com_apply_trailer: unknown trailer type"); + c->c_errors++; + } +} + +static void +com_factor(c, n) + struct compiling *c; + node *n; +{ + int i; + REQ(n, factor); + if (TYPE(CHILD(n, 0)) == PLUS) { + com_factor(c, CHILD(n, 1)); + com_addbyte(c, UNARY_POSITIVE); + } + else if (TYPE(CHILD(n, 0)) == MINUS) { + com_factor(c, CHILD(n, 1)); + com_addbyte(c, UNARY_NEGATIVE); + } + else { + com_atom(c, CHILD(n, 0)); + for (i = 1; i < NCH(n); i++) + com_apply_trailer(c, CHILD(n, i)); + } +} + +static void +com_term(c, n) + struct compiling *c; + node *n; +{ + int i; + int op; + REQ(n, term); + com_factor(c, CHILD(n, 0)); + for (i = 2; i < NCH(n); i += 2) { + com_factor(c, CHILD(n, i)); + switch (TYPE(CHILD(n, i-1))) { + case STAR: + op = BINARY_MULTIPLY; + break; + case SLASH: + op = BINARY_DIVIDE; + break; + case PERCENT: + op = BINARY_MODULO; + break; + default: + err_setstr(SystemError, + "com_term: term operator not *, / or %"); + c->c_errors++; + op = 255; + } + com_addbyte(c, op); + } +} + +static void +com_expr(c, n) + struct compiling *c; + node *n; +{ + int i; + int op; + REQ(n, expr); + com_term(c, CHILD(n, 0)); + for (i = 2; i < NCH(n); i += 2) { + com_term(c, CHILD(n, i)); + switch (TYPE(CHILD(n, i-1))) { + case PLUS: + op = BINARY_ADD; + break; + case MINUS: + op = BINARY_SUBTRACT; + break; + default: + err_setstr(SystemError, + "com_expr: expr operator not + or -"); + c->c_errors++; + op = 255; + } + com_addbyte(c, op); + } +} + +static enum cmp_op +cmp_type(n) + node *n; +{ + REQ(n, comp_op); + /* comp_op: '<' | '>' | '=' | '>' '=' | '<' '=' | '<' '>' + | 'in' | 'not' 'in' | 'is' | 'is' not' */ + if (NCH(n) == 1) { + n = CHILD(n, 0); + switch (TYPE(n)) { + case LESS: return LT; + case GREATER: return GT; + case EQUAL: return EQ; + case NAME: if (strcmp(STR(n), "in") == 0) return IN; + if (strcmp(STR(n), "is") == 0) return IS; + } + } + else if (NCH(n) == 2) { + int t2 = TYPE(CHILD(n, 1)); + switch (TYPE(CHILD(n, 0))) { + case LESS: if (t2 == EQUAL) return LE; + if (t2 == GREATER) return NE; + break; + case GREATER: if (t2 == EQUAL) return GE; + break; + case NAME: if (strcmp(STR(CHILD(n, 1)), "in") == 0) + return NOT_IN; + if (strcmp(STR(CHILD(n, 0)), "is") == 0) + return IS_NOT; + } + } + return BAD; +} + +static void +com_comparison(c, n) + struct compiling *c; + node *n; +{ + int i; + enum cmp_op op; + int anchor; + REQ(n, comparison); /* comparison: expr (comp_op expr)* */ + com_expr(c, CHILD(n, 0)); + if (NCH(n) == 1) + return; + + /**************************************************************** + The following code is generated for all but the last + comparison in a chain: + + label: on stack: opcode: jump to: + + a <code to load b> + a, b DUP_TOP + a, b, b ROT_THREE + b, a, b COMPARE_OP + b, 0-or-1 JUMP_IF_FALSE L1 + b, 1 POP_TOP + b + + We are now ready to repeat this sequence for the next + comparison in the chain. + + For the last we generate: + + b <code to load c> + b, c COMPARE_OP + 0-or-1 + + If there were any jumps to L1 (i.e., there was more than one + comparison), we generate: + + 0-or-1 JUMP_FORWARD L2 + L1: b, 0 ROT_TWO + 0, b POP_TOP + 0 + L2: + ****************************************************************/ + + anchor = 0; + + for (i = 2; i < NCH(n); i += 2) { + com_expr(c, CHILD(n, i)); + if (i+2 < NCH(n)) { + com_addbyte(c, DUP_TOP); + com_addbyte(c, ROT_THREE); + } + op = cmp_type(CHILD(n, i-1)); + if (op == BAD) { + err_setstr(SystemError, + "com_comparison: unknown comparison op"); + c->c_errors++; + } + com_addoparg(c, COMPARE_OP, op); + if (i+2 < NCH(n)) { + com_addfwref(c, JUMP_IF_FALSE, &anchor); + com_addbyte(c, POP_TOP); + } + } + + if (anchor) { + int anchor2 = 0; + com_addfwref(c, JUMP_FORWARD, &anchor2); + com_backpatch(c, anchor); + com_addbyte(c, ROT_TWO); + com_addbyte(c, POP_TOP); + com_backpatch(c, anchor2); + } +} + +static void +com_not_test(c, n) + struct compiling *c; + node *n; +{ + REQ(n, not_test); /* 'not' not_test | comparison */ + if (NCH(n) == 1) { + com_comparison(c, CHILD(n, 0)); + } + else { + com_not_test(c, CHILD(n, 1)); + com_addbyte(c, UNARY_NOT); + } +} + +static void +com_and_test(c, n) + struct compiling *c; + node *n; +{ + int i; + int anchor; + REQ(n, and_test); /* not_test ('and' not_test)* */ + anchor = 0; + i = 0; + for (;;) { + com_not_test(c, CHILD(n, i)); + if ((i += 2) >= NCH(n)) + break; + com_addfwref(c, JUMP_IF_FALSE, &anchor); + com_addbyte(c, POP_TOP); + } + if (anchor) + com_backpatch(c, anchor); +} + +static void +com_test(c, n) + struct compiling *c; + node *n; +{ + int i; + int anchor; + REQ(n, test); /* and_test ('and' and_test)* */ + anchor = 0; + i = 0; + for (;;) { + com_and_test(c, CHILD(n, i)); + if ((i += 2) >= NCH(n)) + break; + com_addfwref(c, JUMP_IF_TRUE, &anchor); + com_addbyte(c, POP_TOP); + } + if (anchor) + com_backpatch(c, anchor); +} + +static void +com_list(c, n) + struct compiling *c; + node *n; +{ + /* exprlist: expr (',' expr)* [',']; likewise for testlist */ + if (NCH(n) == 1) { + com_node(c, CHILD(n, 0)); + } + else { + int i; + int len; + len = (NCH(n) + 1) / 2; + for (i = 0; i < NCH(n); i += 2) + com_node(c, CHILD(n, i)); + com_addoparg(c, BUILD_TUPLE, len); + } +} + + +/* Begin of assignment compilation */ + +static void com_assign_name PROTO((struct compiling *, node *, int)); +static void com_assign PROTO((struct compiling *, node *, int)); + +static void +com_assign_attr(c, n, assigning) + struct compiling *c; + node *n; + int assigning; +{ + com_addopname(c, assigning ? STORE_ATTR : DELETE_ATTR, n); +} + +static void +com_assign_slice(c, n, assigning) + struct compiling *c; + node *n; + int assigning; +{ + com_slice(c, n, assigning ? STORE_SLICE : DELETE_SLICE); +} + +static void +com_assign_subscript(c, n, assigning) + struct compiling *c; + node *n; + int assigning; +{ + com_node(c, n); + com_addbyte(c, assigning ? STORE_SUBSCR : DELETE_SUBSCR); +} + +static void +com_assign_trailer(c, n, assigning) + struct compiling *c; + node *n; + int assigning; +{ + char *name; + REQ(n, trailer); + switch (TYPE(CHILD(n, 0))) { + case LPAR: /* '(' [exprlist] ')' */ + err_setstr(TypeError, "can't assign to function call"); + c->c_errors++; + break; + case DOT: /* '.' NAME */ + com_assign_attr(c, CHILD(n, 1), assigning); + break; + case LSQB: /* '[' subscript ']' */ + n = CHILD(n, 1); + REQ(n, subscript); /* subscript: expr | [expr] ':' [expr] */ + if (NCH(n) > 1 || TYPE(CHILD(n, 0)) == COLON) + com_assign_slice(c, n, assigning); + else + com_assign_subscript(c, CHILD(n, 0), assigning); + break; + default: + err_setstr(TypeError, "unknown trailer type"); + c->c_errors++; + } +} + +static void +com_assign_tuple(c, n, assigning) + struct compiling *c; + node *n; + int assigning; +{ + int i; + if (TYPE(n) != testlist) + REQ(n, exprlist); + if (assigning) + com_addoparg(c, UNPACK_TUPLE, (NCH(n)+1)/2); + for (i = 0; i < NCH(n); i += 2) + com_assign(c, CHILD(n, i), assigning); +} + +static void +com_assign_list(c, n, assigning) + struct compiling *c; + node *n; + int assigning; +{ + int i; + if (assigning) + com_addoparg(c, UNPACK_LIST, (NCH(n)+1)/2); + for (i = 0; i < NCH(n); i += 2) + com_assign(c, CHILD(n, i), assigning); +} + +static void +com_assign_name(c, n, assigning) + struct compiling *c; + node *n; + int assigning; +{ + REQ(n, NAME); + com_addopname(c, assigning ? STORE_NAME : DELETE_NAME, n); +} + +static void +com_assign(c, n, assigning) + struct compiling *c; + node *n; + int assigning; +{ + /* Loop to avoid trivial recursion */ + for (;;) { + switch (TYPE(n)) { + + case exprlist: + case testlist: + if (NCH(n) > 1) { + com_assign_tuple(c, n, assigning); + return; + } + n = CHILD(n, 0); + break; + + case test: + case and_test: + case not_test: + if (NCH(n) > 1) { + err_setstr(TypeError, + "can't assign to operator"); + c->c_errors++; + return; + } + n = CHILD(n, 0); + break; + + case comparison: + if (NCH(n) > 1) { + err_setstr(TypeError, + "can't assign to operator"); + c->c_errors++; + return; + } + n = CHILD(n, 0); + break; + + case expr: + if (NCH(n) > 1) { + err_setstr(TypeError, + "can't assign to operator"); + c->c_errors++; + return; + } + n = CHILD(n, 0); + break; + + case term: + if (NCH(n) > 1) { + err_setstr(TypeError, + "can't assign to operator"); + c->c_errors++; + return; + } + n = CHILD(n, 0); + break; + + case factor: /* ('+'|'-') factor | atom trailer* */ + if (TYPE(CHILD(n, 0)) != atom) { /* '+' | '-' */ + err_setstr(TypeError, + "can't assign to operator"); + c->c_errors++; + return; + } + if (NCH(n) > 1) { /* trailer present */ + int i; + com_node(c, CHILD(n, 0)); + for (i = 1; i+1 < NCH(n); i++) { + com_apply_trailer(c, CHILD(n, i)); + } /* NB i is still alive */ + com_assign_trailer(c, + CHILD(n, i), assigning); + return; + } + n = CHILD(n, 0); + break; + + case atom: + switch (TYPE(CHILD(n, 0))) { + case LPAR: + n = CHILD(n, 1); + if (TYPE(n) == RPAR) { + /* XXX Should allow () = () ??? */ + err_setstr(TypeError, + "can't assign to ()"); + c->c_errors++; + return; + } + break; + case LSQB: + n = CHILD(n, 1); + if (TYPE(n) == RSQB) { + err_setstr(TypeError, + "can't assign to []"); + c->c_errors++; + return; + } + com_assign_list(c, n, assigning); + return; + case NAME: + com_assign_name(c, CHILD(n, 0), assigning); + return; + default: + err_setstr(TypeError, + "can't assign to constant"); + c->c_errors++; + return; + } + break; + + default: + fprintf(stderr, "node type %d\n", TYPE(n)); + err_setstr(SystemError, "com_assign: bad node"); + c->c_errors++; + return; + + } + } +} + +static void +com_expr_stmt(c, n) + struct compiling *c; + node *n; +{ + REQ(n, expr_stmt); /* exprlist ('=' exprlist)* NEWLINE */ + com_node(c, CHILD(n, NCH(n)-2)); + if (NCH(n) == 2) { + com_addbyte(c, PRINT_EXPR); + } + else { + int i; + for (i = 0; i < NCH(n)-3; i+=2) { + if (i+2 < NCH(n)-3) + com_addbyte(c, DUP_TOP); + com_assign(c, CHILD(n, i), 1/*assign*/); + } + } +} + +static void +com_print_stmt(c, n) + struct compiling *c; + node *n; +{ + int i; + REQ(n, print_stmt); /* 'print' (test ',')* [test] NEWLINE */ + for (i = 1; i+1 < NCH(n); i += 2) { + com_node(c, CHILD(n, i)); + com_addbyte(c, PRINT_ITEM); + } + if (TYPE(CHILD(n, NCH(n)-2)) != COMMA) + com_addbyte(c, PRINT_NEWLINE); + /* XXX Alternatively, LOAD_CONST '\n' and then PRINT_ITEM */ +} + +static void +com_return_stmt(c, n) + struct compiling *c; + node *n; +{ + REQ(n, return_stmt); /* 'return' [testlist] NEWLINE */ + if (!c->c_infunction) { + err_setstr(TypeError, "'return' outside function"); + c->c_errors++; + } + if (NCH(n) == 2) + com_addoparg(c, LOAD_CONST, com_addconst(c, None)); + else + com_node(c, CHILD(n, 1)); + com_addbyte(c, RETURN_VALUE); +} + +static void +com_raise_stmt(c, n) + struct compiling *c; + node *n; +{ + REQ(n, raise_stmt); /* 'raise' expr [',' expr] NEWLINE */ + com_node(c, CHILD(n, 1)); + if (NCH(n) > 3) + com_node(c, CHILD(n, 3)); + else + com_addoparg(c, LOAD_CONST, com_addconst(c, None)); + com_addbyte(c, RAISE_EXCEPTION); +} + +static void +com_import_stmt(c, n) + struct compiling *c; + node *n; +{ + int i; + REQ(n, import_stmt); + /* 'import' NAME (',' NAME)* NEWLINE | + 'from' NAME 'import' ('*' | NAME (',' NAME)*) NEWLINE */ + if (STR(CHILD(n, 0))[0] == 'f') { + /* 'from' NAME 'import' ... */ + REQ(CHILD(n, 1), NAME); + com_addopname(c, IMPORT_NAME, CHILD(n, 1)); + for (i = 3; i < NCH(n); i += 2) + com_addopname(c, IMPORT_FROM, CHILD(n, i)); + com_addbyte(c, POP_TOP); + } + else { + /* 'import' ... */ + for (i = 1; i < NCH(n); i += 2) { + com_addopname(c, IMPORT_NAME, CHILD(n, i)); + com_addopname(c, STORE_NAME, CHILD(n, i)); + } + } +} + +static void +com_if_stmt(c, n) + struct compiling *c; + node *n; +{ + int i; + int anchor = 0; + REQ(n, if_stmt); + /*'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] */ + for (i = 0; i+3 < NCH(n); i+=4) { + int a = 0; + node *ch = CHILD(n, i+1); + if (i > 0) + com_addoparg(c, SET_LINENO, ch->n_lineno); + com_node(c, CHILD(n, i+1)); + com_addfwref(c, JUMP_IF_FALSE, &a); + com_addbyte(c, POP_TOP); + com_node(c, CHILD(n, i+3)); + com_addfwref(c, JUMP_FORWARD, &anchor); + com_backpatch(c, a); + com_addbyte(c, POP_TOP); + } + if (i+2 < NCH(n)) + com_node(c, CHILD(n, i+2)); + com_backpatch(c, anchor); +} + +static void +com_while_stmt(c, n) + struct compiling *c; + node *n; +{ + int break_anchor = 0; + int anchor = 0; + int begin; + REQ(n, while_stmt); /* 'while' test ':' suite ['else' ':' suite] */ + com_addfwref(c, SETUP_LOOP, &break_anchor); + begin = c->c_nexti; + com_addoparg(c, SET_LINENO, n->n_lineno); + com_node(c, CHILD(n, 1)); + com_addfwref(c, JUMP_IF_FALSE, &anchor); + com_addbyte(c, POP_TOP); + c->c_loops++; + com_node(c, CHILD(n, 3)); + c->c_loops--; + com_addoparg(c, JUMP_ABSOLUTE, begin); + com_backpatch(c, anchor); + com_addbyte(c, POP_TOP); + com_addbyte(c, POP_BLOCK); + if (NCH(n) > 4) + com_node(c, CHILD(n, 6)); + com_backpatch(c, break_anchor); +} + +static void +com_for_stmt(c, n) + struct compiling *c; + node *n; +{ + object *v; + int break_anchor = 0; + int anchor = 0; + int begin; + REQ(n, for_stmt); + /* 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] */ + com_addfwref(c, SETUP_LOOP, &break_anchor); + com_node(c, CHILD(n, 3)); + v = newintobject(0L); + if (v == NULL) + c->c_errors++; + com_addoparg(c, LOAD_CONST, com_addconst(c, v)); + XDECREF(v); + begin = c->c_nexti; + com_addoparg(c, SET_LINENO, n->n_lineno); + com_addfwref(c, FOR_LOOP, &anchor); + com_assign(c, CHILD(n, 1), 1/*assigning*/); + c->c_loops++; + com_node(c, CHILD(n, 5)); + c->c_loops--; + com_addoparg(c, JUMP_ABSOLUTE, begin); + com_backpatch(c, anchor); + com_addbyte(c, POP_BLOCK); + if (NCH(n) > 8) + com_node(c, CHILD(n, 8)); + com_backpatch(c, break_anchor); +} + +/* Although 'execpt' and 'finally' clauses can be combined + syntactically, they are compiled separately. In fact, + try: S + except E1: S1 + except E2: S2 + ... + finally: Sf + is equivalent to + try: + try: S + except E1: S1 + except E2: S2 + ... + finally: Sf + meaning that the 'finally' clause is entered even if things + go wrong again in an exception handler. Note that this is + not the case for exception handlers: at most one is entered. + + Code generated for "try: S finally: Sf" is as follows: + + SETUP_FINALLY L + <code for S> + POP_BLOCK + LOAD_CONST <nil> + L: <code for Sf> + END_FINALLY + + The special instructions use the block stack. Each block + stack entry contains the instruction that created it (here + SETUP_FINALLY), the level of the value stack at the time the + block stack entry was created, and a label (here L). + + SETUP_FINALLY: + Pushes the current value stack level and the label + onto the block stack. + POP_BLOCK: + Pops en entry from the block stack, and pops the value + stack until its level is the same as indicated on the + block stack. (The label is ignored.) + END_FINALLY: + Pops a variable number of entries from the *value* stack + and re-raises the exception they specify. The number of + entries popped depends on the (pseudo) exception type. + + The block stack is unwound when an exception is raised: + when a SETUP_FINALLY entry is found, the exception is pushed + onto the value stack (and the exception condition is cleared), + and the interpreter jumps to the label gotten from the block + stack. + + Code generated for "try: S except E1, V1: S1 except E2, V2: S2 ...": + (The contents of the value stack is shown in [], with the top + at the right; 'tb' is trace-back info, 'val' the exception's + associated value, and 'exc' the exception.) + + Value stack Label Instruction Argument + [] SETUP_EXCEPT L1 + [] <code for S> + [] POP_BLOCK + [] JUMP_FORWARD L0 + + [tb, val, exc] L1: DUP ) + [tb, val, exc, exc] <evaluate E1> ) + [tb, val, exc, exc, E1] COMPARE_OP EXC_MATCH ) only if E1 + [tb, val, exc, 1-or-0] JUMP_IF_FALSE L2 ) + [tb, val, exc, 1] POP ) + [tb, val, exc] POP + [tb, val] <assign to V1> (or POP if no V1) + [tb] POP + [] <code for S1> + JUMP_FORWARD L0 + + [tb, val, exc, 0] L2: POP + [tb, val, exc] DUP + .............................etc....................... + + [tb, val, exc, 0] Ln+1: POP + [tb, val, exc] END_FINALLY # re-raise exception + + [] L0: <next statement> + + Of course, parts are not generated if Vi or Ei is not present. +*/ + +static void +com_try_stmt(c, n) + struct compiling *c; + node *n; +{ + int finally_anchor = 0; + int except_anchor = 0; + REQ(n, try_stmt); + /* 'try' ':' suite (except_clause ':' suite)* ['finally' ':' suite] */ + + if (NCH(n) > 3 && TYPE(CHILD(n, NCH(n)-3)) != except_clause) { + /* Have a 'finally' clause */ + com_addfwref(c, SETUP_FINALLY, &finally_anchor); + } + if (NCH(n) > 3 && TYPE(CHILD(n, 3)) == except_clause) { + /* Have an 'except' clause */ + com_addfwref(c, SETUP_EXCEPT, &except_anchor); + } + com_node(c, CHILD(n, 2)); + if (except_anchor) { + int end_anchor = 0; + int i; + node *ch; + com_addbyte(c, POP_BLOCK); + com_addfwref(c, JUMP_FORWARD, &end_anchor); + com_backpatch(c, except_anchor); + for (i = 3; + i < NCH(n) && TYPE(ch = CHILD(n, i)) == except_clause; + i += 3) { + /* except_clause: 'except' [expr [',' expr]] */ + if (except_anchor == 0) { + err_setstr(TypeError, + "default 'except:' must be last"); + c->c_errors++; + break; + } + except_anchor = 0; + com_addoparg(c, SET_LINENO, ch->n_lineno); + if (NCH(ch) > 1) { + com_addbyte(c, DUP_TOP); + com_node(c, CHILD(ch, 1)); + com_addoparg(c, COMPARE_OP, EXC_MATCH); + com_addfwref(c, JUMP_IF_FALSE, &except_anchor); + com_addbyte(c, POP_TOP); + } + com_addbyte(c, POP_TOP); + if (NCH(ch) > 3) + com_assign(c, CHILD(ch, 3), 1/*assigning*/); + else + com_addbyte(c, POP_TOP); + com_addbyte(c, POP_TOP); + com_node(c, CHILD(n, i+2)); + com_addfwref(c, JUMP_FORWARD, &end_anchor); + if (except_anchor) { + com_backpatch(c, except_anchor); + com_addbyte(c, POP_TOP); + } + } + com_addbyte(c, END_FINALLY); + com_backpatch(c, end_anchor); + } + if (finally_anchor) { + node *ch; + com_addbyte(c, POP_BLOCK); + com_addoparg(c, LOAD_CONST, com_addconst(c, None)); + com_backpatch(c, finally_anchor); + ch = CHILD(n, NCH(n)-1); + com_addoparg(c, SET_LINENO, ch->n_lineno); + com_node(c, ch); + com_addbyte(c, END_FINALLY); + } +} + +static void +com_suite(c, n) + struct compiling *c; + node *n; +{ + REQ(n, suite); + /* simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT */ + if (NCH(n) == 1) { + com_node(c, CHILD(n, 0)); + } + else { + int i; + for (i = 0; i < NCH(n); i++) { + node *ch = CHILD(n, i); + if (TYPE(ch) == stmt) + com_node(c, ch); + } + } +} + +static void +com_funcdef(c, n) + struct compiling *c; + node *n; +{ + object *v; + REQ(n, funcdef); /* funcdef: 'def' NAME parameters ':' suite */ + v = (object *)compile(n, c->c_filename); + if (v == NULL) + c->c_errors++; + else { + int i = com_addconst(c, v); + com_addoparg(c, LOAD_CONST, i); + com_addbyte(c, BUILD_FUNCTION); + com_addopname(c, STORE_NAME, CHILD(n, 1)); + DECREF(v); + } +} + +static void +com_bases(c, n) + struct compiling *c; + node *n; +{ + int i, nbases; + REQ(n, baselist); + /* + baselist: atom arguments (',' atom arguments)* + arguments: '(' [testlist] ')' + */ + for (i = 0; i < NCH(n); i += 3) + com_node(c, CHILD(n, i)); + com_addoparg(c, BUILD_TUPLE, (NCH(n)+1) / 3); +} + +static void +com_classdef(c, n) + struct compiling *c; + node *n; +{ + object *v; + REQ(n, classdef); + /* + classdef: 'class' NAME parameters ['=' baselist] ':' suite + baselist: atom arguments (',' atom arguments)* + arguments: '(' [testlist] ')' + */ + if (NCH(n) == 7) + com_bases(c, CHILD(n, 4)); + else + com_addoparg(c, LOAD_CONST, com_addconst(c, None)); + v = (object *)compile(n, c->c_filename); + if (v == NULL) + c->c_errors++; + else { + int i = com_addconst(c, v); + com_addoparg(c, LOAD_CONST, i); + com_addbyte(c, BUILD_FUNCTION); + com_addbyte(c, UNARY_CALL); + com_addbyte(c, BUILD_CLASS); + com_addopname(c, STORE_NAME, CHILD(n, 1)); + DECREF(v); + } +} + +static void +com_node(c, n) + struct compiling *c; + node *n; +{ + switch (TYPE(n)) { + + /* Definition nodes */ + + case funcdef: + com_funcdef(c, n); + break; + case classdef: + com_classdef(c, n); + break; + + /* Trivial parse tree nodes */ + + case stmt: + case flow_stmt: + com_node(c, CHILD(n, 0)); + break; + + case simple_stmt: + case compound_stmt: + com_addoparg(c, SET_LINENO, n->n_lineno); + com_node(c, CHILD(n, 0)); + break; + + /* Statement nodes */ + + case expr_stmt: + com_expr_stmt(c, n); + break; + case print_stmt: + com_print_stmt(c, n); + break; + case del_stmt: /* 'del' exprlist NEWLINE */ + com_assign(c, CHILD(n, 1), 0/*delete*/); + break; + case pass_stmt: + break; + case break_stmt: + if (c->c_loops == 0) { + err_setstr(TypeError, "'break' outside loop"); + c->c_errors++; + } + com_addbyte(c, BREAK_LOOP); + break; + case return_stmt: + com_return_stmt(c, n); + break; + case raise_stmt: + com_raise_stmt(c, n); + break; + case import_stmt: + com_import_stmt(c, n); + break; + case if_stmt: + com_if_stmt(c, n); + break; + case while_stmt: + com_while_stmt(c, n); + break; + case for_stmt: + com_for_stmt(c, n); + break; + case try_stmt: + com_try_stmt(c, n); + break; + case suite: + com_suite(c, n); + break; + + /* Expression nodes */ + + case testlist: + com_list(c, n); + break; + case test: + com_test(c, n); + break; + case and_test: + com_and_test(c, n); + break; + case not_test: + com_not_test(c, n); + break; + case comparison: + com_comparison(c, n); + break; + case exprlist: + com_list(c, n); + break; + case expr: + com_expr(c, n); + break; + case term: + com_term(c, n); + break; + case factor: + com_factor(c, n); + break; + case atom: + com_atom(c, n); + break; + + default: + fprintf(stderr, "node type %d\n", TYPE(n)); + err_setstr(SystemError, "com_node: unexpected node type"); + c->c_errors++; + } +} + +static void com_fplist PROTO((struct compiling *, node *)); + +static void +com_fpdef(c, n) + struct compiling *c; + node *n; +{ + REQ(n, fpdef); /* fpdef: NAME | '(' fplist ')' */ + if (TYPE(CHILD(n, 0)) == LPAR) + com_fplist(c, CHILD(n, 1)); + else + com_addopname(c, STORE_NAME, CHILD(n, 0)); +} + +static void +com_fplist(c, n) + struct compiling *c; + node *n; +{ + REQ(n, fplist); /* fplist: fpdef (',' fpdef)* */ + if (NCH(n) == 1) { + com_fpdef(c, CHILD(n, 0)); + } + else { + int i; + com_addoparg(c, UNPACK_TUPLE, (NCH(n)+1)/2); + for (i = 0; i < NCH(n); i += 2) + com_fpdef(c, CHILD(n, i)); + } +} + +static void +com_file_input(c, n) + struct compiling *c; + node *n; +{ + int i; + REQ(n, file_input); /* (NEWLINE | stmt)* ENDMARKER */ + for (i = 0; i < NCH(n); i++) { + node *ch = CHILD(n, i); + if (TYPE(ch) != ENDMARKER && TYPE(ch) != NEWLINE) + com_node(c, ch); + } +} + +/* Top-level compile-node interface */ + +static void +compile_funcdef(c, n) + struct compiling *c; + node *n; +{ + node *ch; + REQ(n, funcdef); /* funcdef: 'def' NAME parameters ':' suite */ + ch = CHILD(n, 2); /* parameters: '(' [fplist] ')' */ + ch = CHILD(ch, 1); /* ')' | fplist */ + if (TYPE(ch) == RPAR) + com_addbyte(c, REFUSE_ARGS); + else { + com_addbyte(c, REQUIRE_ARGS); + com_fplist(c, ch); + } + c->c_infunction = 1; + com_node(c, CHILD(n, 4)); + c->c_infunction = 0; + com_addoparg(c, LOAD_CONST, com_addconst(c, None)); + com_addbyte(c, RETURN_VALUE); +} + +static void +compile_node(c, n) + struct compiling *c; + node *n; +{ + com_addoparg(c, SET_LINENO, n->n_lineno); + + switch (TYPE(n)) { + + case single_input: /* One interactive command */ + /* NEWLINE | simple_stmt | compound_stmt NEWLINE */ + com_addbyte(c, REFUSE_ARGS); + n = CHILD(n, 0); + if (TYPE(n) != NEWLINE) + com_node(c, n); + com_addoparg(c, LOAD_CONST, com_addconst(c, None)); + com_addbyte(c, RETURN_VALUE); + break; + + case file_input: /* A whole file, or built-in function exec() */ + com_addbyte(c, REFUSE_ARGS); + com_file_input(c, n); + com_addoparg(c, LOAD_CONST, com_addconst(c, None)); + com_addbyte(c, RETURN_VALUE); + break; + + case expr_input: /* Built-in function eval() */ + com_addbyte(c, REFUSE_ARGS); + com_node(c, CHILD(n, 0)); + com_addbyte(c, RETURN_VALUE); + break; + + case eval_input: /* Built-in function input() */ + com_addbyte(c, REFUSE_ARGS); + com_node(c, CHILD(n, 0)); + com_addbyte(c, RETURN_VALUE); + break; + + case funcdef: /* A function definition */ + compile_funcdef(c, n); + break; + + case classdef: /* A class definition */ + /* 'class' NAME parameters ['=' baselist] ':' suite */ + com_addbyte(c, REFUSE_ARGS); + com_node(c, CHILD(n, NCH(n)-1)); + com_addbyte(c, LOAD_LOCALS); + com_addbyte(c, RETURN_VALUE); + break; + + default: + fprintf(stderr, "node type %d\n", TYPE(n)); + err_setstr(SystemError, "compile_node: unexpected node type"); + c->c_errors++; + } +} + +codeobject * +compile(n, filename) + node *n; + char *filename; +{ + struct compiling sc; + codeobject *co; + if (!com_init(&sc, filename)) + return NULL; + compile_node(&sc, n); + com_done(&sc); + if (sc.c_errors == 0) + co = newcodeobject(sc.c_code, sc.c_consts, sc.c_names, filename); + else + co = NULL; + com_free(&sc); + return co; +} diff --git a/src/compile.h b/src/compile.h new file mode 100644 index 0000000..fb66ea7 --- /dev/null +++ b/src/compile.h @@ -0,0 +1,47 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Definitions for compiled intermediate code */ + + +/* An intermediate code fragment contains: + - a string that encodes the instructions, + - a list of the constants, + - and a list of the names used. */ + +typedef struct { + OB_HEAD + stringobject *co_code; /* instruction opcodes */ + object *co_consts; /* list of immutable constant objects */ + object *co_names; /* list of stringobjects */ + object *co_filename; /* string */ +} codeobject; + +extern typeobject Codetype; + +#define is_codeobject(op) ((op)->ob_type == &Codetype) + + +/* Public interface */ +codeobject *compile PROTO((struct _node *, char *)); diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..9d153c1 --- /dev/null +++ b/src/config.c @@ -0,0 +1,180 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Configurable Python configuration file */ + +#include <stdio.h> + +#ifdef USE_STDWIN +#include <stdwin.h> + +static int use_stdwin; +#endif + +/*ARGSUSED*/ +void +initargs(p_argc, p_argv) + int *p_argc; + char ***p_argv; +{ +#ifdef USE_STDWIN + extern char *getenv(); + char *display; + + /* Ignore an initial argument of '-s', for backward compatibility */ + if (*p_argc > 1 && strcmp((*p_argv)[1], "-s") == 0) { + (*p_argv)[1] = (*p_argv)[0]; + (*p_argc)--, (*p_argv)++; + } + + /* Assume we have to initialize stdwin if either of the following + conditions holds: + - the environment variable $DISPLAY is set + - there is an argument "-display" somewhere + */ + + display = getenv("DISPLAY"); + if (display != 0) + use_stdwin = 1; + else { + int i; + /* Scan through the arguments looking for "-display" */ + for (i = 1; i < *p_argc; i++) { + if (strcmp((*p_argv)[i], "-display") == 0) { + use_stdwin = 1; + break; + } + } + } + + if (use_stdwin) + wargs(p_argc, p_argv); +#endif +} + +void +initcalls() +{ +} + +void +donecalls() +{ +#ifdef USE_STDWIN + if (use_stdwin) + wdone(); +#endif +#ifdef USE_AUDIO + asa_done(); +#endif +} + +#ifdef USE_STDWIN +static void +maybeinitstdwin() +{ + if (use_stdwin) + initstdwin(); + else + fprintf(stderr, + "No $DISPLAY nor -display arg -- stdwin not available\n"); +} +#endif + +#ifndef PYTHONPATH +#define PYTHONPATH ".:/usr/local/lib/python" +#endif + +extern char *getenv(); + +char * +getpythonpath() +{ + char *path = getenv("PYTHONPATH"); + if (path == 0) + path = PYTHONPATH; + return path; +} + + +/* Table of built-in modules. + These are initialized when first imported. */ + +/* Standard modules */ +extern void inittime(); +extern void initmath(); +extern void initregexp(); +extern void initposix(); +#ifdef USE_AUDIO +extern void initaudio(); +#endif +#ifdef USE_AMOEBA +extern void initamoeba(); +#endif +#ifdef USE_GL +extern void initgl(); +#ifdef USE_PANEL +extern void initpanel(); +#endif +#endif +#ifdef USE_STDWIN +extern void maybeinitstdwin(); +#endif + +struct { + char *name; + void (*initfunc)(); +} inittab[] = { + + /* Standard modules */ + + {"time", inittime}, + {"math", initmath}, + {"regexp", initregexp}, + {"posix", initposix}, + + + /* Optional modules */ + +#ifdef USE_AUDIO + {"audio", initaudio}, +#endif + +#ifdef USE_AMOEBA + {"amoeba", initamoeba}, +#endif + +#ifdef USE_GL + {"gl", initgl}, +#ifdef USE_PANEL + {"pnl", initpanel}, +#endif +#endif + +#ifdef USE_STDWIN + {"stdwin", maybeinitstdwin}, +#endif + + {0, 0} /* Sentinel */ +}; diff --git a/src/configmac.c b/src/configmac.c new file mode 100644 index 0000000..c73130a --- /dev/null +++ b/src/configmac.c @@ -0,0 +1,109 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Configuration using STDWIN on the Mac (THINK_C or MPW) */ + +#ifdef THINK_C +#define USE_STDWIN +#endif + +#ifdef USE_STDWIN +#include "stdwin.h" +#endif + +void +initargs(p_argc, p_argv) + int *p_argc; + char ***p_argv; +{ +#ifdef USE_STDWIN + +#ifdef THINK_C_3_0 + wsetstdio(1); +#else + /* This printf() statement is really needed only + to initialize THINK C 4.0's stdio: */ + printf( +"Python 4.0, Copyright 1990 Stichting Mathematisch Centrum, Amsterdam\n"); +#endif + + wargs(p_argc, p_argv); +#endif +} + +void +initcalls() +{ +} + +void +donecalls() +{ +#ifdef USE_STDWIN + wdone(); +#endif +} + +#ifndef PYTHONPATH +/* On the Mac, the search path is a space-separated list of directories */ +#define PYTHONPATH ": :lib :lib:stdwin :lib:mac :lib:demo" +#endif + +char * +getpythonpath() +{ + return PYTHONPATH; +} + + +/* Table of built-in modules. + These are initialized when first imported. */ + +/* Standard modules */ +extern void inittime(); +extern void initmath(); +extern void initregexp(); + +/* Mac-specific modules */ +extern void initmac(); +#ifdef USE_STDWIN +extern void initstdwin(); +#endif + +struct { + char *name; + void (*initfunc)(); +} inittab[] = { + /* Standard modules */ + {"time", inittime}, + {"math", initmath}, + {"regexp", initregexp}, + + /* Mac-specific modules */ + {"mac", initmac}, +#ifdef USE_STDWIN + {"stdwin", initstdwin}, +#endif + {0, 0} /* Sentinel */ +}; diff --git a/src/cstubs b/src/cstubs new file mode 100644 index 0000000..3996572 --- /dev/null +++ b/src/cstubs @@ -0,0 +1,999 @@ +/* +Input used to generate the Python module "glmodule.c". +The stub generator is a Python script called "cgen". + +Each definition must be contained on one line: + +<returntype> <name> <type> <arg> <type> <arg> + +<returntype> can be: void, short, long (XXX maybe others?) + +<type> can be: char, string, short, float, long, or double + string indicates a null terminated string; + if <type> is char and <arg> begins with a *, the * is stripped + and <type> is changed into string + +<arg> has the form <mode> or <mode>[<subscript>] + where <mode> can be + s: arg is sent + r: arg is received (arg is a pointer) + and <subscript> can be (N and I are numbers): + N + argI + retval + N*argI + N*retval +*/ + +#include <gl.h> +#include <device.h> + +#include "allobjects.h" +#include "import.h" +#include "modsupport.h" +#include "cgensupport.h" + +/* +Some stubs are too complicated for the stub generator. +We can include manually written versions of them here. +A line starting with '%' gives the name of the function so the stub +generator can include it in the table of functions. +*/ + +/* +varray -- an array of v.. calls. +The argument is an array (maybe list or tuple) of points. +Each point must be a tuple or list of coordinates (x, y, z). +The points may be 2- or 3-dimensional but must all have the +same dimension. Float and int values may be mixed however. +The points are always converted to 3D double precision points +by assuming z=0.0 if necessary (as indicated in the man page), +and for each point v3d() is called. +*/ + +% varray + +static object * +gl_varray(self, args) + object *self; + object *args; +{ + object *v, *w; + int i, n, width; + double vec[3]; + object * (*getitem) FPROTO((object *, int)); + + if (!getiobjectarg(args, 1, 0, &v)) + return NULL; + + if (is_listobject(v)) { + n = getlistsize(v); + getitem = getlistitem; + } + else if (is_tupleobject(v)) { + n = gettuplesize(v); + getitem = gettupleitem; + } + else { + err_badarg(); + return NULL; + } + + if (n == 0) { + INCREF(None); + return None; + } + if (n > 0) + w = (*getitem)(v, 0); + + width = 0; + if (w == NULL) { + } + else if (is_listobject(w)) { + width = getlistsize(w); + } + else if (is_tupleobject(w)) { + width = gettuplesize(w); + } + + switch (width) { + case 2: + vec[2] = 0.0; + /* Fall through */ + case 3: + break; + default: + err_badarg(); + return NULL; + } + + for (i = 0; i < n; i++) { + w = (*getitem)(v, i); + if (!getidoublearray(w, 1, 0, width, vec)) + return NULL; + v3d(vec); + } + + INCREF(None); + return None; +} + +/* +vnarray, nvarray -- an array of n3f and v3f calls. +The argument is an array (list or tuple) of pairs of points and normals. +Each pair is a tuple (NOT a list) of a point and a normal for that point. +Each point or normal must be a tuple (NOT a list) of coordinates (x, y, z). +Three coordinates must be given. Float and int values may be mixed. +For each pair, n3f() is called for the normal, and then v3f() is called +for the vector. + +vnarray and nvarray differ only in the order of the vector and normal in +the pair: vnarray expects (v, n) while nvarray expects (n, v). +*/ + +static object *gen_nvarray(); /* Forward */ + +% nvarray + +static object * +gl_nvarray(self, args) + object *self; + object *args; +{ + return gen_nvarray(args, 0); +} + +% vnarray + +static object * +gl_vnarray(self, args) + object *self; + object *args; +{ + return gen_nvarray(args, 1); +} + +/* Generic, internal version of {nv,nv}array: inorm indicates the + argument order, 0: normal first, 1: vector first. */ + +static object * +gen_nvarray(args, inorm) + object *args; + int inorm; +{ + object *v, *w, *wnorm, *wvec; + int i, n; + float norm[3], vec[3]; + object * (*getitem) FPROTO((object *, int)); + + if (!getiobjectarg(args, 1, 0, &v)) + return NULL; + + if (is_listobject(v)) { + n = getlistsize(v); + getitem = getlistitem; + } + else if (is_tupleobject(v)) { + n = gettuplesize(v); + getitem = gettupleitem; + } + else { + err_badarg(); + return NULL; + } + + for (i = 0; i < n; i++) { + w = (*getitem)(v, i); + if (!is_tupleobject(w) || gettuplesize(w) != 2) { + err_badarg(); + return NULL; + } + wnorm = gettupleitem(w, inorm); + wvec = gettupleitem(w, 1 - inorm); + if (!getifloatarray(wnorm, 1, 0, 3, norm) || + !getifloatarray(wvec, 1, 0, 3, vec)) + return NULL; + n3f(norm); + v3f(vec); + } + + INCREF(None); + return None; +} + +/* nurbssurface(s_knots[], t_knots[], ctl[][], s_order, t_order, type). + The dimensions of ctl[] are computed as follows: + [len(s_knots) - s_order], [len(t_knots) - t_order] +*/ + +% nurbssurface + +static object * +gl_nurbssurface(self, args) + object *self; + object *args; +{ + long arg1 ; + double * arg2 ; + long arg3 ; + double * arg4 ; + double *arg5 ; + long arg6 ; + long arg7 ; + long arg8 ; + long ncoords; + long s_byte_stride, t_byte_stride; + long s_nctl, t_nctl; + long s, t; + object *v, *w, *pt; + double *pnext; + if (!getilongarraysize(args, 6, 0, &arg1)) + return NULL; + if ((arg2 = NEW(double, arg1 )) == NULL) { + return err_nomem(); + } + if (!getidoublearray(args, 6, 0, arg1 , arg2)) + return NULL; + if (!getilongarraysize(args, 6, 1, &arg3)) + return NULL; + if ((arg4 = NEW(double, arg3 )) == NULL) { + return err_nomem(); + } + if (!getidoublearray(args, 6, 1, arg3 , arg4)) + return NULL; + if (!getilongarg(args, 6, 3, &arg6)) + return NULL; + if (!getilongarg(args, 6, 4, &arg7)) + return NULL; + if (!getilongarg(args, 6, 5, &arg8)) + return NULL; + if (arg8 == N_XYZ) + ncoords = 3; + else if (arg8 == N_XYZW) + ncoords = 4; + else { + err_badarg(); + return NULL; + } + s_nctl = arg1 - arg6; + t_nctl = arg3 - arg7; + if (!getiobjectarg(args, 6, 2, &v)) + return NULL; + if (!is_listobject(v) || getlistsize(v) != s_nctl) { + err_badarg(); + return NULL; + } + if ((arg5 = NEW(double, s_nctl*t_nctl*ncoords )) == NULL) { + return err_nomem(); + } + pnext = arg5; + for (s = 0; s < s_nctl; s++) { + w = getlistitem(v, s); + if (w == NULL || !is_listobject(w) || + getlistsize(w) != t_nctl) { + err_badarg(); + return NULL; + } + for (t = 0; t < t_nctl; t++) { + pt = getlistitem(w, t); + if (!getidoublearray(pt, 1, 0, ncoords, pnext)) + return NULL; + pnext += ncoords; + } + } + s_byte_stride = sizeof(double) * ncoords; + t_byte_stride = s_byte_stride * s_nctl; + nurbssurface( arg1 , arg2 , arg3 , arg4 , + s_byte_stride , t_byte_stride , arg5 , arg6 , arg7 , arg8 ); + DEL(arg2); + DEL(arg4); + DEL(arg5); + INCREF(None); + return None; +} + +/* nurbscurve(knots, ctlpoints, order, type). + The length of ctlpoints is len(knots)-order. */ + +%nurbscurve + +static object * +gl_nurbscurve(self, args) + object *self; + object *args; +{ + long arg1 ; + double * arg2 ; + long arg3 ; + double * arg4 ; + long arg5 ; + long arg6 ; + int ncoords, npoints; + int i; + object *v; + double *pnext; + if (!getilongarraysize(args, 4, 0, &arg1)) + return NULL; + if ((arg2 = NEW(double, arg1 )) == NULL) { + return err_nomem(); + } + if (!getidoublearray(args, 4, 0, arg1 , arg2)) + return NULL; + if (!getilongarg(args, 4, 2, &arg5)) + return NULL; + if (!getilongarg(args, 4, 3, &arg6)) + return NULL; + if (arg6 == N_ST) + ncoords = 2; + else if (arg6 == N_STW) + ncoords = 3; + else { + err_badarg(); + return NULL; + } + npoints = arg1 - arg5; + if (!getiobjectarg(args, 4, 1, &v)) + return NULL; + if (!is_listobject(v) || getlistsize(v) != npoints) { + err_badarg(); + return NULL; + } + if ((arg4 = NEW(double, npoints*ncoords )) == NULL) { + return err_nomem(); + } + pnext = arg4; + for (i = 0; i < npoints; i++) { + if (!getidoublearray(getlistitem(v, i), 1, 0, ncoords, pnext)) + return NULL; + pnext += ncoords; + } + arg3 = (sizeof(double)) * ncoords; + nurbscurve( arg1 , arg2 , arg3 , arg4 , arg5 , arg6 ); + DEL(arg2); + DEL(arg4); + INCREF(None); + return None; +} + +/* pwlcurve(points, type). + Points is a list of points. Type must be N_ST. */ + +%pwlcurve + +static object * +gl_pwlcurve(self, args) + object *self; + object *args; +{ + object *v; + long type; + double *data, *pnext; + long npoints, ncoords; + int i; + if (!getiobjectarg(args, 2, 0, &v)) + return NULL; + if (!getilongarg(args, 2, 1, &type)) + return NULL; + if (!is_listobject(v)) { + err_badarg(); + return NULL; + } + npoints = getlistsize(v); + if (type == N_ST) + ncoords = 2; + else { + err_badarg(); + return NULL; + } + if ((data = NEW(double, npoints*ncoords)) == NULL) { + return err_nomem(); + } + pnext = data; + for (i = 0; i < npoints; i++) { + if (!getidoublearray(getlistitem(v, i), 1, 0, ncoords, pnext)) + return NULL; + pnext += ncoords; + } + pwlcurve(npoints, data, sizeof(double)*ncoords, type); + DEL(data); + INCREF(None); + return None; +} + + +/* Picking and Selecting */ + +static short *pickbuffer = NULL; +static long pickbuffersize; + +static object * +pick_select(args, func) + object *args; + void (*func)(); +{ + if (!getilongarg(args, 1, 0, &pickbuffersize)) + return NULL; + if (pickbuffer != NULL) { + err_setstr(RuntimeError, + "pick/gselect: already picking/selecting"); + return NULL; + } + if ((pickbuffer = NEW(short, pickbuffersize)) == NULL) { + return err_nomem(); + } + (*func)(pickbuffer, pickbuffersize); + INCREF(None); + return None; +} + +static object * +endpick_select(args, func) + object *args; + long (*func)(); +{ + object *v, *w; + int i, nhits, n; + if (!getnoarg(args)) + return NULL; + if (pickbuffer == NULL) { + err_setstr(RuntimeError, + "endpick/endselect: not in pick/select mode"); + return NULL; + } + nhits = (*func)(pickbuffer); + if (nhits < 0) { + nhits = -nhits; /* How to report buffer overflow otherwise? */ + } + /* Scan the buffer to see how many integers */ + n = 0; + for (; nhits > 0; nhits--) { + n += 1 + pickbuffer[n]; + } + v = newlistobject(n); + if (v == NULL) + return NULL; + /* XXX Could do it nicer and interpret the data structure here, + returning a list of lists. But this can be done in Python... */ + for (i = 0; i < n; i++) { + w = newintobject((long)pickbuffer[i]); + if (w == NULL) { + DECREF(v); + return NULL; + } + setlistitem(v, i, w); + } + DEL(pickbuffer); + pickbuffer = NULL; + return v; +} + +extern void pick(), gselect(); +extern long endpick(), endselect(); + +%pick +static object *gl_pick(self, args) object *self, *args; { + return pick_select(args, pick); +} + +%endpick +static object *gl_endpick(self, args) object *self, *args; { + return endpick_select(args, endpick); +} + +%gselect +static object *gl_gselect(self, args) object *self, *args; { + return pick_select(args, gselect); +} + +%endselect +static object *gl_endselect(self, args) object *self, *args; { + return endpick_select(args, endselect); +} + + +/* XXX The generator botches this one. Here's a quick hack to fix it. */ + +% getmatrix float r[16] + +static object * +gl_getmatrix(self, args) + object *self; + object *args; +{ + float arg1 [ 16 ] ; + object *v, *w; + int i; + getmatrix( arg1 ); + v = newlistobject(16); + if (v == NULL) { + return err_nomem(); + } + for (i = 0; i < 16; i++) { + w = mknewfloatobject(arg1[i]); + if (w == NULL) { + DECREF(v); + return NULL; + } + setlistitem(v, i, w); + } + return v; +} + +/* End of manually written stubs */ + +%% + +long getshade +void devport short s long s +void rdr2i long s long s +void rectfs short s short s short s short s +void rects short s short s short s short s +void rmv2i long s long s +void noport +void popviewport +void clear +void clearhitcode +void closeobj +void cursoff +void curson +void doublebuffer +void finish +void gconfig +void ginit +void greset +void multimap +void onemap +void popattributes +void popmatrix +void pushattributes +void pushmatrix +void pushviewport +void qreset +void RGBmode +void singlebuffer +void swapbuffers +void gsync +void tpon +void tpoff +void clkon +void clkoff +void ringbell +#void callfunc +void gbegin +void textinit +void initnames +void pclos +void popname +void spclos +void zclear +void screenspace +void reshapeviewport +void winpush +void winpop +void foreground +void endfullscrn +void endpupmode +void fullscrn +void pupmode +void winconstraints +void pagecolor short s +void textcolor short s +void color short s +void curveit short s +void font short s +void linewidth short s +void setlinestyle short s +void setmap short s +void swapinterval short s +void writemask short s +void textwritemask short s +void qdevice short s +void unqdevice short s +void curvebasis short s +void curveprecision short s +void loadname short s +void passthrough short s +void pushname short s +void setmonitor short s +void setshade short s +void setpattern short s +void pagewritemask short s +# +void callobj long s +void delobj long s +void editobj long s +void makeobj long s +void maketag long s +void chunksize long s +void compactify long s +void deltag long s +void lsrepeat long s +void objinsert long s +void objreplace long s +void winclose long s +void blanktime long s +void freepup long s +# This is not in the library!? +###void pupcolor long s +# +void backbuffer long s +void frontbuffer long s +void lsbackup long s +void resetls long s +void lampon long s +void lampoff long s +void setbell long s +void blankscreen long s +void depthcue long s +void zbuffer long s +void backface long s +# +void cmov2i long s long s +void draw2i long s long s +void move2i long s long s +void pnt2i long s long s +void patchbasis long s long s +void patchprecision long s long s +void pdr2i long s long s +void pmv2i long s long s +void rpdr2i long s long s +void rpmv2i long s long s +void xfpt2i long s long s +void objdelete long s long s +void patchcurves long s long s +void minsize long s long s +void maxsize long s long s +void keepaspect long s long s +void prefsize long s long s +void stepunit long s long s +void fudge long s long s +void winmove long s long s +# +void attachcursor short s short s +void deflinestyle short s short s +void noise short s short s +void picksize short s short s +void qenter short s short s +void setdepth short s short s +void cmov2s short s short s +void draw2s short s short s +void move2s short s short s +void pdr2s short s short s +void pmv2s short s short s +void pnt2s short s short s +void rdr2s short s short s +void rmv2s short s short s +void rpdr2s short s short s +void rpmv2s short s short s +void xfpt2s short s short s +# +void cmov2 float s float s +void draw2 float s float s +void move2 float s float s +void pnt2 float s float s +void pdr2 float s float s +void pmv2 float s float s +void rdr2 float s float s +void rmv2 float s float s +void rpdr2 float s float s +void rpmv2 float s float s +void xfpt2 float s float s +# +void loadmatrix float s[16] +void multmatrix float s[16] +void crv float s[16] +void rcrv float s[16] +# +# Methods that have strings. +# +void addtopup long s char *s long s +void charstr char *s +void getport char *s +long strwidth char *s +long winopen char *s +void wintitle char *s +# +# Methods that have 1 long (# of elements) and an array +# +void polf long s float s[3*arg1] +void polf2 long s float s[2*arg1] +void poly long s float s[3*arg1] +void poly2 long s float s[2*arg1] +void crvn long s float s[3*arg1] +void rcrvn long s float s[4*arg1] +# +void polf2i long s long s[2*arg1] +void polfi long s long s[3*arg1] +void poly2i long s long s[2*arg1] +void polyi long s long s[3*arg1] +# +void polf2s long s short s[2*arg1] +void polfs long s short s[3*arg1] +void polys long s short s[3*arg1] +void poly2s long s short s[2*arg1] +# +void defcursor short s short s[16] +void writepixels short s short s[arg1] +void defbasis long s float s[16] +void gewrite short s short s[arg1] +# +void rotate short s char s +# This is not in the library!? +###void setbutton short s char s +void rot float s char s +# +void circfi long s long s long s +void circi long s long s long s +void cmovi long s long s long s +void drawi long s long s long s +void movei long s long s long s +void pnti long s long s long s +void newtag long s long s long s +void pdri long s long s long s +void pmvi long s long s long s +void rdri long s long s long s +void rmvi long s long s long s +void rpdri long s long s long s +void rpmvi long s long s long s +void xfpti long s long s long s +# +void circ float s float s float s +void circf float s float s float s +void cmov float s float s float s +void draw float s float s float s +void move float s float s float s +void pnt float s float s float s +void scale float s float s float s +void translate float s float s float s +void pdr float s float s float s +void pmv float s float s float s +void rdr float s float s float s +void rmv float s float s float s +void rpdr float s float s float s +void rpmv float s float s float s +void xfpt float s float s float s +# +void RGBcolor short s short s short s +void RGBwritemask short s short s short s +void setcursor short s short s short s +void tie short s short s short s +void circfs short s short s short s +void circs short s short s short s +void cmovs short s short s short s +void draws short s short s short s +void moves short s short s short s +void pdrs short s short s short s +void pmvs short s short s short s +void pnts short s short s short s +void rdrs short s short s short s +void rmvs short s short s short s +void rpdrs short s short s short s +void rpmvs short s short s short s +void xfpts short s short s short s +void curorigin short s short s short s +void cyclemap short s short s short s +# +void patch float s[16] float s[16] float s[16] +void splf long s float s[3*arg1] short s[arg1] +void splf2 long s float s[2*arg1] short s[arg1] +void splfi long s long s[3*arg1] short s[arg1] +void splf2i long s long s[2*arg1] short s[arg1] +void splfs long s short s[3*arg1] short s[arg1] +void splf2s long s short s[2*arg1] short s[arg1] +void defpattern short s short s short s[arg2*arg2/16] +# +void rpatch float s[16] float s[16] float s[16] float s[16] +# +# routines that send 4 floats +# +void ortho2 float s float s float s float s +void rect float s float s float s float s +void rectf float s float s float s float s +void xfpt4 float s float s float s float s +# +void textport short s short s short s short s +void mapcolor short s short s short s short s +void scrmask short s short s short s short s +void setvaluator short s short s short s short s +void viewport short s short s short s short s +void shaderange short s short s short s short s +void xfpt4s short s short s short s short s +void rectfi long s long s long s long s +void recti long s long s long s long s +void xfpt4i long s long s long s long s +void prefposition long s long s long s long s +# +void arc float s float s float s short s short s +void arcf float s float s float s short s short s +void arcfi long s long s long s short s short s +void arci long s long s long s short s short s +# +void bbox2 short s short s float s float s float s float s +void bbox2i short s short s long s long s long s long s +void bbox2s short s short s short s short s short s short s +void blink short s short s short s short s short s +void ortho float s float s float s float s float s float s +void window float s float s float s float s float s float s +void lookat float s float s float s float s float s float s short s +# +void perspective short s float s float s float s +void polarview float s short s short s short s +# XXX getichararray not supported +#void writeRGB short s char s[arg1] char s[arg1] char s[arg1] +# +void arcfs short s short s short s short s short s +void arcs short s short s short s short s short s +void rectcopy short s short s short s short s short s short s +void RGBcursor short s short s short s short s short s short s short s +# +long getbutton short s +long getcmmode +long getlsbackup +long getresetls +long getdcm +long getzbuffer +long ismex +long isobj long s +long isqueued short s +long istag long s +# +long genobj +long gentag +long getbuffer +long getcolor +long getdisplaymode +long getfont +long getheight +long gethitcode +long getlstyle +long getlwidth +long getmap +long getplanes +long getwritemask +long qtest +long getlsrepeat +long getmonitor +long getopenobj +long getpattern +long winget +long winattach +long getothermonitor +long newpup +# +long getvaluator short s +void winset long s +long dopup long s +void getdepth short r short r +void getcpos short r short r +void getsize long r long r +void getorigin long r long r +void getviewport short r short r short r short r +void gettp short r short r short r short r +void getgpos float r float r float r float r +void winposition long s long s long s long s +void gRGBcolor short r short r short r +void gRGBmask short r short r short r +void getscrmask short r short r short r short r +void gRGBcursor short r short r short r short r short r short r short r short r long * +void getmcolor short s short r short r short r +void mapw long s short s short s float r float r float r float r float r float r +void mapw2 long s short s short s float r float r +void defrasterfont short s short s short s Fontchar s[arg3] short s short s[4*arg5] +long qread short r +void getcursor short r short r short r long r +# +# For these we receive arrays of stuff +# +void getdev long s short s[arg1] short r[arg1] +#XXX not generated correctly yet +#void getmatrix float r[16] +long readpixels short s short r[retval] +long readRGB short s char r[retval] char r[retval] char r[retval] +long blkqread short s short r[arg1] +# +# New 4D routines +# +void cmode +void concave long s +void curstype long s +void drawmode long s +void gammaramp short s[256] short s[256] short s[256] +long getbackface +long getdescender +long getdrawmode +long getmmode +long getsm +long getvideo long s +void imakebackground +void lmbind short s short s +void lmdef long s long s long s float s[arg3] +void mmode long s +void normal float s[3] +void overlay long s +void RGBrange short s short s short s short s short s short s short s short s +void setvideo long s long s +void shademodel long s +void underlay long s +# +# New Personal Iris/GT Routines +# +void bgnclosedline +void bgnline +void bgnpoint +void bgnpolygon +void bgnsurface +void bgntmesh +void bgntrim +void endclosedline +void endline +void endpoint +void endpolygon +void endsurface +void endtmesh +void endtrim +void blendfunction long s long s +void c3f float s[3] +void c3i long s[3] +void c3s short s[3] +void c4f float s[4] +void c4i long s[4] +void c4s short s[4] +void colorf float s +void cpack long s +void czclear long s long s +void dglclose long s +long dglopen char *s long s +long getgdesc long s +void getnurbsproperty long s float r +void glcompat long s long s +void iconsize long s long s +void icontitle char *s +void lRGBrange short s short s short s short s short s short s long s long s +void linesmooth long s +void lmcolor long s +void logicop long s +long lrectread short s short s short s short s long r[retval] +void lrectwrite short s short s short s short s long s[(arg2-arg1+1)*(arg4-arg3+1)] +long rectread short s short s short s short s short r[retval] +void rectwrite short s short s short s short s short s[(arg2-arg1+1)*(arg4-arg3+1)] +void lsetdepth long s long s +void lshaderange short s short s long s long s +void n3f float s[3] +void noborder +void pntsmooth long s +void readsource long s +void rectzoom float s float s +void sbox float s float s float s float s +void sboxi long s long s long s long s +void sboxs short s short s short s short s +void sboxf float s float s float s float s +void sboxfi long s long s long s long s +void sboxfs short s short s short s short s +void setnurbsproperty long s float s +void setpup long s long s long s +void smoothline long s +void subpixel long s +void swaptmesh +long swinopen long s +void v2f float s[2] +void v2i long s[2] +void v2s short s[2] +void v3f float s[3] +void v3i long s[3] +void v3s short s[3] +void v4f float s[4] +void v4i long s[4] +void v4s short s[4] +void videocmd long s +long windepth long s +void wmpack long s +void zdraw long s +void zfunction long s +void zsource long s +void zwritemask long s +# +# uses doubles +# +void v2d double s[2] +void v3d double s[3] +void v4d double s[4] diff --git a/src/dictobject.c b/src/dictobject.c new file mode 100644 index 0000000..3bbd1d5 --- /dev/null +++ b/src/dictobject.c @@ -0,0 +1,605 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Dictionary object implementation; using a hash table */ + +/* +XXX Note -- although this may look professional, I didn't think very hard +about the problem and it is possible that obvious improvements exist. +A similar module that I saw by Chris Torek: +- uses chaining instead of hashed linear probing +- remembers the hash value with the entry to speed up table resizing +- sets the table size to a power of 2 +- uses a different hash function: + h = 0; p = str; while (*p) h = (h<<5) - h + *p++; +*/ + +#include "allobjects.h" + + +/* +Table of primes suitable as keys, in ascending order. +The first line are the largest primes less than some powers of two, +the second line is the largest prime less than 6000, +and the third line is a selection from Knuth, Vol. 3, Sec. 6.1, Table 1. +The final value is a sentinel and should cause the memory allocation +of that many entries to fail (if none of the earlier values cause such +failure already). +*/ +static unsigned int primes[] = { + 3, 7, 13, 31, 61, 127, 251, 509, 1021, 2017, 4093, + 5987, + 9551, 15683, 19609, 31397, + 0xffffffff /* All bits set -- truncation OK */ +}; + +/* String used as dummy key to fill deleted entries */ +static stringobject *dummy; /* Initialized by first call to newdictobject() */ + +/* +Invariant for entries: when in use, de_value is not NULL and de_key is +not NULL and not dummy; when not in use, de_value is NULL and de_key +is either NULL or dummy. A dummy key value cannot be replaced by NULL, +since otherwise other keys may be lost. +*/ +typedef struct { + stringobject *de_key; + object *de_value; +} dictentry; + +/* +To ensure the lookup algorithm terminates, the table size must be a +prime number and there must be at least one NULL key in the table. +The value di_fill is the number of non-NULL keys; di_used is the number +of non-NULL, non-dummy keys. +To avoid slowing down lookups on a near-full table, we resize the table +when it is more than half filled. +*/ +typedef struct { + OB_HEAD + int di_fill; + int di_used; + int di_size; + dictentry *di_table; +} dictobject; + +object * +newdictobject() +{ + register dictobject *dp; + if (dummy == NULL) { /* Auto-initialize dummy */ + dummy = (stringobject *) newstringobject(""); + if (dummy == NULL) + return NULL; + } + dp = NEWOBJ(dictobject, &Dicttype); + if (dp == NULL) + return NULL; + dp->di_size = primes[0]; + dp->di_table = (dictentry *) calloc(sizeof(dictentry), dp->di_size); + if (dp->di_table == NULL) { + DEL(dp); + return err_nomem(); + } + dp->di_fill = 0; + dp->di_used = 0; + return (object *)dp; +} + +/* +The basic lookup function used by all operations. +This is essentially Algorithm D from Knuth Vol. 3, Sec. 6.4. +Open addressing is preferred over chaining since the link overhead for +chaining would be substantial (100% with typical malloc overhead). + +First a 32-bit hash value, 'sum', is computed from the key string. +The first character is added an extra time shifted by 8 to avoid hashing +single-character keys (often heavily used variables) too close together. +All arithmetic on sum should ignore overflow. + +The initial probe index is then computed as sum mod the table size. +Subsequent probe indices are incr apart (mod table size), where incr +is also derived from sum, with the additional requirement that it is +relative prime to the table size (i.e., 1 <= incr < size, since the size +is a prime number). My choice for incr is somewhat arbitrary. +*/ +static dictentry *lookdict PROTO((dictobject *, char *)); +static dictentry * +lookdict(dp, key) + register dictobject *dp; + char *key; +{ + register int i, incr; + register dictentry *freeslot = NULL; + register unsigned char *p = (unsigned char *) key; + register unsigned long sum = *p << 7; + while (*p != '\0') + sum = sum + sum + *p++; + i = sum % dp->di_size; + do { + sum = sum + sum + 1; + incr = sum % dp->di_size; + } while (incr == 0); + for (;;) { + register dictentry *ep = &dp->di_table[i]; + if (ep->de_key == NULL) { + if (freeslot != NULL) + return freeslot; + else + return ep; + } + if (ep->de_key == dummy) { + if (freeslot != NULL) + freeslot = ep; + } + else if (GETSTRINGVALUE(ep->de_key)[0] == key[0]) { + if (strcmp(GETSTRINGVALUE(ep->de_key), key) == 0) { + return ep; + } + } + i = (i + incr) % dp->di_size; + } +} + +/* +Internal routine to insert a new item into the table. +Used both by the internal resize routine and by the public insert routine. +Eats a reference to key and one to value. +*/ +static void insertdict PROTO((dictobject *, stringobject *, object *)); +static void +insertdict(dp, key, value) + register dictobject *dp; + stringobject *key; + object *value; +{ + register dictentry *ep; + ep = lookdict(dp, GETSTRINGVALUE(key)); + if (ep->de_value != NULL) { + DECREF(ep->de_value); + DECREF(key); + } + else { + if (ep->de_key == NULL) + dp->di_fill++; + else + DECREF(ep->de_key); + ep->de_key = key; + dp->di_used++; + } + ep->de_value = value; +} + +/* +Restructure the table by allocating a new table and reinserting all +items again. When entries have been deleted, the new table may +actually be smaller than the old one. +*/ +static int dictresize PROTO((dictobject *)); +static int +dictresize(dp) + dictobject *dp; +{ + register int oldsize = dp->di_size; + register int newsize; + register dictentry *oldtable = dp->di_table; + register dictentry *newtable; + register dictentry *ep; + register int i; + newsize = dp->di_size; + for (i = 0; ; i++) { + if (primes[i] > dp->di_used*2) { + newsize = primes[i]; + break; + } + } + newtable = (dictentry *) calloc(sizeof(dictentry), newsize); + if (newtable == NULL) { + err_nomem(); + return -1; + } + dp->di_size = newsize; + dp->di_table = newtable; + dp->di_fill = 0; + dp->di_used = 0; + for (i = 0, ep = oldtable; i < oldsize; i++, ep++) { + if (ep->de_value != NULL) + insertdict(dp, ep->de_key, ep->de_value); + else if (ep->de_key != NULL) + DECREF(ep->de_key); + } + DEL(oldtable); + return 0; +} + +object * +dictlookup(op, key) + object *op; + char *key; +{ + if (!is_dictobject(op)) + fatal("dictlookup on non-dictionary"); + return lookdict((dictobject *)op, key) -> de_value; +} + +#ifdef NOT_USED +static object * +dict2lookup(op, key) + register object *op; + register object *key; +{ + register object *res; + if (!is_dictobject(op)) { + err_badcall(); + return NULL; + } + if (!is_stringobject(key)) { + err_badarg(); + return NULL; + } + res = lookdict((dictobject *)op, ((stringobject *)key)->ob_sval) + -> de_value; + if (res == NULL) + err_setstr(KeyError, "key not in dictionary"); + return res; +} +#endif + +static int +dict2insert(op, key, value) + register object *op; + object *key; + object *value; +{ + register dictobject *dp; + register stringobject *keyobj; + if (!is_dictobject(op)) { + err_badcall(); + return -1; + } + dp = (dictobject *)op; + if (!is_stringobject(key)) { + err_badarg(); + return -1; + } + keyobj = (stringobject *)key; + /* if fill >= 2/3 size, resize */ + if (dp->di_fill*3 >= dp->di_size*2) { + if (dictresize(dp) != 0) { + if (dp->di_fill+1 > dp->di_size) + return -1; + } + } + INCREF(keyobj); + INCREF(value); + insertdict(dp, keyobj, value); + return 0; +} + +int +dictinsert(op, key, value) + object *op; + char *key; + object *value; +{ + register object *keyobj; + register int err; + keyobj = newstringobject(key); + if (keyobj == NULL) { + err_nomem(); + return -1; + } + err = dict2insert(op, keyobj, value); + DECREF(keyobj); + return err; +} + +int +dictremove(op, key) + object *op; + char *key; +{ + register dictobject *dp; + register dictentry *ep; + if (!is_dictobject(op)) { + err_badcall(); + return -1; + } + dp = (dictobject *)op; + ep = lookdict(dp, key); + if (ep->de_value == NULL) { + err_setstr(KeyError, "key not in dictionary"); + return -1; + } + DECREF(ep->de_key); + INCREF(dummy); + ep->de_key = dummy; + DECREF(ep->de_value); + ep->de_value = NULL; + dp->di_used--; + return 0; +} + +static int +dict2remove(op, key) + object *op; + register object *key; +{ + if (!is_stringobject(key)) { + err_badarg(); + return -1; + } + return dictremove(op, GETSTRINGVALUE((stringobject *)key)); +} + +int +getdictsize(op) + register object *op; +{ + if (!is_dictobject(op)) { + err_badcall(); + return -1; + } + return ((dictobject *)op) -> di_size; +} + +static object * +getdict2key(op, i) + object *op; + register int i; +{ + /* XXX This can't return errors since its callers assume + that NULL means there was no key at that point */ + register dictobject *dp; + if (!is_dictobject(op)) { + /* err_badcall(); */ + return NULL; + } + dp = (dictobject *)op; + if (i < 0 || i >= dp->di_size) { + /* err_badarg(); */ + return NULL; + } + if (dp->di_table[i].de_value == NULL) { + /* Not an error! */ + return NULL; + } + return (object *) dp->di_table[i].de_key; +} + +char * +getdictkey(op, i) + object *op; + int i; +{ + register object *keyobj = getdict2key(op, i); + if (keyobj == NULL) + return NULL; + return GETSTRINGVALUE((stringobject *)keyobj); +} + +/* Methods */ + +static void +dict_dealloc(dp) + register dictobject *dp; +{ + register int i; + register dictentry *ep; + for (i = 0, ep = dp->di_table; i < dp->di_size; i++, ep++) { + if (ep->de_key != NULL) + DECREF(ep->de_key); + if (ep->de_value != NULL) + DECREF(ep->de_value); + } + if (dp->di_table != NULL) + DEL(dp->di_table); + DEL(dp); +} + +static void +dict_print(dp, fp, flags) + register dictobject *dp; + register FILE *fp; + register int flags; +{ + register int i; + register int any; + register dictentry *ep; + fprintf(fp, "{"); + any = 0; + for (i = 0, ep = dp->di_table; i < dp->di_size && !StopPrint; + i++, ep++) { + if (ep->de_value != NULL) { + if (any++ > 0) + fprintf(fp, "; "); + printobject((object *)ep->de_key, fp, flags); + fprintf(fp, ": "); + printobject(ep->de_value, fp, flags); + } + } + fprintf(fp, "}"); +} + +static void +js(pv, w) + object **pv; + object *w; +{ + joinstring(pv, w); + if (w != NULL) + DECREF(w); +} + +static object * +dict_repr(dp) + dictobject *dp; +{ + auto object *v; + register object *w; + object *semi, *colon; + register int i; + register int any; + register dictentry *ep; + v = newstringobject("{"); + semi = newstringobject("; "); + colon = newstringobject(": "); + any = 0; + for (i = 0, ep = dp->di_table; i < dp->di_size && !StopPrint; + i++, ep++) { + if (ep->de_value != NULL) { + if (any++) + joinstring(&v, semi); + js(&v, w = reprobject((object *)ep->de_key)); + joinstring(&v, colon); + js(&v, w = reprobject(ep->de_value)); + } + } + js(&v, w = newstringobject("}")); + if (semi != NULL) + DECREF(semi); + if (colon != NULL) + DECREF(colon); + return v; +} + +static int +dict_length(dp) + dictobject *dp; +{ + return dp->di_used; +} + +static object * +dict_subscript(dp, v) + dictobject *dp; + register object *v; +{ + if (!is_stringobject(v)) { + err_badarg(); + return NULL; + } + v = lookdict(dp, GETSTRINGVALUE((stringobject *)v)) -> de_value; + if (v == NULL) + err_setstr(KeyError, "key not in dictionary"); + else + INCREF(v); + return v; +} + +static int +dict_ass_sub(dp, v, w) + dictobject *dp; + object *v, *w; +{ + if (w == NULL) + return dict2remove((object *)dp, v); + else + return dict2insert((object *)dp, v, w); +} + +static mapping_methods dict_as_mapping = { + dict_length, /*mp_length*/ + dict_subscript, /*mp_subscript*/ + dict_ass_sub, /*mp_ass_subscript*/ +}; + +static object * +dict_keys(dp, args) + register dictobject *dp; + object *args; +{ + register object *v; + register int i, j; + if (!getnoarg(args)) + return NULL; + v = newlistobject(dp->di_used); + if (v == NULL) + return NULL; + for (i = 0, j = 0; i < dp->di_size; i++) { + if (dp->di_table[i].de_value != NULL) { + stringobject *key = dp->di_table[i].de_key; + INCREF(key); + setlistitem(v, j, (object *)key); + j++; + } + } + return v; +} + +object * +getdictkeys(dp) + object *dp; +{ + if (dp == NULL || !is_dictobject(dp)) { + err_badcall(); + return NULL; + } + return dict_keys((dictobject *)dp, (object *)NULL); +} + +static object * +dict_has_key(dp, args) + register dictobject *dp; + object *args; +{ + object *key; + register long ok; + if (!getstrarg(args, &key)) + return NULL; + ok = lookdict(dp, GETSTRINGVALUE((stringobject *)key))->de_value + != NULL; + return newintobject(ok); +} + +static struct methodlist dict_methods[] = { + {"keys", dict_keys}, + {"has_key", dict_has_key}, + {NULL, NULL} /* sentinel */ +}; + +static object * +dict_getattr(dp, name) + dictobject *dp; + char *name; +{ + return findmethod(dict_methods, (object *)dp, name); +} + +typeobject Dicttype = { + OB_HEAD_INIT(&Typetype) + 0, + "dictionary", + sizeof(dictobject), + 0, + dict_dealloc, /*tp_dealloc*/ + dict_print, /*tp_print*/ + dict_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + dict_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + &dict_as_mapping, /*tp_as_mapping*/ +}; diff --git a/src/dictobject.h b/src/dictobject.h new file mode 100644 index 0000000..d665aa5 --- /dev/null +++ b/src/dictobject.h @@ -0,0 +1,44 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* +Dictionary object type -- mapping from char * to object. +NB: the key is given as a char *, not as a stringobject. +These functions set errno for errors. Functions dictremove() and +dictinsert() return nonzero for errors, getdictsize() returns -1, +the others NULL. A successful call to dictinsert() calls INCREF() +for the inserted item. +*/ + +extern typeobject Dicttype; + +#define is_dictobject(op) ((op)->ob_type == &Dicttype) + +extern object *newdictobject PROTO((void)); +extern object *dictlookup PROTO((object *dp, char *key)); +extern int dictinsert PROTO((object *dp, char *key, object *item)); +extern int dictremove PROTO((object *dp, char *key)); +extern int getdictsize PROTO((object *dp)); +extern char *getdictkey PROTO((object *dp, int i)); +extern object *getdictkeys PROTO((object *dp)); diff --git a/src/errcode.h b/src/errcode.h new file mode 100644 index 0000000..3324489 --- /dev/null +++ b/src/errcode.h @@ -0,0 +1,36 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Error codes passed around between file input, tokenizer, parser and + interpreter. This was necessary so we can turn them into Python + exceptions at a higher level. */ + +#define E_OK 10 /* No error */ +#define E_EOF 11 /* (Unexpected) EOF read */ +#define E_INTR 12 /* Interrupted */ +#define E_TOKEN 13 /* Bad token */ +#define E_SYNTAX 14 /* Syntax error */ +#define E_NOMEM 15 /* Ran out of memory */ +#define E_DONE 16 /* Parsing complete */ +#define E_ERROR 17 /* Execution error */ diff --git a/src/errors.c b/src/errors.c new file mode 100644 index 0000000..b3e6aa3 --- /dev/null +++ b/src/errors.c @@ -0,0 +1,196 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Error handling -- see also run.c */ + +/* New error handling interface. + + The following problem exists (existed): methods of built-in modules + are called with 'self' and 'args' arguments, but without a context + argument, so they have no way to raise a specific exception. + The same is true for the object implementations: no context argument. + The old convention was to set 'errno' and to return NULL. + The caller (usually call_function() in eval.c) detects the NULL + return value and then calls puterrno(ctx) to turn the errno value + into a true exception. Problems with this approach are: + - it used standard errno values to indicate Python-specific errors, + but this means that when such an error code is reported by a system + call (e.g., in module posix), the user gets a confusing message + - errno is a global variable, which makes extensions to a multi- + threading environment difficult; e.g., in IRIX, multi-threaded + programs must use the function oserror() instead of looking in errno + - there is no portable way to add new error numbers for specic + situations -- the value space for errno is reserved to the OS, yet + the way to turn module-specific errors into a module-specific + exception requires module-specific values for errno + - there is no way to add a more situation-specific message to an + error. + + The new interface solves all these problems. To return an error, a + built-in function calls err_set(exception), err_setval(exception, + value) or err_setstr(exception, string), and returns NULL. These + functions save the value for later use by puterrno(). To adapt this + scheme to a multi-threaded environment, only the implementation of + err_setval() has to be changed. +*/ + +#include "allobjects.h" + +#include <errno.h> +#ifndef errno +extern int errno; +#endif + +#include "errcode.h" + +extern char *strerror PROTO((int)); + +/* Last exception stored by err_setval() */ + +static object *last_exception; +static object *last_exc_val; + +void +err_setval(exception, value) + object *exception; + object *value; +{ + XDECREF(last_exception); + XINCREF(exception); + last_exception = exception; + + XDECREF(last_exc_val); + XINCREF(value); + last_exc_val = value; +} + +void +err_set(exception) + object *exception; +{ + err_setval(exception, (object *)NULL); +} + +void +err_setstr(exception, string) + object *exception; + char *string; +{ + object *value = newstringobject(string); + err_setval(exception, value); + XDECREF(value); +} + +int +err_occurred() +{ + return last_exception != NULL; +} + +void +err_get(p_exc, p_val) + object **p_exc; + object **p_val; +{ + *p_exc = last_exception; + last_exception = NULL; + *p_val = last_exc_val; + last_exc_val = NULL; +} + +void +err_clear() +{ + XDECREF(last_exception); + last_exception = NULL; + XDECREF(last_exc_val); + last_exc_val = NULL; +} + +/* Convenience functions to set a type error exception and return 0 */ + +int +err_badarg() +{ + err_setstr(TypeError, "illegal argument type for built-in operation"); + return 0; +} + +object * +err_nomem() +{ + err_set(MemoryError); + return NULL; +} + +object * +err_errno(exc) + object *exc; +{ + object *v = newtupleobject(2); + if (v != NULL) { + settupleitem(v, 0, newintobject((long)errno)); + settupleitem(v, 1, newstringobject(strerror(errno))); + } + err_setval(exc, v); + XDECREF(v); + return NULL; +} + +void +err_badcall() +{ + err_setstr(SystemError, "bad argument to internal function"); +} + +/* Set the error appropriate to the given input error code (see errcode.h) */ + +void +err_input(err) + int err; +{ + switch (err) { + case E_DONE: + case E_OK: + break; + case E_SYNTAX: + err_setstr(RuntimeError, "syntax error"); + break; + case E_TOKEN: + err_setstr(RuntimeError, "illegal token"); + break; + case E_INTR: + err_set(KeyboardInterrupt); + break; + case E_NOMEM: + err_nomem(); + break; + case E_EOF: + err_set(EOFError); + break; + default: + err_setstr(RuntimeError, "unknown input error"); + break; + } +} diff --git a/src/errors.h b/src/errors.h new file mode 100644 index 0000000..4baa142 --- /dev/null +++ b/src/errors.h @@ -0,0 +1,58 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Error handling definitions */ + +void err_set PROTO((object *)); +void err_setval PROTO((object *, object *)); +void err_setstr PROTO((object *, char *)); +int err_occurred PROTO((void)); +void err_get PROTO((object **, object **)); +void err_clear PROTO((void)); + +/* Predefined exceptions */ + +extern object *RuntimeError; +extern object *EOFError; +extern object *TypeError; +extern object *MemoryError; +extern object *NameError; +extern object *SystemError; +extern object *KeyboardInterrupt; + +/* Some more planned for the future */ + +#define IndexError RuntimeError +#define KeyError RuntimeError +#define ZeroDivisionError RuntimeError +#define OverflowError RuntimeError + +/* Convenience functions */ + +extern int err_badarg PROTO((void)); +extern object *err_nomem PROTO((void)); +extern object *err_errno PROTO((object *)); +extern void err_input PROTO((int)); + +extern void err_badcall PROTO((void)); diff --git a/src/fgetsintr.c b/src/fgetsintr.c new file mode 100644 index 0000000..bda1ed8 --- /dev/null +++ b/src/fgetsintr.c @@ -0,0 +1,94 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Interruptable version of fgets(). + Return < 0 for interrupted, 1 for EOF, 0 for valid input. */ + +/* XXX This uses longjmp() from a signal out of fgets(). + Should use read() instead?! */ + +#include "pgenheaders.h" + +#include <signal.h> +#include <setjmp.h> + +#include "errcode.h" +#include "sigtype.h" +#include "fgetsintr.h" + +#ifndef AMOEBA +#define sig_block() /*empty*/ +#define sig_unblock() /*empty*/ +#endif + +static jmp_buf jback; + +static void catcher PROTO((int)); + +static void +catcher(sig) + int sig; +{ + longjmp(jback, 1); +} + +int +fgets_intr(buf, size, fp) + char *buf; + int size; + FILE *fp; +{ + int ret; + SIGTYPE (*sigsave)(); + + if (setjmp(jback)) { + clearerr(fp); + signal(SIGINT, sigsave); +#ifdef THINK_C_3_0 + Set_Echo(1); +#endif + return E_INTR; + } + + /* The casts to (SIGTYPE(*)()) are needed by THINK_C only */ + + sigsave = signal(SIGINT, (SIGTYPE(*)()) SIG_IGN); + if (sigsave != (SIGTYPE(*)()) SIG_IGN) + signal(SIGINT, (SIGTYPE(*)()) catcher); + +#ifndef THINK_C + if (intrcheck()) + ret = E_INTR; + else +#endif + { + sig_block(); + ret = (fgets(buf, size, fp) == NULL) ? E_EOF : E_OK; + sig_unblock(); + } + + if (sigsave != (SIGTYPE(*)()) SIG_IGN) + signal(SIGINT, (SIGTYPE(*)()) sigsave); + return ret; +} diff --git a/src/fgetsintr.h b/src/fgetsintr.h new file mode 100644 index 0000000..87f1d2a --- /dev/null +++ b/src/fgetsintr.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. + +******************************************************************/ + +extern int fgets_intr PROTO((char *, int, FILE *)); diff --git a/src/fileobject.c b/src/fileobject.c new file mode 100644 index 0000000..640e27b --- /dev/null +++ b/src/fileobject.c @@ -0,0 +1,293 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* File object implementation */ + +/* XXX This should become a built-in module 'io'. It should support more + functionality, better exception handling for invalid calls, etc. + (Especially reading on a write-only file or vice versa!) + It should also cooperate with posix to support popen(), which should + share most code but have a special close function. */ + +#include "allobjects.h" + +#include "errno.h" +#ifndef errno +extern int errno; +#endif + +typedef struct { + OB_HEAD + FILE *f_fp; + object *f_name; + object *f_mode; + /* XXX Should move the 'need space' on printing flag here */ +} fileobject; + +FILE * +getfilefile(f) + object *f; +{ + if (!is_fileobject(f)) { + err_badcall(); + return NULL; + } + return ((fileobject *)f)->f_fp; +} + +object * +newopenfileobject(fp, name, mode) + FILE *fp; + char *name; + char *mode; +{ + fileobject *f = NEWOBJ(fileobject, &Filetype); + if (f == NULL) + return NULL; + f->f_fp = NULL; + f->f_name = newstringobject(name); + f->f_mode = newstringobject(mode); + if (f->f_name == NULL || f->f_mode == NULL) { + DECREF(f); + return NULL; + } + f->f_fp = fp; + return (object *) f; +} + +object * +newfileobject(name, mode) + char *name, *mode; +{ + fileobject *f; + FILE *fp; + f = (fileobject *) newopenfileobject((FILE *)NULL, name, mode); + if (f == NULL) + return NULL; +#ifdef THINK_C + if (*mode == '*') { + FILE *fopenRF(); + f->f_fp = fopenRF(name, mode+1); + } + else +#endif + f->f_fp = fopen(name, mode); + if (f->f_fp == NULL) { + err_errno(RuntimeError); + DECREF(f); + return NULL; + } + return (object *)f; +} + +/* Methods */ + +static void +file_dealloc(f) + fileobject *f; +{ + if (f->f_fp != NULL) + fclose(f->f_fp); + if (f->f_name != NULL) + DECREF(f->f_name); + if (f->f_mode != NULL) + DECREF(f->f_mode); + free((char *)f); +} + +static void +file_print(f, fp, flags) + fileobject *f; + FILE *fp; + int flags; +{ + fprintf(fp, "<%s file ", f->f_fp == NULL ? "closed" : "open"); + printobject(f->f_name, fp, flags); + fprintf(fp, ", mode "); + printobject(f->f_mode, fp, flags); + fprintf(fp, ">"); +} + +static object * +file_repr(f) + fileobject *f; +{ + char buf[300]; + /* XXX This differs from file_print if the filename contains + quotes or other funny characters. */ + sprintf(buf, "<%s file '%.256s', mode '%.10s'>", + f->f_fp == NULL ? "closed" : "open", + getstringvalue(f->f_name), + getstringvalue(f->f_mode)); + return newstringobject(buf); +} + +static object * +file_close(f, args) + fileobject *f; + object *args; +{ + if (args != NULL) { + err_badarg(); + return NULL; + } + if (f->f_fp != NULL) { + fclose(f->f_fp); + f->f_fp = NULL; + } + INCREF(None); + return None; +} + +static object * +file_read(f, args) + fileobject *f; + object *args; +{ + int n; + object *v; + if (f->f_fp == NULL) { + err_badarg(); + return NULL; + } + if (args == NULL || !is_intobject(args)) { + err_badarg(); + return NULL; + } + n = getintvalue(args); + if (n < 0) { + err_badarg(); + return NULL; + } + v = newsizedstringobject((char *)NULL, n); + if (v == NULL) + return NULL; + n = fread(getstringvalue(v), 1, n, f->f_fp); + /* EOF is reported as an empty string */ + /* XXX should detect real I/O errors? */ + resizestring(&v, n); + return v; +} + +/* XXX Should this be unified with raw_input()? */ + +static object * +file_readline(f, args) + fileobject *f; + object *args; +{ + int n; + object *v; + if (f->f_fp == NULL) { + err_badarg(); + return NULL; + } + if (args == NULL) { + n = 10000; /* XXX should really be unlimited */ + } + else if (is_intobject(args)) { + n = getintvalue(args); + if (n < 0) { + err_badarg(); + return NULL; + } + } + else { + err_badarg(); + return NULL; + } + v = newsizedstringobject((char *)NULL, n); + if (v == NULL) + return NULL; +#ifndef THINK_C_3_0 + /* XXX Think C 3.0 wrongly reads up to n characters... */ + n = n+1; +#endif + if (fgets(getstringvalue(v), n, f->f_fp) == NULL) { + /* EOF is reported as an empty string */ + /* XXX should detect real I/O errors? */ + n = 0; + } + else { + n = strlen(getstringvalue(v)); + } + resizestring(&v, n); + return v; +} + +static object * +file_write(f, args) + fileobject *f; + object *args; +{ + int n, n2; + if (f->f_fp == NULL) { + err_badarg(); + return NULL; + } + if (args == NULL || !is_stringobject(args)) { + err_badarg(); + return NULL; + } + errno = 0; + n2 = fwrite(getstringvalue(args), 1, n = getstringsize(args), f->f_fp); + if (n2 != n) { + if (errno == 0) + errno = EIO; + err_errno(RuntimeError); + return NULL; + } + INCREF(None); + return None; +} + +static struct methodlist file_methods[] = { + {"write", file_write}, + {"read", file_read}, + {"readline", file_readline}, + {"close", file_close}, + {NULL, NULL} /* sentinel */ +}; + +static object * +file_getattr(f, name) + fileobject *f; + char *name; +{ + return findmethod(file_methods, (object *)f, name); +} + +typeobject Filetype = { + OB_HEAD_INIT(&Typetype) + 0, + "file", + sizeof(fileobject), + 0, + file_dealloc, /*tp_dealloc*/ + file_print, /*tp_print*/ + file_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + file_repr, /*tp_repr*/ +}; diff --git a/src/fileobject.h b/src/fileobject.h new file mode 100644 index 0000000..eefae74 --- /dev/null +++ b/src/fileobject.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. + +******************************************************************/ + +/* File object interface */ + +extern typeobject Filetype; + +#define is_fileobject(op) ((op)->ob_type == &Filetype) + +extern object *newfileobject PROTO((char *, char *)); +extern object *newopenfileobject PROTO((FILE *, char *, char *)); +extern FILE *getfilefile PROTO((object *)); diff --git a/src/firstsets.c b/src/firstsets.c new file mode 100644 index 0000000..6bd7ce0 --- /dev/null +++ b/src/firstsets.c @@ -0,0 +1,133 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Computation of FIRST stets */ + +#include "pgenheaders.h" +#include "grammar.h" +#include "token.h" + +extern int debugging; + +/* Forward */ +static void calcfirstset PROTO((grammar *, dfa *)); + +void +addfirstsets(g) + grammar *g; +{ + int i; + dfa *d; + + printf("Adding FIRST sets ...\n"); + for (i = 0; i < g->g_ndfas; i++) { + d = &g->g_dfa[i]; + if (d->d_first == NULL) + calcfirstset(g, d); + } +} + +static void +calcfirstset(g, d) + grammar *g; + dfa *d; +{ + int i, j; + state *s; + arc *a; + int nsyms; + int *sym; + int nbits; + static bitset dummy; + bitset result; + int type; + dfa *d1; + label *l0; + + if (debugging) + printf("Calculate FIRST set for '%s'\n", d->d_name); + + if (dummy == NULL) + dummy = newbitset(1); + if (d->d_first == dummy) { + fprintf(stderr, "Left-recursion for '%s'\n", d->d_name); + return; + } + if (d->d_first != NULL) { + fprintf(stderr, "Re-calculating FIRST set for '%s' ???\n", + d->d_name); + } + d->d_first = dummy; + + l0 = g->g_ll.ll_label; + nbits = g->g_ll.ll_nlabels; + result = newbitset(nbits); + + sym = NEW(int, 1); + if (sym == NULL) + fatal("no mem for new sym in calcfirstset"); + nsyms = 1; + sym[0] = findlabel(&g->g_ll, d->d_type, (char *)NULL); + + s = &d->d_state[d->d_initial]; + for (i = 0; i < s->s_narcs; i++) { + a = &s->s_arc[i]; + for (j = 0; j < nsyms; j++) { + if (sym[j] == a->a_lbl) + break; + } + if (j >= nsyms) { /* New label */ + RESIZE(sym, int, nsyms + 1); + if (sym == NULL) + fatal("no mem to resize sym in calcfirstset"); + sym[nsyms++] = a->a_lbl; + type = l0[a->a_lbl].lb_type; + if (ISNONTERMINAL(type)) { + d1 = finddfa(g, type); + if (d1->d_first == dummy) { + fprintf(stderr, + "Left-recursion below '%s'\n", + d->d_name); + } + else { + if (d1->d_first == NULL) + calcfirstset(g, d1); + mergebitset(result, d1->d_first, nbits); + } + } + else if (ISTERMINAL(type)) { + addbit(result, a->a_lbl); + } + } + } + d->d_first = result; + if (debugging) { + printf("FIRST set for '%s': {", d->d_name); + for (i = 0; i < nbits; i++) { + if (testbit(result, i)) + printf(" %s", labelrepr(&l0[i])); + } + printf(" }\n"); + } +} diff --git a/src/floatobject.c b/src/floatobject.c new file mode 100644 index 0000000..c637989 --- /dev/null +++ b/src/floatobject.c @@ -0,0 +1,271 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Float object implementation */ + +/* XXX There should be overflow checks here, but it's hard to check + for any kind of float exception without losing portability. */ + +#include "allobjects.h" + +#include <errno.h> +#ifndef errno +extern int errno; +#endif + +#include <ctype.h> +#include <math.h> + +#ifndef THINK_C +extern double fmod PROTO((double, double)); +extern double pow PROTO((double, double)); +#endif + +object * +newfloatobject(fval) + double fval; +{ + /* For efficiency, this code is copied from newobject() */ + register floatobject *op = (floatobject *) malloc(sizeof(floatobject)); + if (op == NULL) + return err_nomem(); + NEWREF(op); + op->ob_type = &Floattype; + op->ob_fval = fval; + return (object *) op; +} + +double +getfloatvalue(op) + object *op; +{ + if (!is_floatobject(op)) { + err_badarg(); + return -1; + } + else + return ((floatobject *)op) -> ob_fval; +} + +/* Methods */ + +static void +float_buf_repr(buf, v) + char *buf; + floatobject *v; +{ + register char *cp; + /* Subroutine for float_repr and float_print. + We want float numbers to be recognizable as such, + i.e., they should contain a decimal point or an exponent. + However, %g may print the number as an integer; + in such cases, we append ".0" to the string. */ + sprintf(buf, "%.12g", v->ob_fval); + cp = buf; + if (*cp == '-') + cp++; + for (; *cp != '\0'; cp++) { + /* Any non-digit means it's not an integer; + this takes care of NAN and INF as well. */ + if (!isdigit(*cp)) + break; + } + if (*cp == '\0') { + *cp++ = '.'; + *cp++ = '0'; + *cp++ = '\0'; + } +} + +static void +float_print(v, fp, flags) + floatobject *v; + FILE *fp; + int flags; +{ + char buf[100]; + float_buf_repr(buf, v); + fputs(buf, fp); +} + +static object * +float_repr(v) + floatobject *v; +{ + char buf[100]; + float_buf_repr(buf, v); + return newstringobject(buf); +} + +static int +float_compare(v, w) + floatobject *v, *w; +{ + double i = v->ob_fval; + double j = w->ob_fval; + return (i < j) ? -1 : (i > j) ? 1 : 0; +} + +static object * +float_add(v, w) + floatobject *v; + object *w; +{ + if (!is_floatobject(w)) { + err_badarg(); + return NULL; + } + return newfloatobject(v->ob_fval + ((floatobject *)w) -> ob_fval); +} + +static object * +float_sub(v, w) + floatobject *v; + object *w; +{ + if (!is_floatobject(w)) { + err_badarg(); + return NULL; + } + return newfloatobject(v->ob_fval - ((floatobject *)w) -> ob_fval); +} + +static object * +float_mul(v, w) + floatobject *v; + object *w; +{ + if (!is_floatobject(w)) { + err_badarg(); + return NULL; + } + return newfloatobject(v->ob_fval * ((floatobject *)w) -> ob_fval); +} + +static object * +float_div(v, w) + floatobject *v; + object *w; +{ + if (!is_floatobject(w)) { + err_badarg(); + return NULL; + } + if (((floatobject *)w) -> ob_fval == 0) { + err_setstr(ZeroDivisionError, "float division by zero"); + return NULL; + } + return newfloatobject(v->ob_fval / ((floatobject *)w) -> ob_fval); +} + +static object * +float_rem(v, w) + floatobject *v; + object *w; +{ + double wx; + if (!is_floatobject(w)) { + err_badarg(); + return NULL; + } + wx = ((floatobject *)w) -> ob_fval; + if (wx == 0.0) { + err_setstr(ZeroDivisionError, "float division by zero"); + return NULL; + } + return newfloatobject(fmod(v->ob_fval, wx)); +} + +static object * +float_pow(v, w) + floatobject *v; + object *w; +{ + double iv, iw, ix; + if (!is_floatobject(w)) { + err_badarg(); + return NULL; + } + iv = v->ob_fval; + iw = ((floatobject *)w)->ob_fval; + if (iw == 0.0) + return newfloatobject(1.0); /* x**0 is always 1, even 0**0 */ + errno = 0; + ix = pow(iv, iw); + if (errno != 0) { + /* XXX could it be another type of error? */ + err_errno(OverflowError); + return NULL; + } + return newfloatobject(ix); +} + +static object * +float_neg(v) + floatobject *v; +{ + return newfloatobject(-v->ob_fval); +} + +static object * +float_pos(v) + floatobject *v; +{ + return newfloatobject(v->ob_fval); +} + +static number_methods float_as_number = { + float_add, /*tp_add*/ + float_sub, /*tp_subtract*/ + float_mul, /*tp_multiply*/ + float_div, /*tp_divide*/ + float_rem, /*tp_remainder*/ + float_pow, /*tp_power*/ + float_neg, /*tp_negate*/ + float_pos, /*tp_plus*/ +}; + +typeobject Floattype = { + OB_HEAD_INIT(&Typetype) + 0, + "float", + sizeof(floatobject), + 0, + free, /*tp_dealloc*/ + float_print, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + float_compare, /*tp_compare*/ + float_repr, /*tp_repr*/ + &float_as_number, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; + +/* +XXX This is not enough. Need: +- automatic casts for mixed arithmetic (3.1 * 4) +- mixed comparisons (!) +- look at other uses of ints that could be extended to floats +*/ diff --git a/src/floatobject.h b/src/floatobject.h new file mode 100644 index 0000000..52db73e --- /dev/null +++ b/src/floatobject.h @@ -0,0 +1,44 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Float object interface */ + +/* +floatobject represents a (double precision) floating point number. +*/ + +typedef struct { + OB_HEAD + double ob_fval; +} floatobject; + +extern typeobject Floattype; + +#define is_floatobject(op) ((op)->ob_type == &Floattype) + +extern object *newfloatobject PROTO((double)); +extern double getfloatvalue PROTO((object *)); + +/* Macro, trading safety for speed */ +#define GETFLOATVALUE(op) ((op)->ob_fval) diff --git a/src/fmod.c b/src/fmod.c new file mode 100644 index 0000000..fe90e07 --- /dev/null +++ b/src/fmod.c @@ -0,0 +1,51 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Portable fmod(x, y) implementation for systems that don't have it */ + +#include <math.h> +#include <errno.h> + +extern int errno; + +double +fmod(x, y) + double x, y; +{ + double i, f; + + if (y == 0.0) { + errno = EDOM; + return 0.0; + } + + /* return f such that x = i*y + f for some integer i + such that |f| < |y| and f has the same sign as x */ + + i = floor(x/y); + f = x - i*y; + if ((x < 0.0) != (y < 0.0)) + f = f-y; + return f; +} diff --git a/src/frameobject.c b/src/frameobject.c new file mode 100644 index 0000000..4f9e250 --- /dev/null +++ b/src/frameobject.c @@ -0,0 +1,156 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Frame object implementation */ + +#include "allobjects.h" + +#include "compile.h" +#include "frameobject.h" +#include "opcode.h" +#include "structmember.h" + +#define OFF(x) offsetof(frameobject, x) + +static struct memberlist frame_memberlist[] = { + {"f_back", T_OBJECT, OFF(f_back)}, + {"f_code", T_OBJECT, OFF(f_code)}, + {"f_globals", T_OBJECT, OFF(f_globals)}, + {"f_locals", T_OBJECT, OFF(f_locals)}, + {NULL} /* Sentinel */ +}; + +static object * +frame_getattr(f, name) + frameobject *f; + char *name; +{ + return getmember((char *)f, frame_memberlist, name); +} + +static void +frame_dealloc(f) + frameobject *f; +{ + XDECREF(f->f_back); + XDECREF(f->f_code); + XDECREF(f->f_globals); + XDECREF(f->f_locals); + XDEL(f->f_valuestack); + XDEL(f->f_blockstack); + DEL(f); +} + +typeobject Frametype = { + OB_HEAD_INIT(&Typetype) + 0, + "frame", + sizeof(frameobject), + 0, + frame_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + frame_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; + +frameobject * +newframeobject(back, code, globals, locals, nvalues, nblocks) + frameobject *back; + codeobject *code; + object *globals; + object *locals; + int nvalues; + int nblocks; +{ + frameobject *f; + if ((back != NULL && !is_frameobject(back)) || + code == NULL || !is_codeobject(code) || + globals == NULL || !is_dictobject(globals) || + locals == NULL || !is_dictobject(locals) || + nvalues < 0 || nblocks < 0) { + err_badcall(); + return NULL; + } + f = NEWOBJ(frameobject, &Frametype); + if (f != NULL) { + if (back) + INCREF(back); + f->f_back = back; + INCREF(code); + f->f_code = code; + INCREF(globals); + f->f_globals = globals; + INCREF(locals); + f->f_locals = locals; + f->f_valuestack = NEW(object *, nvalues+1); + f->f_blockstack = NEW(block, nblocks+1); + f->f_nvalues = nvalues; + f->f_nblocks = nblocks; + f->f_iblock = 0; + if (f->f_valuestack == NULL || f->f_blockstack == NULL) { + err_nomem(); + DECREF(f); + f = NULL; + } + } + return f; +} + +/* Block management */ + +void +setup_block(f, type, handler, level) + frameobject *f; + int type; + int handler; + int level; +{ + block *b; + if (f->f_iblock >= f->f_nblocks) { + fprintf(stderr, "XXX block stack overflow\n"); + abort(); + } + b = &f->f_blockstack[f->f_iblock++]; + b->b_type = type; + b->b_level = level; + b->b_handler = handler; +} + +block * +pop_block(f) + frameobject *f; +{ + block *b; + if (f->f_iblock <= 0) { + fprintf(stderr, "XXX block stack underflow\n"); + abort(); + } + b = &f->f_blockstack[--f->f_iblock]; + return b; +} diff --git a/src/frameobject.h b/src/frameobject.h new file mode 100644 index 0000000..8ea0fa2 --- /dev/null +++ b/src/frameobject.h @@ -0,0 +1,80 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Frame object interface */ + +typedef struct { + int b_type; /* what kind of block this is */ + int b_handler; /* where to jump to find handler */ + int b_level; /* value stack level to pop to */ +} block; + +typedef struct _frame { + OB_HEAD + struct _frame *f_back; /* previous frame, or NULL */ + codeobject *f_code; /* code segment */ + object *f_globals; /* global symbol table (dictobject) */ + object *f_locals; /* local symbol table (dictobject) */ + object **f_valuestack; /* malloc'ed array */ + block *f_blockstack; /* malloc'ed array */ + int f_nvalues; /* size of f_valuestack */ + int f_nblocks; /* size of f_blockstack */ + int f_iblock; /* index in f_blockstack */ +} frameobject; + + +/* Standard object interface */ + +extern typeobject Frametype; + +#define is_frameobject(op) ((op)->ob_type == &Frametype) + +frameobject * newframeobject PROTO( + (frameobject *, codeobject *, object *, object *, int, int)); + + +/* The rest of the interface is specific for frame objects */ + +/* List access macros */ + +#ifdef NDEBUG +#define GETITEM(v, i) GETLISTITEM((listobject *)(v), (i)) +#define GETITEMNAME(v, i) GETSTRINGVALUE((stringobject *)GETITEM((v), (i))) +#else +#define GETITEM(v, i) getlistitem((v), (i)) +#define GETITEMNAME(v, i) getstringvalue(getlistitem((v), (i))) +#endif + +#define GETUSTRINGVALUE(s) ((unsigned char *)GETSTRINGVALUE(s)) + +/* Code access macros */ + +#define Getconst(f, i) (GETITEM((f)->f_code->co_consts, (i))) +#define Getname(f, i) (GETITEMNAME((f)->f_code->co_names, (i))) + + +/* Block management functions */ + +void setup_block PROTO((frameobject *, int, int, int)); +block *pop_block PROTO((frameobject *)); diff --git a/src/funcobject.c b/src/funcobject.c new file mode 100644 index 0000000..1088d7b --- /dev/null +++ b/src/funcobject.c @@ -0,0 +1,113 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Function object implementation */ + +#include "allobjects.h" + +#include "structmember.h" + +typedef struct { + OB_HEAD + object *func_code; + object *func_globals; +} funcobject; + +object * +newfuncobject(code, globals) + object *code; + object *globals; +{ + funcobject *op = NEWOBJ(funcobject, &Functype); + if (op != NULL) { + INCREF(code); + op->func_code = code; + INCREF(globals); + op->func_globals = globals; + } + return (object *)op; +} + +object * +getfunccode(op) + object *op; +{ + if (!is_funcobject(op)) { + err_badcall(); + return NULL; + } + return ((funcobject *) op) -> func_code; +} + +object * +getfuncglobals(op) + object *op; +{ + if (!is_funcobject(op)) { + err_badcall(); + return NULL; + } + return ((funcobject *) op) -> func_globals; +} + +/* Methods */ + +#define OFF(x) offsetof(funcobject, x) + +static struct memberlist func_memberlist[] = { + {"func_code", T_OBJECT, OFF(func_code)}, + {"func_globals",T_OBJECT, OFF(func_globals)}, + {NULL} /* Sentinel */ +}; + +static object * +func_getattr(op, name) + funcobject *op; + char *name; +{ + return getmember((char *)op, func_memberlist, name); +} + +static void +func_dealloc(op) + funcobject *op; +{ + DECREF(op->func_code); + DECREF(op->func_globals); + DEL(op); +} + +typeobject Functype = { + OB_HEAD_INIT(&Typetype) + 0, + "function", + sizeof(funcobject), + 0, + func_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + func_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; diff --git a/src/funcobject.h b/src/funcobject.h new file mode 100644 index 0000000..de8b1a7 --- /dev/null +++ b/src/funcobject.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. + +******************************************************************/ + +/* Function object interface */ + +extern typeobject Functype; + +#define is_funcobject(op) ((op)->ob_type == &Functype) + +extern object *newfuncobject PROTO((object *, object *)); +extern object *getfunccode PROTO((object *)); +extern object *getfuncglobals PROTO((object *)); diff --git a/src/getcwd.c b/src/getcwd.c new file mode 100644 index 0000000..3de6291 --- /dev/null +++ b/src/getcwd.c @@ -0,0 +1,102 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Two PD getcwd() implementations. + Author: Guido van Rossum, CWI Amsterdam, Jan 1991, <[email protected]>. */ + +/* #define NO_GETWD /* Turn this on to popen pwd instead of calling getwd() */ + +#include <stdio.h> +#include <errno.h> + +extern int errno; + +#ifndef NO_GETWD + +/* Default: Version for BSD systems -- use getwd() */ + +#include "sys/param.h" + +extern char *getwd(); + +char * +getcwd(buf, size) + char *buf; + int size; +{ + char localbuf[MAXPATHLEN+1]; + char *ret; + + if (size <= 0) { + errno = EINVAL; + return NULL; + } + ret = getwd(localbuf); + if (ret != NULL && strlen(localbuf) >= size) { + errno = ERANGE; + return NULL; + } + if (ret == NULL) { + errno = EACCES; /* Most likely error */ + return NULL; + } + strncpy(buf, localbuf, size); + return buf; +} + +#else + +/* NO_GETWD defined: Version for backward UNIXes -- popen /bin/pwd */ + +#define PWD_CMD "/bin/pwd" + +char * +getcwd(buf, size) + char *buf; + int size; +{ + FILE *fp; + char *p; + int sts; + if (size <= 0) { + errno = EINVAL; + return NULL; + } + if ((fp = popen(PWD_CMD, "r")) == NULL) + return NULL; + if (fgets(buf, size, fp) == NULL || (sts = pclose(fp)) != 0) { + errno = EACCES; /* Most likely error */ + return NULL; + } + for (p = buf; *p != '\n'; p++) { + if (*p == '\0') { + errno = ERANGE; + return NULL; + } + } + *p = '\0'; + return buf; +} + +#endif diff --git a/src/graminit.c b/src/graminit.c new file mode 100644 index 0000000..2f18183 --- /dev/null +++ b/src/graminit.c @@ -0,0 +1,1094 @@ +/*********************************************************** +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. + +******************************************************************/ + +#include "pgenheaders.h" +#include "grammar.h" +static arc arcs_0_0[3] = { + {2, 1}, + {3, 1}, + {4, 2}, +}; +static arc arcs_0_1[1] = { + {0, 1}, +}; +static arc arcs_0_2[1] = { + {2, 1}, +}; +static state states_0[3] = { + {3, arcs_0_0}, + {1, arcs_0_1}, + {1, arcs_0_2}, +}; +static arc arcs_1_0[3] = { + {2, 0}, + {6, 0}, + {7, 1}, +}; +static arc arcs_1_1[1] = { + {0, 1}, +}; +static state states_1[2] = { + {3, arcs_1_0}, + {1, arcs_1_1}, +}; +static arc arcs_2_0[1] = { + {9, 1}, +}; +static arc arcs_2_1[1] = { + {2, 2}, +}; +static arc arcs_2_2[1] = { + {0, 2}, +}; +static state states_2[3] = { + {1, arcs_2_0}, + {1, arcs_2_1}, + {1, arcs_2_2}, +}; +static arc arcs_3_0[1] = { + {9, 1}, +}; +static arc arcs_3_1[1] = { + {7, 2}, +}; +static arc arcs_3_2[1] = { + {0, 2}, +}; +static state states_3[3] = { + {1, arcs_3_0}, + {1, arcs_3_1}, + {1, arcs_3_2}, +}; +static arc arcs_4_0[1] = { + {12, 1}, +}; +static arc arcs_4_1[1] = { + {13, 2}, +}; +static arc arcs_4_2[1] = { + {14, 3}, +}; +static arc arcs_4_3[1] = { + {15, 4}, +}; +static arc arcs_4_4[1] = { + {16, 5}, +}; +static arc arcs_4_5[1] = { + {0, 5}, +}; +static state states_4[6] = { + {1, arcs_4_0}, + {1, arcs_4_1}, + {1, arcs_4_2}, + {1, arcs_4_3}, + {1, arcs_4_4}, + {1, arcs_4_5}, +}; +static arc arcs_5_0[1] = { + {17, 1}, +}; +static arc arcs_5_1[2] = { + {18, 2}, + {19, 3}, +}; +static arc arcs_5_2[1] = { + {19, 3}, +}; +static arc arcs_5_3[1] = { + {0, 3}, +}; +static state states_5[4] = { + {1, arcs_5_0}, + {2, arcs_5_1}, + {1, arcs_5_2}, + {1, arcs_5_3}, +}; +static arc arcs_6_0[1] = { + {20, 1}, +}; +static arc arcs_6_1[2] = { + {21, 0}, + {0, 1}, +}; +static state states_6[2] = { + {1, arcs_6_0}, + {2, arcs_6_1}, +}; +static arc arcs_7_0[2] = { + {13, 1}, + {17, 2}, +}; +static arc arcs_7_1[1] = { + {0, 1}, +}; +static arc arcs_7_2[1] = { + {18, 3}, +}; +static arc arcs_7_3[1] = { + {19, 1}, +}; +static state states_7[4] = { + {2, arcs_7_0}, + {1, arcs_7_1}, + {1, arcs_7_2}, + {1, arcs_7_3}, +}; +static arc arcs_8_0[2] = { + {3, 1}, + {4, 1}, +}; +static arc arcs_8_1[1] = { + {0, 1}, +}; +static state states_8[2] = { + {2, arcs_8_0}, + {1, arcs_8_1}, +}; +static arc arcs_9_0[6] = { + {22, 1}, + {23, 1}, + {24, 1}, + {25, 1}, + {26, 1}, + {27, 1}, +}; +static arc arcs_9_1[1] = { + {0, 1}, +}; +static state states_9[2] = { + {6, arcs_9_0}, + {1, arcs_9_1}, +}; +static arc arcs_10_0[1] = { + {28, 1}, +}; +static arc arcs_10_1[2] = { + {29, 0}, + {2, 2}, +}; +static arc arcs_10_2[1] = { + {0, 2}, +}; +static state states_10[3] = { + {1, arcs_10_0}, + {2, arcs_10_1}, + {1, arcs_10_2}, +}; +static arc arcs_11_0[1] = { + {30, 1}, +}; +static arc arcs_11_1[2] = { + {31, 2}, + {2, 3}, +}; +static arc arcs_11_2[2] = { + {21, 1}, + {2, 3}, +}; +static arc arcs_11_3[1] = { + {0, 3}, +}; +static state states_11[4] = { + {1, arcs_11_0}, + {2, arcs_11_1}, + {2, arcs_11_2}, + {1, arcs_11_3}, +}; +static arc arcs_12_0[1] = { + {32, 1}, +}; +static arc arcs_12_1[1] = { + {28, 2}, +}; +static arc arcs_12_2[1] = { + {2, 3}, +}; +static arc arcs_12_3[1] = { + {0, 3}, +}; +static state states_12[4] = { + {1, arcs_12_0}, + {1, arcs_12_1}, + {1, arcs_12_2}, + {1, arcs_12_3}, +}; +static arc arcs_13_0[1] = { + {33, 1}, +}; +static arc arcs_13_1[1] = { + {2, 2}, +}; +static arc arcs_13_2[1] = { + {0, 2}, +}; +static state states_13[3] = { + {1, arcs_13_0}, + {1, arcs_13_1}, + {1, arcs_13_2}, +}; +static arc arcs_14_0[3] = { + {34, 1}, + {35, 1}, + {36, 1}, +}; +static arc arcs_14_1[1] = { + {0, 1}, +}; +static state states_14[2] = { + {3, arcs_14_0}, + {1, arcs_14_1}, +}; +static arc arcs_15_0[1] = { + {37, 1}, +}; +static arc arcs_15_1[1] = { + {2, 2}, +}; +static arc arcs_15_2[1] = { + {0, 2}, +}; +static state states_15[3] = { + {1, arcs_15_0}, + {1, arcs_15_1}, + {1, arcs_15_2}, +}; +static arc arcs_16_0[1] = { + {38, 1}, +}; +static arc arcs_16_1[2] = { + {9, 2}, + {2, 3}, +}; +static arc arcs_16_2[1] = { + {2, 3}, +}; +static arc arcs_16_3[1] = { + {0, 3}, +}; +static state states_16[4] = { + {1, arcs_16_0}, + {2, arcs_16_1}, + {1, arcs_16_2}, + {1, arcs_16_3}, +}; +static arc arcs_17_0[1] = { + {39, 1}, +}; +static arc arcs_17_1[1] = { + {40, 2}, +}; +static arc arcs_17_2[2] = { + {21, 3}, + {2, 4}, +}; +static arc arcs_17_3[1] = { + {40, 5}, +}; +static arc arcs_17_4[1] = { + {0, 4}, +}; +static arc arcs_17_5[1] = { + {2, 4}, +}; +static state states_17[6] = { + {1, arcs_17_0}, + {1, arcs_17_1}, + {2, arcs_17_2}, + {1, arcs_17_3}, + {1, arcs_17_4}, + {1, arcs_17_5}, +}; +static arc arcs_18_0[2] = { + {41, 1}, + {42, 2}, +}; +static arc arcs_18_1[1] = { + {13, 3}, +}; +static arc arcs_18_2[1] = { + {13, 4}, +}; +static arc arcs_18_3[2] = { + {21, 1}, + {2, 5}, +}; +static arc arcs_18_4[1] = { + {41, 6}, +}; +static arc arcs_18_5[1] = { + {0, 5}, +}; +static arc arcs_18_6[2] = { + {43, 7}, + {13, 8}, +}; +static arc arcs_18_7[1] = { + {2, 5}, +}; +static arc arcs_18_8[2] = { + {21, 9}, + {2, 5}, +}; +static arc arcs_18_9[1] = { + {13, 8}, +}; +static state states_18[10] = { + {2, arcs_18_0}, + {1, arcs_18_1}, + {1, arcs_18_2}, + {2, arcs_18_3}, + {1, arcs_18_4}, + {1, arcs_18_5}, + {2, arcs_18_6}, + {1, arcs_18_7}, + {2, arcs_18_8}, + {1, arcs_18_9}, +}; +static arc arcs_19_0[6] = { + {44, 1}, + {45, 1}, + {46, 1}, + {47, 1}, + {11, 1}, + {48, 1}, +}; +static arc arcs_19_1[1] = { + {0, 1}, +}; +static state states_19[2] = { + {6, arcs_19_0}, + {1, arcs_19_1}, +}; +static arc arcs_20_0[1] = { + {49, 1}, +}; +static arc arcs_20_1[1] = { + {31, 2}, +}; +static arc arcs_20_2[1] = { + {15, 3}, +}; +static arc arcs_20_3[1] = { + {16, 4}, +}; +static arc arcs_20_4[3] = { + {50, 1}, + {51, 5}, + {0, 4}, +}; +static arc arcs_20_5[1] = { + {15, 6}, +}; +static arc arcs_20_6[1] = { + {16, 7}, +}; +static arc arcs_20_7[1] = { + {0, 7}, +}; +static state states_20[8] = { + {1, arcs_20_0}, + {1, arcs_20_1}, + {1, arcs_20_2}, + {1, arcs_20_3}, + {3, arcs_20_4}, + {1, arcs_20_5}, + {1, arcs_20_6}, + {1, arcs_20_7}, +}; +static arc arcs_21_0[1] = { + {52, 1}, +}; +static arc arcs_21_1[1] = { + {31, 2}, +}; +static arc arcs_21_2[1] = { + {15, 3}, +}; +static arc arcs_21_3[1] = { + {16, 4}, +}; +static arc arcs_21_4[2] = { + {51, 5}, + {0, 4}, +}; +static arc arcs_21_5[1] = { + {15, 6}, +}; +static arc arcs_21_6[1] = { + {16, 7}, +}; +static arc arcs_21_7[1] = { + {0, 7}, +}; +static state states_21[8] = { + {1, arcs_21_0}, + {1, arcs_21_1}, + {1, arcs_21_2}, + {1, arcs_21_3}, + {2, arcs_21_4}, + {1, arcs_21_5}, + {1, arcs_21_6}, + {1, arcs_21_7}, +}; +static arc arcs_22_0[1] = { + {53, 1}, +}; +static arc arcs_22_1[1] = { + {28, 2}, +}; +static arc arcs_22_2[1] = { + {54, 3}, +}; +static arc arcs_22_3[1] = { + {28, 4}, +}; +static arc arcs_22_4[1] = { + {15, 5}, +}; +static arc arcs_22_5[1] = { + {16, 6}, +}; +static arc arcs_22_6[2] = { + {51, 7}, + {0, 6}, +}; +static arc arcs_22_7[1] = { + {15, 8}, +}; +static arc arcs_22_8[1] = { + {16, 9}, +}; +static arc arcs_22_9[1] = { + {0, 9}, +}; +static state states_22[10] = { + {1, arcs_22_0}, + {1, arcs_22_1}, + {1, arcs_22_2}, + {1, arcs_22_3}, + {1, arcs_22_4}, + {1, arcs_22_5}, + {2, arcs_22_6}, + {1, arcs_22_7}, + {1, arcs_22_8}, + {1, arcs_22_9}, +}; +static arc arcs_23_0[1] = { + {55, 1}, +}; +static arc arcs_23_1[1] = { + {15, 2}, +}; +static arc arcs_23_2[1] = { + {16, 3}, +}; +static arc arcs_23_3[3] = { + {56, 1}, + {57, 4}, + {0, 3}, +}; +static arc arcs_23_4[1] = { + {15, 5}, +}; +static arc arcs_23_5[1] = { + {16, 6}, +}; +static arc arcs_23_6[1] = { + {0, 6}, +}; +static state states_23[7] = { + {1, arcs_23_0}, + {1, arcs_23_1}, + {1, arcs_23_2}, + {3, arcs_23_3}, + {1, arcs_23_4}, + {1, arcs_23_5}, + {1, arcs_23_6}, +}; +static arc arcs_24_0[1] = { + {58, 1}, +}; +static arc arcs_24_1[2] = { + {40, 2}, + {0, 1}, +}; +static arc arcs_24_2[2] = { + {21, 3}, + {0, 2}, +}; +static arc arcs_24_3[1] = { + {40, 4}, +}; +static arc arcs_24_4[1] = { + {0, 4}, +}; +static state states_24[5] = { + {1, arcs_24_0}, + {2, arcs_24_1}, + {2, arcs_24_2}, + {1, arcs_24_3}, + {1, arcs_24_4}, +}; +static arc arcs_25_0[2] = { + {3, 1}, + {2, 2}, +}; +static arc arcs_25_1[1] = { + {0, 1}, +}; +static arc arcs_25_2[1] = { + {59, 3}, +}; +static arc arcs_25_3[2] = { + {2, 3}, + {6, 4}, +}; +static arc arcs_25_4[3] = { + {6, 4}, + {2, 4}, + {60, 1}, +}; +static state states_25[5] = { + {2, arcs_25_0}, + {1, arcs_25_1}, + {1, arcs_25_2}, + {2, arcs_25_3}, + {3, arcs_25_4}, +}; +static arc arcs_26_0[1] = { + {61, 1}, +}; +static arc arcs_26_1[2] = { + {62, 0}, + {0, 1}, +}; +static state states_26[2] = { + {1, arcs_26_0}, + {2, arcs_26_1}, +}; +static arc arcs_27_0[1] = { + {63, 1}, +}; +static arc arcs_27_1[2] = { + {64, 0}, + {0, 1}, +}; +static state states_27[2] = { + {1, arcs_27_0}, + {2, arcs_27_1}, +}; +static arc arcs_28_0[2] = { + {65, 1}, + {66, 2}, +}; +static arc arcs_28_1[1] = { + {63, 2}, +}; +static arc arcs_28_2[1] = { + {0, 2}, +}; +static state states_28[3] = { + {2, arcs_28_0}, + {1, arcs_28_1}, + {1, arcs_28_2}, +}; +static arc arcs_29_0[1] = { + {40, 1}, +}; +static arc arcs_29_1[2] = { + {67, 0}, + {0, 1}, +}; +static state states_29[2] = { + {1, arcs_29_0}, + {2, arcs_29_1}, +}; +static arc arcs_30_0[6] = { + {68, 1}, + {69, 2}, + {29, 3}, + {54, 3}, + {65, 4}, + {70, 5}, +}; +static arc arcs_30_1[3] = { + {29, 3}, + {69, 3}, + {0, 1}, +}; +static arc arcs_30_2[2] = { + {29, 3}, + {0, 2}, +}; +static arc arcs_30_3[1] = { + {0, 3}, +}; +static arc arcs_30_4[1] = { + {54, 3}, +}; +static arc arcs_30_5[2] = { + {65, 3}, + {0, 5}, +}; +static state states_30[6] = { + {6, arcs_30_0}, + {3, arcs_30_1}, + {2, arcs_30_2}, + {1, arcs_30_3}, + {1, arcs_30_4}, + {2, arcs_30_5}, +}; +static arc arcs_31_0[1] = { + {71, 1}, +}; +static arc arcs_31_1[3] = { + {72, 0}, + {73, 0}, + {0, 1}, +}; +static state states_31[2] = { + {1, arcs_31_0}, + {3, arcs_31_1}, +}; +static arc arcs_32_0[1] = { + {74, 1}, +}; +static arc arcs_32_1[4] = { + {43, 0}, + {75, 0}, + {76, 0}, + {0, 1}, +}; +static state states_32[2] = { + {1, arcs_32_0}, + {4, arcs_32_1}, +}; +static arc arcs_33_0[3] = { + {72, 1}, + {73, 1}, + {77, 2}, +}; +static arc arcs_33_1[1] = { + {74, 3}, +}; +static arc arcs_33_2[2] = { + {78, 2}, + {0, 2}, +}; +static arc arcs_33_3[1] = { + {0, 3}, +}; +static state states_33[4] = { + {3, arcs_33_0}, + {1, arcs_33_1}, + {2, arcs_33_2}, + {1, arcs_33_3}, +}; +static arc arcs_34_0[7] = { + {17, 1}, + {79, 2}, + {81, 3}, + {83, 4}, + {13, 5}, + {84, 5}, + {85, 5}, +}; +static arc arcs_34_1[2] = { + {9, 6}, + {19, 5}, +}; +static arc arcs_34_2[2] = { + {9, 7}, + {80, 5}, +}; +static arc arcs_34_3[1] = { + {82, 5}, +}; +static arc arcs_34_4[1] = { + {9, 8}, +}; +static arc arcs_34_5[1] = { + {0, 5}, +}; +static arc arcs_34_6[1] = { + {19, 5}, +}; +static arc arcs_34_7[1] = { + {80, 5}, +}; +static arc arcs_34_8[1] = { + {83, 5}, +}; +static state states_34[9] = { + {7, arcs_34_0}, + {2, arcs_34_1}, + {2, arcs_34_2}, + {1, arcs_34_3}, + {1, arcs_34_4}, + {1, arcs_34_5}, + {1, arcs_34_6}, + {1, arcs_34_7}, + {1, arcs_34_8}, +}; +static arc arcs_35_0[3] = { + {17, 1}, + {79, 2}, + {87, 3}, +}; +static arc arcs_35_1[2] = { + {9, 4}, + {19, 5}, +}; +static arc arcs_35_2[1] = { + {86, 6}, +}; +static arc arcs_35_3[1] = { + {13, 5}, +}; +static arc arcs_35_4[1] = { + {19, 5}, +}; +static arc arcs_35_5[1] = { + {0, 5}, +}; +static arc arcs_35_6[1] = { + {80, 5}, +}; +static state states_35[7] = { + {3, arcs_35_0}, + {2, arcs_35_1}, + {1, arcs_35_2}, + {1, arcs_35_3}, + {1, arcs_35_4}, + {1, arcs_35_5}, + {1, arcs_35_6}, +}; +static arc arcs_36_0[2] = { + {40, 1}, + {15, 2}, +}; +static arc arcs_36_1[2] = { + {15, 2}, + {0, 1}, +}; +static arc arcs_36_2[2] = { + {40, 3}, + {0, 2}, +}; +static arc arcs_36_3[1] = { + {0, 3}, +}; +static state states_36[4] = { + {2, arcs_36_0}, + {2, arcs_36_1}, + {2, arcs_36_2}, + {1, arcs_36_3}, +}; +static arc arcs_37_0[1] = { + {40, 1}, +}; +static arc arcs_37_1[2] = { + {21, 2}, + {0, 1}, +}; +static arc arcs_37_2[2] = { + {40, 1}, + {0, 2}, +}; +static state states_37[3] = { + {1, arcs_37_0}, + {2, arcs_37_1}, + {2, arcs_37_2}, +}; +static arc arcs_38_0[1] = { + {31, 1}, +}; +static arc arcs_38_1[2] = { + {21, 2}, + {0, 1}, +}; +static arc arcs_38_2[2] = { + {31, 1}, + {0, 2}, +}; +static state states_38[3] = { + {1, arcs_38_0}, + {2, arcs_38_1}, + {2, arcs_38_2}, +}; +static arc arcs_39_0[1] = { + {88, 1}, +}; +static arc arcs_39_1[1] = { + {13, 2}, +}; +static arc arcs_39_2[1] = { + {14, 3}, +}; +static arc arcs_39_3[2] = { + {29, 4}, + {15, 5}, +}; +static arc arcs_39_4[1] = { + {89, 6}, +}; +static arc arcs_39_5[1] = { + {16, 7}, +}; +static arc arcs_39_6[1] = { + {15, 5}, +}; +static arc arcs_39_7[1] = { + {0, 7}, +}; +static state states_39[8] = { + {1, arcs_39_0}, + {1, arcs_39_1}, + {1, arcs_39_2}, + {2, arcs_39_3}, + {1, arcs_39_4}, + {1, arcs_39_5}, + {1, arcs_39_6}, + {1, arcs_39_7}, +}; +static arc arcs_40_0[1] = { + {77, 1}, +}; +static arc arcs_40_1[1] = { + {90, 2}, +}; +static arc arcs_40_2[2] = { + {21, 0}, + {0, 2}, +}; +static state states_40[3] = { + {1, arcs_40_0}, + {1, arcs_40_1}, + {2, arcs_40_2}, +}; +static arc arcs_41_0[1] = { + {17, 1}, +}; +static arc arcs_41_1[2] = { + {9, 2}, + {19, 3}, +}; +static arc arcs_41_2[1] = { + {19, 3}, +}; +static arc arcs_41_3[1] = { + {0, 3}, +}; +static state states_41[4] = { + {1, arcs_41_0}, + {2, arcs_41_1}, + {1, arcs_41_2}, + {1, arcs_41_3}, +}; +static dfa dfas[42] = { + {256, "single_input", 0, 3, states_0, + "\004\060\002\100\343\006\262\000\000\203\072\001"}, + {257, "file_input", 0, 2, states_1, + "\204\060\002\100\343\006\262\000\000\203\072\001"}, + {258, "expr_input", 0, 3, states_2, + "\000\040\002\000\000\000\000\000\002\203\072\000"}, + {259, "eval_input", 0, 3, states_3, + "\000\040\002\000\000\000\000\000\002\203\072\000"}, + {260, "funcdef", 0, 6, states_4, + "\000\020\000\000\000\000\000\000\000\000\000\000"}, + {261, "parameters", 0, 4, states_5, + "\000\000\002\000\000\000\000\000\000\000\000\000"}, + {262, "fplist", 0, 2, states_6, + "\000\040\002\000\000\000\000\000\000\000\000\000"}, + {263, "fpdef", 0, 4, states_7, + "\000\040\002\000\000\000\000\000\000\000\000\000"}, + {264, "stmt", 0, 2, states_8, + "\000\060\002\100\343\006\262\000\000\203\072\001"}, + {265, "simple_stmt", 0, 2, states_9, + "\000\040\002\100\343\006\000\000\000\203\072\000"}, + {266, "expr_stmt", 0, 3, states_10, + "\000\040\002\000\000\000\000\000\000\203\072\000"}, + {267, "print_stmt", 0, 4, states_11, + "\000\000\000\100\000\000\000\000\000\000\000\000"}, + {268, "del_stmt", 0, 4, states_12, + "\000\000\000\000\001\000\000\000\000\000\000\000"}, + {269, "pass_stmt", 0, 3, states_13, + "\000\000\000\000\002\000\000\000\000\000\000\000"}, + {270, "flow_stmt", 0, 2, states_14, + "\000\000\000\000\340\000\000\000\000\000\000\000"}, + {271, "break_stmt", 0, 3, states_15, + "\000\000\000\000\040\000\000\000\000\000\000\000"}, + {272, "return_stmt", 0, 4, states_16, + "\000\000\000\000\100\000\000\000\000\000\000\000"}, + {273, "raise_stmt", 0, 6, states_17, + "\000\000\000\000\200\000\000\000\000\000\000\000"}, + {274, "import_stmt", 0, 10, states_18, + "\000\000\000\000\000\006\000\000\000\000\000\000"}, + {275, "compound_stmt", 0, 2, states_19, + "\000\020\000\000\000\000\262\000\000\000\000\001"}, + {276, "if_stmt", 0, 8, states_20, + "\000\000\000\000\000\000\002\000\000\000\000\000"}, + {277, "while_stmt", 0, 8, states_21, + "\000\000\000\000\000\000\020\000\000\000\000\000"}, + {278, "for_stmt", 0, 10, states_22, + "\000\000\000\000\000\000\040\000\000\000\000\000"}, + {279, "try_stmt", 0, 7, states_23, + "\000\000\000\000\000\000\200\000\000\000\000\000"}, + {280, "except_clause", 0, 5, states_24, + "\000\000\000\000\000\000\000\004\000\000\000\000"}, + {281, "suite", 0, 5, states_25, + "\004\040\002\100\343\006\000\000\000\203\072\000"}, + {282, "test", 0, 2, states_26, + "\000\040\002\000\000\000\000\000\002\203\072\000"}, + {283, "and_test", 0, 2, states_27, + "\000\040\002\000\000\000\000\000\002\203\072\000"}, + {284, "not_test", 0, 3, states_28, + "\000\040\002\000\000\000\000\000\002\203\072\000"}, + {285, "comparison", 0, 2, states_29, + "\000\040\002\000\000\000\000\000\000\203\072\000"}, + {286, "comp_op", 0, 6, states_30, + "\000\000\000\040\000\000\100\000\162\000\000\000"}, + {287, "expr", 0, 2, states_31, + "\000\040\002\000\000\000\000\000\000\203\072\000"}, + {288, "term", 0, 2, states_32, + "\000\040\002\000\000\000\000\000\000\203\072\000"}, + {289, "factor", 0, 4, states_33, + "\000\040\002\000\000\000\000\000\000\203\072\000"}, + {290, "atom", 0, 9, states_34, + "\000\040\002\000\000\000\000\000\000\200\072\000"}, + {291, "trailer", 0, 7, states_35, + "\000\000\002\000\000\000\000\000\000\200\200\000"}, + {292, "subscript", 0, 4, states_36, + "\000\240\002\000\000\000\000\000\000\203\072\000"}, + {293, "exprlist", 0, 3, states_37, + "\000\040\002\000\000\000\000\000\000\203\072\000"}, + {294, "testlist", 0, 3, states_38, + "\000\040\002\000\000\000\000\000\002\203\072\000"}, + {295, "classdef", 0, 8, states_39, + "\000\000\000\000\000\000\000\000\000\000\000\001"}, + {296, "baselist", 0, 3, states_40, + "\000\040\002\000\000\000\000\000\000\200\072\000"}, + {297, "arguments", 0, 4, states_41, + "\000\000\002\000\000\000\000\000\000\000\000\000"}, +}; +static label labels[91] = { + {0, "EMPTY"}, + {256, 0}, + {4, 0}, + {265, 0}, + {275, 0}, + {257, 0}, + {264, 0}, + {0, 0}, + {258, 0}, + {294, 0}, + {259, 0}, + {260, 0}, + {1, "def"}, + {1, 0}, + {261, 0}, + {11, 0}, + {281, 0}, + {7, 0}, + {262, 0}, + {8, 0}, + {263, 0}, + {12, 0}, + {266, 0}, + {267, 0}, + {269, 0}, + {268, 0}, + {270, 0}, + {274, 0}, + {293, 0}, + {22, 0}, + {1, "print"}, + {282, 0}, + {1, "del"}, + {1, "pass"}, + {271, 0}, + {272, 0}, + {273, 0}, + {1, "break"}, + {1, "return"}, + {1, "raise"}, + {287, 0}, + {1, "import"}, + {1, "from"}, + {16, 0}, + {276, 0}, + {277, 0}, + {278, 0}, + {279, 0}, + {295, 0}, + {1, "if"}, + {1, "elif"}, + {1, "else"}, + {1, "while"}, + {1, "for"}, + {1, "in"}, + {1, "try"}, + {280, 0}, + {1, "finally"}, + {1, "except"}, + {5, 0}, + {6, 0}, + {283, 0}, + {1, "or"}, + {284, 0}, + {1, "and"}, + {1, "not"}, + {285, 0}, + {286, 0}, + {20, 0}, + {21, 0}, + {1, "is"}, + {288, 0}, + {14, 0}, + {15, 0}, + {289, 0}, + {17, 0}, + {24, 0}, + {290, 0}, + {291, 0}, + {9, 0}, + {10, 0}, + {26, 0}, + {27, 0}, + {25, 0}, + {2, 0}, + {3, 0}, + {292, 0}, + {23, 0}, + {1, "class"}, + {296, 0}, + {297, 0}, +}; +grammar gram = { + 42, + dfas, + {91, labels}, + 256 +}; diff --git a/src/graminit.h b/src/graminit.h new file mode 100644 index 0000000..051b549 --- /dev/null +++ b/src/graminit.h @@ -0,0 +1,66 @@ +/*********************************************************** +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 single_input 256 +#define file_input 257 +#define expr_input 258 +#define eval_input 259 +#define funcdef 260 +#define parameters 261 +#define fplist 262 +#define fpdef 263 +#define stmt 264 +#define simple_stmt 265 +#define expr_stmt 266 +#define print_stmt 267 +#define del_stmt 268 +#define pass_stmt 269 +#define flow_stmt 270 +#define break_stmt 271 +#define return_stmt 272 +#define raise_stmt 273 +#define import_stmt 274 +#define compound_stmt 275 +#define if_stmt 276 +#define while_stmt 277 +#define for_stmt 278 +#define try_stmt 279 +#define except_clause 280 +#define suite 281 +#define test 282 +#define and_test 283 +#define not_test 284 +#define comparison 285 +#define comp_op 286 +#define expr 287 +#define term 288 +#define factor 289 +#define atom 290 +#define trailer 291 +#define subscript 292 +#define exprlist 293 +#define testlist 294 +#define classdef 295 +#define baselist 296 +#define arguments 297 diff --git a/src/grammar.c b/src/grammar.c new file mode 100644 index 0000000..4ba4a1a --- /dev/null +++ b/src/grammar.c @@ -0,0 +1,233 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Grammar implementation */ + +#include "pgenheaders.h" + +#include <ctype.h> + +#include "assert.h" +#include "token.h" +#include "grammar.h" + +extern int debugging; + +grammar * +newgrammar(start) + int start; +{ + grammar *g; + + g = NEW(grammar, 1); + if (g == NULL) + fatal("no mem for new grammar"); + g->g_ndfas = 0; + g->g_dfa = NULL; + g->g_start = start; + g->g_ll.ll_nlabels = 0; + g->g_ll.ll_label = NULL; + return g; +} + +dfa * +adddfa(g, type, name) + grammar *g; + int type; + char *name; +{ + dfa *d; + + RESIZE(g->g_dfa, dfa, g->g_ndfas + 1); + if (g->g_dfa == NULL) + fatal("no mem to resize dfa in adddfa"); + d = &g->g_dfa[g->g_ndfas++]; + d->d_type = type; + d->d_name = name; + d->d_nstates = 0; + d->d_state = NULL; + d->d_initial = -1; + d->d_first = NULL; + return d; /* Only use while fresh! */ +} + +int +addstate(d) + dfa *d; +{ + state *s; + + RESIZE(d->d_state, state, d->d_nstates + 1); + if (d->d_state == NULL) + fatal("no mem to resize state in addstate"); + s = &d->d_state[d->d_nstates++]; + s->s_narcs = 0; + s->s_arc = NULL; + return s - d->d_state; +} + +void +addarc(d, from, to, lbl) + dfa *d; + int lbl; +{ + state *s; + arc *a; + + assert(0 <= from && from < d->d_nstates); + assert(0 <= to && to < d->d_nstates); + + s = &d->d_state[from]; + RESIZE(s->s_arc, arc, s->s_narcs + 1); + if (s->s_arc == NULL) + fatal("no mem to resize arc list in addarc"); + a = &s->s_arc[s->s_narcs++]; + a->a_lbl = lbl; + a->a_arrow = to; +} + +int +addlabel(ll, type, str) + labellist *ll; + int type; + char *str; +{ + int i; + label *lb; + + for (i = 0; i < ll->ll_nlabels; i++) { + if (ll->ll_label[i].lb_type == type && + strcmp(ll->ll_label[i].lb_str, str) == 0) + return i; + } + RESIZE(ll->ll_label, label, ll->ll_nlabels + 1); + if (ll->ll_label == NULL) + fatal("no mem to resize labellist in addlabel"); + lb = &ll->ll_label[ll->ll_nlabels++]; + lb->lb_type = type; + lb->lb_str = str; /* XXX strdup(str) ??? */ + return lb - ll->ll_label; +} + +/* Same, but rather dies than adds */ + +int +findlabel(ll, type, str) + labellist *ll; + int type; + char *str; +{ + int i; + label *lb; + + for (i = 0; i < ll->ll_nlabels; i++) { + if (ll->ll_label[i].lb_type == type /*&& + strcmp(ll->ll_label[i].lb_str, str) == 0*/) + return i; + } + fprintf(stderr, "Label %d/'%s' not found\n", type, str); + abort(); +} + +/* Forward */ +static void translabel PROTO((grammar *, label *)); + +void +translatelabels(g) + grammar *g; +{ + int i; + + printf("Translating labels ...\n"); + /* Don't translate EMPTY */ + for (i = EMPTY+1; i < g->g_ll.ll_nlabels; i++) + translabel(g, &g->g_ll.ll_label[i]); +} + +static void +translabel(g, lb) + grammar *g; + label *lb; +{ + int i; + + if (debugging) + printf("Translating label %s ...\n", labelrepr(lb)); + + if (lb->lb_type == NAME) { + for (i = 0; i < g->g_ndfas; i++) { + if (strcmp(lb->lb_str, g->g_dfa[i].d_name) == 0) { + if (debugging) + printf("Label %s is non-terminal %d.\n", + lb->lb_str, + g->g_dfa[i].d_type); + lb->lb_type = g->g_dfa[i].d_type; + lb->lb_str = NULL; + return; + } + } + for (i = 0; i < (int)N_TOKENS; i++) { + if (strcmp(lb->lb_str, tok_name[i]) == 0) { + if (debugging) + printf("Label %s is terminal %d.\n", + lb->lb_str, i); + lb->lb_type = i; + lb->lb_str = NULL; + return; + } + } + printf("Can't translate NAME label '%s'\n", lb->lb_str); + return; + } + + if (lb->lb_type == STRING) { + if (isalpha(lb->lb_str[1])) { + char *p, *strchr(); + if (debugging) + printf("Label %s is a keyword\n", lb->lb_str); + lb->lb_type = NAME; + lb->lb_str++; + p = strchr(lb->lb_str, '\''); + if (p) + *p = '\0'; + } + else { + if (lb->lb_str[2] == lb->lb_str[0]) { + int type = (int) tok_1char(lb->lb_str[1]); + if (type != OP) { + lb->lb_type = type; + lb->lb_str = NULL; + } + else + printf("Unknown OP label %s\n", + lb->lb_str); + } + else + printf("Can't translate STRING label %s\n", + lb->lb_str); + } + } + else + printf("Can't translate label '%s'\n", labelrepr(lb)); +} diff --git a/src/grammar.h b/src/grammar.h new file mode 100644 index 0000000..82f34c3 --- /dev/null +++ b/src/grammar.h @@ -0,0 +1,105 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Grammar interface */ + +#include "bitset.h" /* Sigh... */ + +/* A label of an arc */ + +typedef struct _label { + int lb_type; + char *lb_str; +} label; + +#define EMPTY 0 /* Label number 0 is by definition the empty label */ + +/* A list of labels */ + +typedef struct _labellist { + int ll_nlabels; + label *ll_label; +} labellist; + +/* An arc from one state to another */ + +typedef struct _arc { + short a_lbl; /* Label of this arc */ + short a_arrow; /* State where this arc goes to */ +} arc; + +/* A state in a DFA */ + +typedef struct _state { + int s_narcs; + arc *s_arc; /* Array of arcs */ + + /* Optional accelerators */ + int s_lower; /* Lowest label index */ + int s_upper; /* Highest label index */ + int *s_accel; /* Accelerator */ + int s_accept; /* Nonzero for accepting state */ +} state; + +/* A DFA */ + +typedef struct _dfa { + int d_type; /* Non-terminal this represents */ + char *d_name; /* For printing */ + int d_initial; /* Initial state */ + int d_nstates; + state *d_state; /* Array of states */ + bitset d_first; +} dfa; + +/* A grammar */ + +typedef struct _grammar { + int g_ndfas; + dfa *g_dfa; /* Array of DFAs */ + labellist g_ll; + int g_start; /* Start symbol of the grammar */ + int g_accel; /* Set if accelerators present */ +} grammar; + +/* FUNCTIONS */ + +grammar *newgrammar PROTO((int start)); +dfa *adddfa PROTO((grammar *g, int type, char *name)); +int addstate PROTO((dfa *d)); +void addarc PROTO((dfa *d, int from, int to, int lbl)); +dfa *finddfa PROTO((grammar *g, int type)); +char *typename PROTO((grammar *g, int lbl)); + +int addlabel PROTO((labellist *ll, int type, char *str)); +int findlabel PROTO((labellist *ll, int type, char *str)); +char *labelrepr PROTO((label *lb)); +void translatelabels PROTO((grammar *g)); + +void addfirstsets PROTO((grammar *g)); + +void addaccellerators PROTO((grammar *g)); + +void printgrammar PROTO((grammar *g, FILE *fp)); +void printnonterminals PROTO((grammar *g, FILE *fp)); diff --git a/src/grammar1.c b/src/grammar1.c new file mode 100644 index 0000000..eafe4fe --- /dev/null +++ b/src/grammar1.c @@ -0,0 +1,75 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Grammar subroutines needed by parser */ + +#include "pgenheaders.h" +#include "assert.h" +#include "grammar.h" +#include "token.h" + +/* Return the DFA for the given type */ + +dfa * +finddfa(g, type) + grammar *g; + register int type; +{ + register int i; + register dfa *d; + + for (i = g->g_ndfas, d = g->g_dfa; --i >= 0; d++) { + if (d->d_type == type) + return d; + } + assert(0); + /* NOTREACHED */ +} + +char * +labelrepr(lb) + label *lb; +{ + static char buf[100]; + + if (lb->lb_type == ENDMARKER) + return "EMPTY"; + else if (ISNONTERMINAL(lb->lb_type)) { + if (lb->lb_str == NULL) { + sprintf(buf, "NT%d", lb->lb_type); + return buf; + } + else + return lb->lb_str; + } + else { + if (lb->lb_str == NULL) + return tok_name[lb->lb_type]; + else { + sprintf(buf, "%.32s(%.32s)", + tok_name[lb->lb_type], lb->lb_str); + return buf; + } + } +} diff --git a/src/import.c b/src/import.c new file mode 100644 index 0000000..d461007 --- /dev/null +++ b/src/import.c @@ -0,0 +1,259 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Module definition and import implementation */ + +#include "allobjects.h" + +#include "node.h" +#include "token.h" +#include "graminit.h" +#include "import.h" +#include "errcode.h" +#include "sysmodule.h" +#include "pythonrun.h" + +/* Define pathname separator used in file names */ + +#ifdef THINK_C +#define SEP ':' +#endif + +#ifndef SEP +#define SEP '/' +#endif + +static object *modules; + +/* Initialization */ + +void +initimport() +{ + if ((modules = newdictobject()) == NULL) + fatal("no mem for dictionary of modules"); +} + +object * +get_modules() +{ + return modules; +} + +object * +add_module(name) + char *name; +{ + object *m; + if ((m = dictlookup(modules, name)) != NULL && is_moduleobject(m)) + return m; + m = newmoduleobject(name); + if (m == NULL) + return NULL; + if (dictinsert(modules, name, m) != 0) { + DECREF(m); + return NULL; + } + DECREF(m); /* Yes, it still exists, in modules! */ + return m; +} + +static FILE * +open_module(name, suffix, namebuf) + char *name; + char *suffix; + char *namebuf; /* XXX No buffer overflow checks! */ +{ + object *path; + FILE *fp; + + path = sysget("path"); + if (path == NULL || !is_listobject(path)) { + strcpy(namebuf, name); + strcat(namebuf, suffix); + fp = fopen(namebuf, "r"); + } + else { + int npath = getlistsize(path); + int i; + fp = NULL; + for (i = 0; i < npath; i++) { + object *v = getlistitem(path, i); + int len; + if (!is_stringobject(v)) + continue; + strcpy(namebuf, getstringvalue(v)); + len = getstringsize(v); + if (len > 0 && namebuf[len-1] != SEP) + namebuf[len++] = SEP; + strcpy(namebuf+len, name); + strcat(namebuf, suffix); + fp = fopen(namebuf, "r"); + if (fp != NULL) + break; + } + } + return fp; +} + +static object * +get_module(m, name, m_ret) + /*module*/object *m; + char *name; + object **m_ret; +{ + object *d; + FILE *fp; + node *n; + int err; + char namebuf[256]; + + fp = open_module(name, ".py", namebuf); + if (fp == NULL) { + if (m == NULL) + err_setstr(NameError, name); + else + err_setstr(RuntimeError, "no module source file"); + return NULL; + } + err = parse_file(fp, namebuf, file_input, &n); + fclose(fp); + if (err != E_DONE) { + err_input(err); + return NULL; + } + if (m == NULL) { + m = add_module(name); + if (m == NULL) { + freetree(n); + return NULL; + } + *m_ret = m; + } + d = getmoduledict(m); + return run_node(n, namebuf, d, d); +} + +static object * +load_module(name) + char *name; +{ + object *m, *v; + v = get_module((object *)NULL, name, &m); + if (v == NULL) + return NULL; + DECREF(v); + return m; +} + +object * +import_module(name) + char *name; +{ + object *m; + if ((m = dictlookup(modules, name)) == NULL) { + if (init_builtin(name)) { + if ((m = dictlookup(modules, name)) == NULL) + err_setstr(SystemError, "builtin module missing"); + } + else { + m = load_module(name); + } + } + return m; +} + +object * +reload_module(m) + object *m; +{ + if (m == NULL || !is_moduleobject(m)) { + err_setstr(TypeError, "reload() argument must be module"); + return NULL; + } + /* XXX Ought to check for builtin modules -- can't reload these... */ + return get_module(m, getmodulename(m), (object **)NULL); +} + +static void +cleardict(d) + object *d; +{ + int i; + for (i = getdictsize(d); --i >= 0; ) { + char *k; + k = getdictkey(d, i); + if (k != NULL) + (void) dictremove(d, k); + } +} + +void +doneimport() +{ + if (modules != NULL) { + int i; + /* Explicitly erase all modules; this is the safest way + to get rid of at least *some* circular dependencies */ + for (i = getdictsize(modules); --i >= 0; ) { + char *k; + k = getdictkey(modules, i); + if (k != NULL) { + object *m; + m = dictlookup(modules, k); + if (m != NULL && is_moduleobject(m)) { + object *d; + d = getmoduledict(m); + if (d != NULL && is_dictobject(d)) { + cleardict(d); + } + } + } + } + cleardict(modules); + } + DECREF(modules); +} + + +/* Initialize built-in modules when first imported */ + +extern struct { + char *name; + void (*initfunc)(); +} inittab[]; + +static int +init_builtin(name) + char *name; +{ + int i; + for (i = 0; inittab[i].name != NULL; i++) { + if (strcmp(name, inittab[i].name) == 0) { + (*inittab[i].initfunc)(); + return 1; + } + } + return 0; +} diff --git a/src/import.h b/src/import.h new file mode 100644 index 0000000..0923395 --- /dev/null +++ b/src/import.h @@ -0,0 +1,31 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Module definition and import interface */ + +object *get_modules PROTO((void)); +object *add_module PROTO((char *name)); +object *import_module PROTO((char *name)); +object *reload_module PROTO((object *m)); +void doneimport PROTO((void)); diff --git a/src/intobject.c b/src/intobject.c new file mode 100644 index 0000000..dba9cc6 --- /dev/null +++ b/src/intobject.c @@ -0,0 +1,307 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Integer object implementation */ + +#include "allobjects.h" + +/* Standard Booleans */ + +intobject FalseObject = { + OB_HEAD_INIT(&Inttype) + 0 +}; + +intobject TrueObject = { + OB_HEAD_INIT(&Inttype) + 1 +}; + +static object * +err_ovf() +{ + err_setstr(OverflowError, "integer overflow"); + return NULL; +} + +static object * +err_zdiv() +{ + err_setstr(ZeroDivisionError, "integer division by zero"); + return NULL; +} + +/* Integers are quite normal objects, to make object handling uniform. + (Using odd pointers to represent integers would save much space + but require extra checks for this special case throughout the code.) + Since, a typical Python program spends much of its time allocating + and deallocating integers, these operations should be very fast. + Therefore we use a dedicated allocation scheme with a much lower + overhead (in space and time) than straight malloc(): a simple + dedicated free list, filled when necessary with memory from malloc(). +*/ + +#define BLOCK_SIZE 1000 /* 1K less typical malloc overhead */ +#define N_INTOBJECTS (BLOCK_SIZE / sizeof(intobject)) + +static intobject * +fill_free_list() +{ + intobject *p, *q; + p = NEW(intobject, N_INTOBJECTS); + if (p == NULL) + return (intobject *)err_nomem(); + q = p + N_INTOBJECTS; + while (--q > p) + *(intobject **)q = q-1; + *(intobject **)q = NULL; + return p + N_INTOBJECTS - 1; +} + +static intobject *free_list = NULL; + +object * +newintobject(ival) + long ival; +{ + register intobject *v; + if (free_list == NULL) { + if ((free_list = fill_free_list()) == NULL) + return NULL; + } + v = free_list; + free_list = *(intobject **)free_list; + NEWREF(v); + v->ob_type = &Inttype; + v->ob_ival = ival; + return (object *) v; +} + +static void +int_dealloc(v) + intobject *v; +{ + *(intobject **)v = free_list; + free_list = v; +} + +long +getintvalue(op) + register object *op; +{ + if (!is_intobject(op)) { + err_badcall(); + return -1; + } + else + return ((intobject *)op) -> ob_ival; +} + +/* Methods */ + +static void +int_print(v, fp, flags) + intobject *v; + FILE *fp; + int flags; +{ + fprintf(fp, "%ld", v->ob_ival); +} + +static object * +int_repr(v) + intobject *v; +{ + char buf[20]; + sprintf(buf, "%ld", v->ob_ival); + return newstringobject(buf); +} + +static int +int_compare(v, w) + intobject *v, *w; +{ + register long i = v->ob_ival; + register long j = w->ob_ival; + return (i < j) ? -1 : (i > j) ? 1 : 0; +} + +static object * +int_add(v, w) + intobject *v; + register object *w; +{ + register long a, b, x; + if (!is_intobject(w)) { + err_badarg(); + return NULL; + } + a = v->ob_ival; + b = ((intobject *)w) -> ob_ival; + x = a + b; + if ((x^a) < 0 && (x^b) < 0) + return err_ovf(); + return newintobject(x); +} + +static object * +int_sub(v, w) + intobject *v; + register object *w; +{ + register long a, b, x; + if (!is_intobject(w)) { + err_badarg(); + return NULL; + } + a = v->ob_ival; + b = ((intobject *)w) -> ob_ival; + x = a - b; + if ((x^a) < 0 && (x^~b) < 0) + return err_ovf(); + return newintobject(x); +} + +static object * +int_mul(v, w) + intobject *v; + register object *w; +{ + register long a, b; + double x; + if (!is_intobject(w)) { + err_badarg(); + return NULL; + } + a = v->ob_ival; + b = ((intobject *)w) -> ob_ival; + x = (double)a * (double)b; + if (x > 0x7fffffff || x < (double) (long) 0x80000000) + return err_ovf(); + return newintobject(a * b); +} + +static object * +int_div(v, w) + intobject *v; + register object *w; +{ + if (!is_intobject(w)) { + err_badarg(); + return NULL; + } + if (((intobject *)w) -> ob_ival == 0) + return err_zdiv(); + return newintobject(v->ob_ival / ((intobject *)w) -> ob_ival); +} + +static object * +int_rem(v, w) + intobject *v; + register object *w; +{ + if (!is_intobject(w)) { + err_badarg(); + return NULL; + } + if (((intobject *)w) -> ob_ival == 0) + return err_zdiv(); + return newintobject(v->ob_ival % ((intobject *)w) -> ob_ival); +} + +static object * +int_pow(v, w) + intobject *v; + register object *w; +{ + register long iv, iw, ix; + register int neg; + if (!is_intobject(w)) { + err_badarg(); + return NULL; + } + iv = v->ob_ival; + iw = ((intobject *)w)->ob_ival; + neg = 0; + if (iw < 0) + neg = 1, iw = -iw; + ix = 1; + for (; iw > 0; iw--) + ix = ix * iv; + if (neg) { + if (ix == 0) + return err_zdiv(); + ix = 1/ix; + } + /* XXX How to check for overflow? */ + return newintobject(ix); +} + +static object * +int_neg(v) + intobject *v; +{ + register long a, x; + a = v->ob_ival; + x = -a; + if (a < 0 && x < 0) + return err_ovf(); + return newintobject(x); +} + +static object * +int_pos(v) + intobject *v; +{ + INCREF(v); + return (object *)v; +} + +static number_methods int_as_number = { + int_add, /*tp_add*/ + int_sub, /*tp_subtract*/ + int_mul, /*tp_multiply*/ + int_div, /*tp_divide*/ + int_rem, /*tp_remainder*/ + int_pow, /*tp_power*/ + int_neg, /*tp_negate*/ + int_pos, /*tp_plus*/ +}; + +typeobject Inttype = { + OB_HEAD_INIT(&Typetype) + 0, + "int", + sizeof(intobject), + 0, + int_dealloc, /*tp_dealloc*/ + int_print, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + int_compare, /*tp_compare*/ + int_repr, /*tp_repr*/ + &int_as_number, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; diff --git a/src/intobject.h b/src/intobject.h new file mode 100644 index 0000000..8a5330d --- /dev/null +++ b/src/intobject.h @@ -0,0 +1,72 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Integer object interface */ + +/* +123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 + +intobject represents a (long) integer. This is an immutable object; +an integer cannot change its value after creation. + +There are functions to create new integer objects, to test an object +for integer-ness, and to get the integer value. The latter functions +returns -1 and sets errno to EBADF if the object is not an intobject. +None of the functions should be applied to nil objects. + +The type intobject is (unfortunately) exposed bere so we can declare +TrueObject and FalseObject below; don't use this. +*/ + +typedef struct { + OB_HEAD + long ob_ival; +} intobject; + +extern typeobject Inttype; + +#define is_intobject(op) ((op)->ob_type == &Inttype) + +extern object *newintobject PROTO((long)); +extern long getintvalue PROTO((object *)); + + +/* +123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 + +False and True are special intobjects used by Boolean expressions. +All values of type Boolean must point to either of these; but in +contexts where integers are required they are integers (valued 0 and 1). +Hope these macros don't conflict with other people's. + +Don't forget to apply INCREF() when returning True or False!!! +*/ + +extern intobject FalseObject, TrueObject; /* Don't use these directly */ + +#define False ((object *) &FalseObject) +#define True ((object *) &TrueObject) + +/* Macro, trading safety for speed */ +#define GETINTVALUE(op) ((op)->ob_ival) diff --git a/src/intrcheck.c b/src/intrcheck.c new file mode 100644 index 0000000..8e2fb5b --- /dev/null +++ b/src/intrcheck.c @@ -0,0 +1,144 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Check for interrupts */ + +#ifdef MSDOS + +/* This might work for MS-DOS (untested though): */ + +void +initintr() +{ +} + +int +intrcheck() +{ + int interrupted = 0; + while (kbhit()) { + if (getch() == '\003') + interrupted = 1; + } + return interrupted; +} + +#define OK + +#endif + + +#ifdef THINK_C + +/* This is for THINK C 4.0. + For 3.0, you may have to remove the signal stuff. */ + +#include <MacHeaders> +#include <signal.h> +#include "sigtype.h" + +static int interrupted; + +static SIGTYPE +intcatcher(sig) + int sig; +{ + interrupted = 1; + signal(SIGINT, intcatcher); +} + +void +initintr() +{ + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + signal(SIGINT, intcatcher); +} + +int +intrcheck() +{ + register EvQElPtr q; + + /* This is like THINK C 4.0's <console.h>. + I'm not sure why FlushEvents must be called from asm{}. */ + for (q = (EvQElPtr)EventQueue.qHead; q; q = (EvQElPtr)q->qLink) { + if (q->evtQWhat == keyDown && + (char)q->evtQMessage == '.' && + (q->evtQModifiers & cmdKey) != 0) { + + asm { + moveq #keyDownMask,d0 + _FlushEvents + } + interrupted = 1; + break; + } + } + if (interrupted) { + interrupted = 0; + return 1; + } + return 0; +} + +#define OK + +#endif /* THINK_C */ + + +#ifndef OK + +/* Default version -- for real operating systems and for Standard C */ + +#include <stdio.h> +#include <signal.h> +#include "sigtype.h" + +static int interrupted; + +static SIGTYPE +intcatcher(sig) + int sig; +{ + interrupted = 1; + signal(SIGINT, intcatcher); +} + +void +initintr() +{ + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + signal(SIGINT, intcatcher); +} + +int +intrcheck() +{ + if (!interrupted) + return 0; + interrupted = 0; + return 1; +} + +#endif /* !OK */ diff --git a/src/listnode.c b/src/listnode.c new file mode 100644 index 0000000..333d01f --- /dev/null +++ b/src/listnode.c @@ -0,0 +1,93 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* List a node on a file */ + +#include "pgenheaders.h" +#include "token.h" +#include "node.h" + +/* Forward */ +static void list1node PROTO((FILE *, node *)); + +void +listtree(n) + node *n; +{ + listnode(stdout, n); +} + +static int level, atbol; + +void +listnode(fp, n) + FILE *fp; + node *n; +{ + level = 0; + atbol = 1; + list1node(fp, n); +} + +static void +list1node(fp, n) + FILE *fp; + node *n; +{ + if (n == 0) + return; + if (ISNONTERMINAL(TYPE(n))) { + int i; + for (i = 0; i < NCH(n); i++) + list1node(fp, CHILD(n, i)); + } + else if (ISTERMINAL(TYPE(n))) { + switch (TYPE(n)) { + case INDENT: + ++level; + break; + case DEDENT: + --level; + break; + default: + if (atbol) { + int i; + for (i = 0; i < level; ++i) + fprintf(fp, "\t"); + atbol = 0; + } + if (TYPE(n) == NEWLINE) { + if (STR(n) != NULL) + fprintf(fp, "%s", STR(n)); + fprintf(fp, "\n"); + atbol = 1; + } + else + fprintf(fp, "%s ", STR(n)); + break; + } + } + else + fprintf(fp, "? "); +} diff --git a/src/listobject.c b/src/listobject.c new file mode 100644 index 0000000..be1382c --- /dev/null +++ b/src/listobject.c @@ -0,0 +1,519 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* List object implementation */ + +#include "allobjects.h" + +object * +newlistobject(size) + int size; +{ + int i; + listobject *op; + if (size < 0) { + err_badcall(); + return NULL; + } + op = (listobject *) malloc(sizeof(listobject)); + if (op == NULL) { + return err_nomem(); + } + if (size <= 0) { + op->ob_item = NULL; + } + else { + op->ob_item = (object **) malloc(size * sizeof(object *)); + if (op->ob_item == NULL) { + free((ANY *)op); + return err_nomem(); + } + } + NEWREF(op); + op->ob_type = &Listtype; + op->ob_size = size; + for (i = 0; i < size; i++) + op->ob_item[i] = NULL; + return (object *) op; +} + +int +getlistsize(op) + object *op; +{ + if (!is_listobject(op)) { + err_badcall(); + return -1; + } + else + return ((listobject *)op) -> ob_size; +} + +object * +getlistitem(op, i) + object *op; + int i; +{ + if (!is_listobject(op)) { + err_badcall(); + return NULL; + } + if (i < 0 || i >= ((listobject *)op) -> ob_size) { + err_setstr(IndexError, "list index out of range"); + return NULL; + } + return ((listobject *)op) -> ob_item[i]; +} + +int +setlistitem(op, i, newitem) + register object *op; + register int i; + register object *newitem; +{ + register object *olditem; + if (!is_listobject(op)) { + if (newitem != NULL) + DECREF(newitem); + err_badcall(); + return -1; + } + if (i < 0 || i >= ((listobject *)op) -> ob_size) { + if (newitem != NULL) + DECREF(newitem); + err_setstr(IndexError, "list assignment index out of range"); + return -1; + } + olditem = ((listobject *)op) -> ob_item[i]; + ((listobject *)op) -> ob_item[i] = newitem; + if (olditem != NULL) + DECREF(olditem); + return 0; +} + +static int +ins1(self, where, v) + listobject *self; + int where; + object *v; +{ + int i; + object **items; + if (v == NULL) { + err_badcall(); + return -1; + } + items = self->ob_item; + RESIZE(items, object *, self->ob_size+1); + if (items == NULL) { + err_nomem(); + return -1; + } + if (where < 0) + where = 0; + if (where > self->ob_size) + where = self->ob_size; + for (i = self->ob_size; --i >= where; ) + items[i+1] = items[i]; + INCREF(v); + items[where] = v; + self->ob_item = items; + self->ob_size++; + return 0; +} + +int +inslistitem(op, where, newitem) + object *op; + int where; + object *newitem; +{ + if (!is_listobject(op)) { + err_badcall(); + return -1; + } + return ins1((listobject *)op, where, newitem); +} + +int +addlistitem(op, newitem) + object *op; + object *newitem; +{ + if (!is_listobject(op)) { + err_badcall(); + return -1; + } + return ins1((listobject *)op, + (int) ((listobject *)op)->ob_size, newitem); +} + +/* Methods */ + +static void +list_dealloc(op) + listobject *op; +{ + int i; + for (i = 0; i < op->ob_size; i++) { + if (op->ob_item[i] != NULL) + DECREF(op->ob_item[i]); + } + if (op->ob_item != NULL) + free((ANY *)op->ob_item); + free((ANY *)op); +} + +static void +list_print(op, fp, flags) + listobject *op; + FILE *fp; + int flags; +{ + int i; + fprintf(fp, "["); + for (i = 0; i < op->ob_size && !StopPrint; i++) { + if (i > 0) { + fprintf(fp, ", "); + } + printobject(op->ob_item[i], fp, flags); + } + fprintf(fp, "]"); +} + +object * +list_repr(v) + listobject *v; +{ + object *s, *t, *comma; + int i; + s = newstringobject("["); + comma = newstringobject(", "); + for (i = 0; i < v->ob_size && s != NULL; i++) { + if (i > 0) + joinstring(&s, comma); + t = reprobject(v->ob_item[i]); + joinstring(&s, t); + DECREF(t); + } + DECREF(comma); + t = newstringobject("]"); + joinstring(&s, t); + DECREF(t); + return s; +} + +static int +list_compare(v, w) + listobject *v, *w; +{ + int len = (v->ob_size < w->ob_size) ? v->ob_size : w->ob_size; + int i; + for (i = 0; i < len; i++) { + int cmp = cmpobject(v->ob_item[i], w->ob_item[i]); + if (cmp != 0) + return cmp; + } + return v->ob_size - w->ob_size; +} + +static int +list_length(a) + listobject *a; +{ + return a->ob_size; +} + +static object * +list_item(a, i) + listobject *a; + int i; +{ + if (i < 0 || i >= a->ob_size) { + err_setstr(IndexError, "list index out of range"); + return NULL; + } + INCREF(a->ob_item[i]); + return a->ob_item[i]; +} + +static object * +list_slice(a, ilow, ihigh) + listobject *a; + int ilow, ihigh; +{ + listobject *np; + int i; + if (ilow < 0) + ilow = 0; + else if (ilow > a->ob_size) + ilow = a->ob_size; + if (ihigh < 0) + ihigh = 0; + if (ihigh < ilow) + ihigh = ilow; + else if (ihigh > a->ob_size) + ihigh = a->ob_size; + np = (listobject *) newlistobject(ihigh - ilow); + if (np == NULL) + return NULL; + for (i = ilow; i < ihigh; i++) { + object *v = a->ob_item[i]; + INCREF(v); + np->ob_item[i - ilow] = v; + } + return (object *)np; +} + +static object * +list_concat(a, bb) + listobject *a; + object *bb; +{ + int size; + int i; + listobject *np; + if (!is_listobject(bb)) { + err_badarg(); + return NULL; + } +#define b ((listobject *)bb) + size = a->ob_size + b->ob_size; + np = (listobject *) newlistobject(size); + if (np == NULL) { + return err_nomem(); + } + for (i = 0; i < a->ob_size; i++) { + object *v = a->ob_item[i]; + INCREF(v); + np->ob_item[i] = v; + } + for (i = 0; i < b->ob_size; i++) { + object *v = b->ob_item[i]; + INCREF(v); + np->ob_item[i + a->ob_size] = v; + } + return (object *)np; +#undef b +} + +static int +list_ass_item(a, i, v) + listobject *a; + int i; + object *v; +{ + if (i < 0 || i >= a->ob_size) { + err_setstr(IndexError, "list assignment index out of range"); + return -1; + } + if (v == NULL) + return list_ass_slice(a, i, i+1, v); + INCREF(v); + DECREF(a->ob_item[i]); + a->ob_item[i] = v; + return 0; +} + +static int +list_ass_slice(a, ilow, ihigh, v) + listobject *a; + int ilow, ihigh; + object *v; +{ + object **item; + int n; /* Size of replacement list */ + int d; /* Change in size */ + int k; /* Loop index */ +#define b ((listobject *)v) + if (v == NULL) + n = 0; + else if (is_listobject(v)) + n = b->ob_size; + else { + err_badarg(); + return -1; + } + if (ilow < 0) + ilow = 0; + else if (ilow > a->ob_size) + ilow = a->ob_size; + if (ihigh < 0) + ihigh = 0; + if (ihigh < ilow) + ihigh = ilow; + else if (ihigh > a->ob_size) + ihigh = a->ob_size; + item = a->ob_item; + d = n - (ihigh-ilow); + if (d <= 0) { /* Delete -d items; DECREF ihigh-ilow items */ + for (k = ilow; k < ihigh; k++) + DECREF(item[k]); + if (d < 0) { + for (/*k = ihigh*/; k < a->ob_size; k++) + item[k+d] = item[k]; + a->ob_size += d; + RESIZE(item, object *, a->ob_size); /* Can't fail */ + a->ob_item = item; + } + } + else { /* Insert d items; DECREF ihigh-ilow items */ + RESIZE(item, object *, a->ob_size + d); + if (item == NULL) { + err_nomem(); + return -1; + } + for (k = a->ob_size; --k >= ihigh; ) + item[k+d] = item[k]; + for (/*k = ihigh-1*/; k >= ilow; --k) + DECREF(item[k]); + a->ob_item = item; + a->ob_size += d; + } + for (k = 0; k < n; k++, ilow++) { + object *w = b->ob_item[k]; + INCREF(w); + item[ilow] = w; + } + return 0; +#undef b +} + +static object * +ins(self, where, v) + listobject *self; + int where; + object *v; +{ + if (ins1(self, where, v) != 0) + return NULL; + INCREF(None); + return None; +} + +static object * +listinsert(self, args) + listobject *self; + object *args; +{ + int i; + if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2) { + err_badarg(); + return NULL; + } + if (!getintarg(gettupleitem(args, 0), &i)) + return NULL; + return ins(self, i, gettupleitem(args, 1)); +} + +static object * +listappend(self, args) + listobject *self; + object *args; +{ + return ins(self, (int) self->ob_size, args); +} + +static int +cmp(v, w) + char *v, *w; +{ + return cmpobject(* (object **) v, * (object **) w); +} + +static object * +listsort(self, args) + listobject *self; + object *args; +{ + if (args != NULL) { + err_badarg(); + return NULL; + } + err_clear(); + if (self->ob_size > 1) + qsort((char *)self->ob_item, + (int) self->ob_size, sizeof(object *), cmp); + if (err_occurred()) + return NULL; + INCREF(None); + return None; +} + +int +sortlist(v) + object *v; +{ + if (v == NULL || !is_listobject(v)) { + err_badcall(); + return -1; + } + v = listsort((listobject *)v, (object *)NULL); + if (v == NULL) + return -1; + DECREF(v); + return 0; +} + +static struct methodlist list_methods[] = { + {"append", listappend}, + {"insert", listinsert}, + {"sort", listsort}, + {NULL, NULL} /* sentinel */ +}; + +static object * +list_getattr(f, name) + listobject *f; + char *name; +{ + return findmethod(list_methods, (object *)f, name); +} + +static sequence_methods list_as_sequence = { + list_length, /*sq_length*/ + list_concat, /*sq_concat*/ + 0, /*sq_repeat*/ + list_item, /*sq_item*/ + list_slice, /*sq_slice*/ + list_ass_item, /*sq_ass_item*/ + list_ass_slice, /*sq_ass_slice*/ +}; + +typeobject Listtype = { + OB_HEAD_INIT(&Typetype) + 0, + "list", + sizeof(listobject), + 0, + list_dealloc, /*tp_dealloc*/ + list_print, /*tp_print*/ + list_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + list_compare, /*tp_compare*/ + list_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + &list_as_sequence, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; diff --git a/src/listobject.h b/src/listobject.h new file mode 100644 index 0000000..103ceb6 --- /dev/null +++ b/src/listobject.h @@ -0,0 +1,59 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* List object interface */ + +/* +123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 + +Another generally useful object type is an list of object pointers. +This is a mutable type: the list items can be changed, and items can be +added or removed. Out-of-range indices or non-list objects are ignored. + +*** WARNING *** setlistitem does not increment the new item's reference +count, but does decrement the reference count of the item it replaces, +if not nil. It does *decrement* the reference count if it is *not* +inserted in the list. Similarly, getlistitem does not increment the +returned item's reference count. +*/ + +typedef struct { + OB_VARHEAD + object **ob_item; +} listobject; + +extern typeobject Listtype; + +#define is_listobject(op) ((op)->ob_type == &Listtype) + +extern object *newlistobject PROTO((int size)); +extern int getlistsize PROTO((object *)); +extern object *getlistitem PROTO((object *, int)); +extern int setlistitem PROTO((object *, int, object *)); +extern int inslistitem PROTO((object *, int, object *)); +extern int addlistitem PROTO((object *, object *)); +extern int sortlist PROTO((object *)); + +/* Macro, trading safety for speed */ +#define GETLISTITEM(op, i) ((op)->ob_item[i]) diff --git a/src/macmodule.c b/src/macmodule.c new file mode 100644 index 0000000..4f20914 --- /dev/null +++ b/src/macmodule.c @@ -0,0 +1,246 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Macintosh OS module implementation */ + +#include "allobjects.h" + +#include "import.h" +#include "modsupport.h" + +#include "sigtype.h" + +#include "::unixemu:dir.h" +#include "::unixemu:stat.h" + +static object *MacError; /* Exception */ + + +static object * +mac_chdir(self, args) + object *self; + object *args; +{ + object *path; + if (!getstrarg(args, &path)) + return NULL; + if (chdir(getstringvalue(path)) != 0) + return err_errno(MacError); + INCREF(None); + return None; +} + + +static object * +mac_getcwd(self, args) + object *self; + object *args; +{ + extern char *getwd(); + char buf[1025]; + if (!getnoarg(args)) + return NULL; + strcpy(buf, "mac.getcwd() failed"); /* In case getwd() doesn't set a msg */ + if (getwd(buf) == NULL) { + err_setstr(MacError, buf); + return NULL; + } + return newstringobject(buf); +} + + +static object * +mac_listdir(self, args) + object *self; + object *args; +{ + object *name, *d, *v; + DIR *dirp; + struct direct *ep; + if (!getstrarg(args, &name)) + return NULL; + if ((dirp = opendir(getstringvalue(name))) == NULL) + return err_errno(MacError); + if ((d = newlistobject(0)) == NULL) { + closedir(dirp); + return NULL; + } + while ((ep = readdir(dirp)) != NULL) { + v = newstringobject(ep->d_name); + if (v == NULL) { + DECREF(d); + d = NULL; + break; + } + if (addlistitem(d, v) != 0) { + DECREF(v); + DECREF(d); + d = NULL; + break; + } + DECREF(v); + } + closedir(dirp); + return d; +} + + +static object * +mac_mkdir(self, args) + object *self; + object *args; +{ + object *path; + int mode; + if (!getstrintarg(args, &path, &mode)) + return NULL; + if (mkdir(getstringvalue(path), mode) != 0) + return err_errno(MacError); + INCREF(None); + return None; +} + + +static object * +mac_rename(self, args) + object *self; + object *args; +{ + object *src, *dst; + if (!getstrstrarg(args, &src, &dst)) + return NULL; + if (rename(getstringvalue(src), getstringvalue(dst)) != 0) + return err_errno(MacError); + INCREF(None); + return None; +} + + +static object * +mac_rmdir(self, args) + object *self; + object *args; +{ + object *path; + if (!getstrarg(args, &path)) + return NULL; + if (rmdir(getstringvalue(path)) != 0) + return err_errno(MacError); + INCREF(None); + return None; +} + + +static object * +mac_stat(self, args) + object *self; + object *args; +{ + struct stat st; + object *path; + object *v; + if (!getstrarg(args, &path)) + return NULL; + if (stat(getstringvalue(path), &st) != 0) + return err_errno(MacError); + v = newtupleobject(11); + if (v == NULL) + return NULL; +#define SET(i, val) settupleitem(v, i, newintobject((long)(val))) +#define XXX(i, val) SET(i, 0) /* For values my Mac stat doesn't support */ + SET(0, st.st_mode); + XXX(1, st.st_ino); + XXX(2, st.st_dev); + XXX(3, st.st_nlink); + XXX(4, st.st_uid); + XXX(5, st.st_gid); + SET(6, st.st_size); + XXX(7, st.st_atime); + SET(8, st.st_mtime); + XXX(9, st.st_ctime); + SET(10, st.st_rsize); /* Mac-specific: resource size */ +#undef SET + if (err_occurred()) { + DECREF(v); + return NULL; + } + return v; +} + + +static object * +mac_sync(self, args) + object *self; + object *args; +{ + if (!getnoarg(args)) + return NULL; + sync(); + INCREF(None); + return None; +} + + +static object * +mac_unlink(self, args) + object *self; + object *args; +{ + object *path; + if (!getstrarg(args, &path)) + return NULL; + if (unlink(getstringvalue(path)) != 0) + return err_errno(MacError); + INCREF(None); + return None; +} + + +static struct methodlist mac_methods[] = { + {"chdir", mac_chdir}, + {"getcwd", mac_getcwd}, + {"listdir", mac_listdir}, + {"mkdir", mac_mkdir}, + {"rename", mac_rename}, + {"rmdir", mac_rmdir}, + {"stat", mac_stat}, + {"sync", mac_sync}, + {"unlink", mac_unlink}, + {NULL, NULL} /* Sentinel */ +}; + + +void +initmac() +{ + object *m, *d; + + m = initmodule("mac", mac_methods); + d = getmoduledict(m); + + /* Initialize mac.error exception */ + MacError = newstringobject("mac.error"); + if (MacError == NULL || dictinsert(d, "error", MacError) != 0) + fatal("can't define mac.error"); +} diff --git a/src/malloc.h b/src/malloc.h new file mode 100644 index 0000000..c2d9969 --- /dev/null +++ b/src/malloc.h @@ -0,0 +1,63 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Lowest-level memory allocation interface */ + +#ifdef THINK_C +#define ANY void +#ifndef THINK_C_3_0 +#define HAVE_STDLIB +#endif +#endif + +#ifdef __STD_C__ +#define ANY void +#define HAVE_STDLIB +#endif + +#ifndef ANY +#define ANY char +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#define NEW(type, n) ( (type *) malloc((n) * sizeof(type)) ) +#define RESIZE(p, type, n) \ + if ((p) == NULL) \ + (p) = (type *) malloc((n) * sizeof(type)); \ + else \ + (p) = (type *) realloc((char *)(p), (n) * sizeof(type)) +#define DEL(p) free((char *)p) +#define XDEL(p) if ((p) == NULL) ; else DEL(p) + +#ifdef HAVE_STDLIB +#include <stdlib.h> +#else +extern ANY *malloc PROTO((unsigned int)); +extern ANY *calloc PROTO((unsigned int, unsigned int)); +extern ANY *realloc PROTO((ANY *, unsigned int)); +extern void free PROTO((ANY *)); /* XXX sometimes int on Unix old systems */ +#endif diff --git a/src/mathmodule.c b/src/mathmodule.c new file mode 100644 index 0000000..3fa8d03 --- /dev/null +++ b/src/mathmodule.c @@ -0,0 +1,180 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Math module -- standard C math library functions, pi and e */ + +#include "allobjects.h" + +#include <errno.h> +#ifndef errno +extern int errno; +#endif + +#include "modsupport.h" + +#include <math.h> + +static int +getdoublearg(args, px) + register object *args; + double *px; +{ + if (args == NULL) + return err_badarg(); + if (is_floatobject(args)) { + *px = getfloatvalue(args); + return 1; + } + if (is_intobject(args)) { + *px = getintvalue(args); + return 1; + } + return err_badarg(); +} + +static int +get2doublearg(args, px, py) + register object *args; + double *px, *py; +{ + if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2) + return err_badarg(); + return getdoublearg(gettupleitem(args, 0), px) && + getdoublearg(gettupleitem(args, 1), py); +} + +static object * +math_1(args, func) + object *args; + double (*func) FPROTO((double)); +{ + double x; + if (!getdoublearg(args, &x)) + return NULL; + errno = 0; + x = (*func)(x); + if (errno != 0) + return NULL; + else + return newfloatobject(x); +} + +static object * +math_2(args, func) + object *args; + double (*func) FPROTO((double, double)); +{ + double x, y; + if (!get2doublearg(args, &x, &y)) + return NULL; + errno = 0; + x = (*func)(x, y); + if (errno != 0) + return NULL; + else + return newfloatobject(x); +} + +#define FUNC1(stubname, func) \ + static object * stubname(self, args) object *self, *args; { \ + return math_1(args, func); \ + } + +#define FUNC2(stubname, func) \ + static object * stubname(self, args) object *self, *args; { \ + return math_2(args, func); \ + } + +FUNC1(math_acos, acos) +FUNC1(math_asin, asin) +FUNC1(math_atan, atan) +FUNC2(math_atan2, atan2) +FUNC1(math_ceil, ceil) +FUNC1(math_cos, cos) +FUNC1(math_cosh, cosh) +FUNC1(math_exp, exp) +FUNC1(math_fabs, fabs) +FUNC1(math_floor, floor) +#if 0 +/* XXX This one is not in the Amoeba library yet, so what the heck... */ +FUNC2(math_fmod, fmod) +#endif +FUNC1(math_log, log) +FUNC1(math_log10, log10) +FUNC2(math_pow, pow) +FUNC1(math_sin, sin) +FUNC1(math_sinh, sinh) +FUNC1(math_sqrt, sqrt) +FUNC1(math_tan, tan) +FUNC1(math_tanh, tanh) + +#if 0 +/* What about these? */ +double frexp(double x, int *i); +double ldexp(double x, int n); +double modf(double x, double *i); +#endif + +static struct methodlist math_methods[] = { + {"acos", math_acos}, + {"asin", math_asin}, + {"atan", math_atan}, + {"atan2", math_atan2}, + {"ceil", math_ceil}, + {"cos", math_cos}, + {"cosh", math_cosh}, + {"exp", math_exp}, + {"fabs", math_fabs}, + {"floor", math_floor}, +#if 0 + {"fmod", math_fmod}, + {"frexp", math_freqp}, + {"ldexp", math_ldexp}, +#endif + {"log", math_log}, + {"log10", math_log10}, +#if 0 + {"modf", math_modf}, +#endif + {"pow", math_pow}, + {"sin", math_sin}, + {"sinh", math_sinh}, + {"sqrt", math_sqrt}, + {"tan", math_tan}, + {"tanh", math_tanh}, + {NULL, NULL} /* sentinel */ +}; + +void +initmath() +{ + object *m, *d, *v; + + m = initmodule("math", math_methods); + d = getmoduledict(m); + dictinsert(d, "pi", v = newfloatobject(atan(1.0) * 4.0)); + DECREF(v); + dictinsert(d, "e", v = newfloatobject(exp(1.0))); + DECREF(v); +} diff --git a/src/metagrammar.c b/src/metagrammar.c new file mode 100644 index 0000000..57d47cb --- /dev/null +++ b/src/metagrammar.c @@ -0,0 +1,176 @@ +/*********************************************************** +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. + +******************************************************************/ + +#include "pgenheaders.h" +#include "metagrammar.h" +#include "grammar.h" +#include "pgen.h" +static arc arcs_0_0[3] = { + {2, 0}, + {3, 0}, + {4, 1}, +}; +static arc arcs_0_1[1] = { + {0, 1}, +}; +static state states_0[2] = { + {3, arcs_0_0}, + {1, arcs_0_1}, +}; +static arc arcs_1_0[1] = { + {5, 1}, +}; +static arc arcs_1_1[1] = { + {6, 2}, +}; +static arc arcs_1_2[1] = { + {7, 3}, +}; +static arc arcs_1_3[1] = { + {3, 4}, +}; +static arc arcs_1_4[1] = { + {0, 4}, +}; +static state states_1[5] = { + {1, arcs_1_0}, + {1, arcs_1_1}, + {1, arcs_1_2}, + {1, arcs_1_3}, + {1, arcs_1_4}, +}; +static arc arcs_2_0[1] = { + {8, 1}, +}; +static arc arcs_2_1[2] = { + {9, 0}, + {0, 1}, +}; +static state states_2[2] = { + {1, arcs_2_0}, + {2, arcs_2_1}, +}; +static arc arcs_3_0[1] = { + {10, 1}, +}; +static arc arcs_3_1[2] = { + {10, 1}, + {0, 1}, +}; +static state states_3[2] = { + {1, arcs_3_0}, + {2, arcs_3_1}, +}; +static arc arcs_4_0[2] = { + {11, 1}, + {13, 2}, +}; +static arc arcs_4_1[1] = { + {7, 3}, +}; +static arc arcs_4_2[3] = { + {14, 4}, + {15, 4}, + {0, 2}, +}; +static arc arcs_4_3[1] = { + {12, 4}, +}; +static arc arcs_4_4[1] = { + {0, 4}, +}; +static state states_4[5] = { + {2, arcs_4_0}, + {1, arcs_4_1}, + {3, arcs_4_2}, + {1, arcs_4_3}, + {1, arcs_4_4}, +}; +static arc arcs_5_0[3] = { + {5, 1}, + {16, 1}, + {17, 2}, +}; +static arc arcs_5_1[1] = { + {0, 1}, +}; +static arc arcs_5_2[1] = { + {7, 3}, +}; +static arc arcs_5_3[1] = { + {18, 1}, +}; +static state states_5[4] = { + {3, arcs_5_0}, + {1, arcs_5_1}, + {1, arcs_5_2}, + {1, arcs_5_3}, +}; +static dfa dfas[6] = { + {256, "MSTART", 0, 2, states_0, + "\070\000\000"}, + {257, "RULE", 0, 5, states_1, + "\040\000\000"}, + {258, "RHS", 0, 2, states_2, + "\040\010\003"}, + {259, "ALT", 0, 2, states_3, + "\040\010\003"}, + {260, "ITEM", 0, 5, states_4, + "\040\010\003"}, + {261, "ATOM", 0, 4, states_5, + "\040\000\003"}, +}; +static label labels[19] = { + {0, "EMPTY"}, + {256, 0}, + {257, 0}, + {4, 0}, + {0, 0}, + {1, 0}, + {11, 0}, + {258, 0}, + {259, 0}, + {18, 0}, + {260, 0}, + {9, 0}, + {10, 0}, + {261, 0}, + {16, 0}, + {14, 0}, + {3, 0}, + {7, 0}, + {8, 0}, +}; +static grammar gram = { + 6, + dfas, + {19, labels}, + 256 +}; + +grammar * +meta_grammar() +{ + return &gram; +} diff --git a/src/metagrammar.h b/src/metagrammar.h new file mode 100644 index 0000000..a937b64 --- /dev/null +++ b/src/metagrammar.h @@ -0,0 +1,30 @@ +/*********************************************************** +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 MSTART 256 +#define RULE 257 +#define RHS 258 +#define ALT 259 +#define ITEM 260 +#define ATOM 261 diff --git a/src/methodobject.c b/src/methodobject.c new file mode 100644 index 0000000..68a0217 --- /dev/null +++ b/src/methodobject.c @@ -0,0 +1,147 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Method object implementation */ + +#include "allobjects.h" + +#include "token.h" + +typedef struct { + OB_HEAD + char *m_name; + method m_meth; + object *m_self; +} methodobject; + +object * +newmethodobject(name, meth, self) + char *name; /* static string */ + method meth; + object *self; +{ + methodobject *op = NEWOBJ(methodobject, &Methodtype); + if (op != NULL) { + op->m_name = name; + op->m_meth = meth; + if (self != NULL) + INCREF(self); + op->m_self = self; + } + return (object *)op; +} + +method +getmethod(op) + object *op; +{ + if (!is_methodobject(op)) { + err_badcall(); + return NULL; + } + return ((methodobject *)op) -> m_meth; +} + +object * +getself(op) + object *op; +{ + if (!is_methodobject(op)) { + err_badcall(); + return NULL; + } + return ((methodobject *)op) -> m_self; +} + +/* Methods (the standard built-in methods, that is) */ + +static void +meth_dealloc(m) + methodobject *m; +{ + if (m->m_self != NULL) + DECREF(m->m_self); + free((char *)m); +} + +static void +meth_print(m, fp, flags) + methodobject *m; + FILE *fp; + int flags; +{ + if (m->m_self == NULL) + fprintf(fp, "<built-in function '%s'>", m->m_name); + else + fprintf(fp, "<built-in method '%s' of some %s object>", + m->m_name, m->m_self->ob_type->tp_name); +} + +static object * +meth_repr(m) + methodobject *m; +{ + char buf[200]; + if (m->m_self == NULL) + sprintf(buf, "<built-in function '%.80s'>", m->m_name); + else + sprintf(buf, + "<built-in method '%.80s' of some %.80s object>", + m->m_name, m->m_self->ob_type->tp_name); + return newstringobject(buf); +} + +typeobject Methodtype = { + OB_HEAD_INIT(&Typetype) + 0, + "method", + sizeof(methodobject), + 0, + meth_dealloc, /*tp_dealloc*/ + meth_print, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + meth_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; + +/* Find a method in a module's method table. + Usually called from an object's getattr method. */ + +object * +findmethod(ml, op, name) + struct methodlist *ml; + object *op; + char *name; +{ + for (; ml->ml_name != NULL; ml++) { + if (strcmp(name, ml->ml_name) == 0) + return newmethodobject(ml->ml_name, ml->ml_meth, op); + } + err_setstr(NameError, name); + return NULL; +} diff --git a/src/methodobject.h b/src/methodobject.h new file mode 100644 index 0000000..674ed7d --- /dev/null +++ b/src/methodobject.h @@ -0,0 +1,42 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Method object interface */ + +extern typeobject Methodtype; + +#define is_methodobject(op) ((op)->ob_type == &Methodtype) + +typedef object *(*method) FPROTO((object *, object *)); + +extern object *newmethodobject PROTO((char *, method, object *)); +extern method getmethod PROTO((object *)); +extern object *getself PROTO((object *)); + +struct methodlist { + char *ml_name; + method ml_meth; +}; + +extern object *findmethod PROTO((struct methodlist *, object *, char *)); diff --git a/src/modsupport.c b/src/modsupport.c new file mode 100644 index 0000000..1044268 --- /dev/null +++ b/src/modsupport.c @@ -0,0 +1,381 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Module support implementation */ + +#include "allobjects.h" +#include "modsupport.h" +#include "import.h" + + +object * +initmodule(name, methods) + char *name; + struct methodlist *methods; +{ + object *m, *d, *v; + struct methodlist *ml; + char namebuf[256]; + if ((m = add_module(name)) == NULL) { + fprintf(stderr, "initializing module: %s\n", name); + fatal("can't create a module"); + } + d = getmoduledict(m); + for (ml = methods; ml->ml_name != NULL; ml++) { + sprintf(namebuf, "%s.%s", name, ml->ml_name); + v = newmethodobject(strdup(namebuf), ml->ml_meth, + (object *)NULL); + /* XXX The strdup'ed memory is never freed */ + if (v == NULL || dictinsert(d, ml->ml_name, v) != 0) { + fprintf(stderr, "initializing module: %s\n", name); + fatal("can't initialize module"); + } + DECREF(v); + } + return m; +} + + +/* Argument list handling tools. + All return 1 for success, or call err_set*() and return 0 for failure */ + +int +getnoarg(v) + object *v; +{ + if (v != NULL) { + return err_badarg(); + } + return 1; +} + +int +getintarg(v, a) + object *v; + int *a; +{ + if (v == NULL || !is_intobject(v)) { + return err_badarg(); + } + *a = getintvalue(v); + return 1; +} + +int +getintintarg(v, a, b) + object *v; + int *a; + int *b; +{ + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { + return err_badarg(); + } + return getintarg(gettupleitem(v, 0), a) && + getintarg(gettupleitem(v, 1), b); +} + +int +getlongarg(v, a) + object *v; + long *a; +{ + if (v == NULL || !is_intobject(v)) { + return err_badarg(); + } + *a = getintvalue(v); + return 1; +} + +int +getlonglongargs(v, a, b) + object *v; + long *a, *b; +{ + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { + return err_badarg(); + } + return getlongarg(gettupleitem(v, 0), a) && + getlongarg(gettupleitem(v, 1), b); +} + +int +getlonglongobjectargs(v, a, b, c) + object *v; + long *a, *b; + object **c; +{ + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 3) { + return err_badarg(); + } + if (getlongarg(gettupleitem(v, 0), a) && + getlongarg(gettupleitem(v, 1), b)) { + *c = gettupleitem(v, 2); + return 1; + } + else { + return err_badarg(); + } +} + +int +getstrarg(v, a) + object *v; + object **a; +{ + if (v == NULL || !is_stringobject(v)) { + return err_badarg(); + } + *a = v; + return 1; +} + +int +getstrstrarg(v, a, b) + object *v; + object **a; + object **b; +{ + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { + return err_badarg(); + } + return getstrarg(gettupleitem(v, 0), a) && + getstrarg(gettupleitem(v, 1), b); +} + +int +getstrstrintarg(v, a, b, c) + object *v; + object **a; + object **b; + int *c; +{ + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 3) { + return err_badarg(); + } + return getstrarg(gettupleitem(v, 0), a) && + getstrarg(gettupleitem(v, 1), b) && + getintarg(gettupleitem(v, 2), c); +} + +int +getstrintarg(v, a, b) + object *v; + object **a; + int *b; +{ + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { + return err_badarg(); + } + return getstrarg(gettupleitem(v, 0), a) && + getintarg(gettupleitem(v, 1), b); +} + +int +getintstrarg(v, a, b) + object *v; + int *a; + object **b; +{ + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { + return err_badarg(); + } + return getintarg(gettupleitem(v, 0), a) && + getstrarg(gettupleitem(v, 1), b); +} + +int +getpointarg(v, a) + object *v; + int *a; /* [2] */ +{ + return getintintarg(v, a, a+1); +} + +int +get3pointarg(v, a) + object *v; + int *a; /* [6] */ +{ + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 3) { + return err_badarg(); + } + return getpointarg(gettupleitem(v, 0), a) && + getpointarg(gettupleitem(v, 1), a+2) && + getpointarg(gettupleitem(v, 2), a+4); +} + +int +getrectarg(v, a) + object *v; + int *a; /* [2+2] */ +{ + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { + return err_badarg(); + } + return getpointarg(gettupleitem(v, 0), a) && + getpointarg(gettupleitem(v, 1), a+2); +} + +int +getrectintarg(v, a) + object *v; + int *a; /* [4+1] */ +{ + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { + return err_badarg(); + } + return getrectarg(gettupleitem(v, 0), a) && + getintarg(gettupleitem(v, 1), a+4); +} + +int +getpointintarg(v, a) + object *v; + int *a; /* [2+1] */ +{ + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { + return err_badarg(); + } + return getpointarg(gettupleitem(v, 0), a) && + getintarg(gettupleitem(v, 1), a+2); +} + +int +getpointstrarg(v, a, b) + object *v; + int *a; /* [2] */ + object **b; +{ + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { + return err_badarg(); + } + return getpointarg(gettupleitem(v, 0), a) && + getstrarg(gettupleitem(v, 1), b); +} + +int +getstrintintarg(v, a, b, c) + object *v; + object *a; + int *b, *c; +{ + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 3) { + return err_badarg(); + } + return getstrarg(gettupleitem(v, 0), a) && + getintarg(gettupleitem(v, 1), b) && + getintarg(gettupleitem(v, 2), c); +} + +int +getrectpointarg(v, a) + object *v; + int *a; /* [4+2] */ +{ + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) { + return err_badarg(); + } + return getrectarg(gettupleitem(v, 0), a) && + getpointarg(gettupleitem(v, 1), a+4); +} + +int +getlongtuplearg(args, a, n) + object *args; + long *a; /* [n] */ + int n; +{ + int i; + if (!is_tupleobject(args) || gettuplesize(args) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + object *v = gettupleitem(args, i); + if (!is_intobject(v)) { + return err_badarg(); + } + a[i] = getintvalue(v); + } + return 1; +} + +int +getshorttuplearg(args, a, n) + object *args; + short *a; /* [n] */ + int n; +{ + int i; + if (!is_tupleobject(args) || gettuplesize(args) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + object *v = gettupleitem(args, i); + if (!is_intobject(v)) { + return err_badarg(); + } + a[i] = getintvalue(v); + } + return 1; +} + +int +getlonglistarg(args, a, n) + object *args; + long *a; /* [n] */ + int n; +{ + int i; + if (!is_listobject(args) || getlistsize(args) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + object *v = getlistitem(args, i); + if (!is_intobject(v)) { + return err_badarg(); + } + a[i] = getintvalue(v); + } + return 1; +} + +int +getshortlistarg(args, a, n) + object *args; + short *a; /* [n] */ + int n; +{ + int i; + if (!is_listobject(args) || getlistsize(args) != n) { + return err_badarg(); + } + for (i = 0; i < n; i++) { + object *v = getlistitem(args, i); + if (!is_intobject(v)) { + return err_badarg(); + } + a[i] = getintvalue(v); + } + return 1; +} diff --git a/src/modsupport.h b/src/modsupport.h new file mode 100644 index 0000000..843b209 --- /dev/null +++ b/src/modsupport.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. + +******************************************************************/ + +/* Module support interface */ + +extern object *initmodule PROTO((char *, struct methodlist *)); diff --git a/src/moduleobject.c b/src/moduleobject.c new file mode 100644 index 0000000..82599f9 --- /dev/null +++ b/src/moduleobject.c @@ -0,0 +1,154 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Module object implementation */ + +#include "allobjects.h" + +typedef struct { + OB_HEAD + object *md_name; + object *md_dict; +} moduleobject; + +object * +newmoduleobject(name) + char *name; +{ + moduleobject *m = NEWOBJ(moduleobject, &Moduletype); + if (m == NULL) + return NULL; + m->md_name = newstringobject(name); + m->md_dict = newdictobject(); + if (m->md_name == NULL || m->md_dict == NULL) { + DECREF(m); + return NULL; + } + return (object *)m; +} + +object * +getmoduledict(m) + object *m; +{ + if (!is_moduleobject(m)) { + err_badcall(); + return NULL; + } + return ((moduleobject *)m) -> md_dict; +} + +char * +getmodulename(m) + object *m; +{ + if (!is_moduleobject(m)) { + err_badarg(); + return NULL; + } + return getstringvalue(((moduleobject *)m) -> md_name); +} + +/* Methods */ + +static void +module_dealloc(m) + moduleobject *m; +{ + if (m->md_name != NULL) + DECREF(m->md_name); + if (m->md_dict != NULL) + DECREF(m->md_dict); + free((char *)m); +} + +static void +module_print(m, fp, flags) + moduleobject *m; + FILE *fp; + int flags; +{ + fprintf(fp, "<module '%s'>", getstringvalue(m->md_name)); +} + +static object * +module_repr(m) + moduleobject *m; +{ + char buf[100]; + sprintf(buf, "<module '%.80s'>", getstringvalue(m->md_name)); + return newstringobject(buf); +} + +static object * +module_getattr(m, name) + moduleobject *m; + char *name; +{ + object *res; + if (strcmp(name, "__dict__") == 0) { + INCREF(m->md_dict); + return m->md_dict; + } + if (strcmp(name, "__name__") == 0) { + INCREF(m->md_name); + return m->md_name; + } + res = dictlookup(m->md_dict, name); + if (res == NULL) + err_setstr(NameError, name); + else + INCREF(res); + return res; +} + +static int +module_setattr(m, name, v) + moduleobject *m; + char *name; + object *v; +{ + if (strcmp(name, "__dict__") == 0 || strcmp(name, "__name__") == 0) { + err_setstr(NameError, "can't assign to reserved member name"); + return -1; + } + if (v == NULL) + return dictremove(m->md_dict, name); + else + return dictinsert(m->md_dict, name, v); +} + +typeobject Moduletype = { + OB_HEAD_INIT(&Typetype) + 0, /*ob_size*/ + "module", /*tp_name*/ + sizeof(moduleobject), /*tp_size*/ + 0, /*tp_itemsize*/ + module_dealloc, /*tp_dealloc*/ + module_print, /*tp_print*/ + module_getattr, /*tp_getattr*/ + module_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + module_repr, /*tp_repr*/ +}; diff --git a/src/moduleobject.h b/src/moduleobject.h new file mode 100644 index 0000000..4657c22 --- /dev/null +++ b/src/moduleobject.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. + +******************************************************************/ + +/* Module object interface */ + +extern typeobject Moduletype; + +#define is_moduleobject(op) ((op)->ob_type == &Moduletype) + +extern object *newmoduleobject PROTO((char *)); +extern object *getmoduledict PROTO((object *)); +extern char *getmodulename PROTO((object *)); diff --git a/src/node.c b/src/node.c new file mode 100644 index 0000000..2b76ae8 --- /dev/null +++ b/src/node.c @@ -0,0 +1,100 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Parse tree node implementation */ + +#include "pgenheaders.h" +#include "node.h" + +node * +newtree(type) + int type; +{ + node *n = NEW(node, 1); + if (n == NULL) + return NULL; + n->n_type = type; + n->n_str = NULL; + n->n_lineno = 0; + n->n_nchildren = 0; + n->n_child = NULL; + return n; +} + +#define XXX 3 /* Node alignment factor to speed up realloc */ +#define XXXROUNDUP(n) ((n) == 1 ? 1 : ((n) + XXX - 1) / XXX * XXX) + +node * +addchild(n1, type, str, lineno) + register node *n1; + int type; + char *str; + int lineno; +{ + register int nch = n1->n_nchildren; + register int nch1 = nch+1; + register node *n; + if (XXXROUNDUP(nch) < nch1) { + n = n1->n_child; + nch1 = XXXROUNDUP(nch1); + RESIZE(n, node, nch1); + if (n == NULL) + return NULL; + n1->n_child = n; + } + n = &n1->n_child[n1->n_nchildren++]; + n->n_type = type; + n->n_str = str; + n->n_lineno = lineno; + n->n_nchildren = 0; + n->n_child = NULL; + return n; +} + +/* Forward */ +static void freechildren PROTO((node *)); + + +void +freetree(n) + node *n; +{ + if (n != NULL) { + freechildren(n); + DEL(n); + } +} + +static void +freechildren(n) + node *n; +{ + int i; + for (i = NCH(n); --i >= 0; ) + freechildren(CHILD(n, i)); + if (n->n_child != NULL) + DEL(n->n_child); + if (STR(n) != NULL) + DEL(STR(n)); +} diff --git a/src/node.h b/src/node.h new file mode 100644 index 0000000..5b43f8f --- /dev/null +++ b/src/node.h @@ -0,0 +1,58 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Parse tree node interface */ + +typedef struct _node { + int n_type; + char *n_str; + int n_lineno; + int n_nchildren; + struct _node *n_child; +} node; + +extern node *newtree PROTO((int type)); +extern node *addchild PROTO((node *n, int type, char *str, int lineno)); +extern void freetree PROTO((node *n)); + +/* Node access functions */ +#define NCH(n) ((n)->n_nchildren) +#define CHILD(n, i) (&(n)->n_child[i]) +#define TYPE(n) ((n)->n_type) +#define STR(n) ((n)->n_str) + +/* Assert that the type of a node is what we expect */ +#ifndef DEBUG +#define REQ(n, type) { /*pass*/ ; } +#else +#define REQ(n, type) \ + { if (TYPE(n) != (type)) { \ + fprintf(stderr, "FATAL: node type %d, required %d\n", \ + TYPE(n), type); \ + abort(); \ + } } +#endif + +extern void listtree PROTO((node *)); +extern void listnode PROTO((FILE *, node *)); diff --git a/src/object.c b/src/object.c new file mode 100644 index 0000000..37e2b26 --- /dev/null +++ b/src/object.c @@ -0,0 +1,290 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Generic object operations; and implementation of None (NoObject) */ + +#include "allobjects.h" + +#ifdef REF_DEBUG +long ref_total; +#endif + +/* Object allocation routines used by NEWOBJ and NEWVAROBJ macros. + These are used by the individual routines for object creation. + Do not call them otherwise, they do not initialize the object! */ + +object * +newobject(tp) + typeobject *tp; +{ + object *op = (object *) malloc(tp->tp_basicsize); + if (op == NULL) + return err_nomem(); + NEWREF(op); + op->ob_type = tp; + return op; +} + +#if 0 /* unused */ + +varobject * +newvarobject(tp, size) + typeobject *tp; + unsigned int size; +{ + varobject *op = (varobject *) + malloc(tp->tp_basicsize + size * tp->tp_itemsize); + if (op == NULL) + return err_nomem(); + NEWREF(op); + op->ob_type = tp; + op->ob_size = size; + return op; +} + +#endif + +int StopPrint; /* Flag to indicate printing must be stopped */ + +static int prlevel; + +void +printobject(op, fp, flags) + object *op; + FILE *fp; + int flags; +{ + /* Hacks to make printing a long or recursive object interruptible */ + /* XXX Interrupts should leave a more permanent error */ + prlevel++; + if (!StopPrint && intrcheck()) { + fprintf(fp, "\n[print interrupted]\n"); + StopPrint = 1; + } + if (!StopPrint) { + if (op == NULL) { + fprintf(fp, "<nil>"); + } + else { + if (op->ob_refcnt <= 0) + fprintf(fp, "(refcnt %d):", op->ob_refcnt); + if (op->ob_type->tp_print == NULL) { + fprintf(fp, "<%s object at %lx>", + op->ob_type->tp_name, (long)op); + } + else { + (*op->ob_type->tp_print)(op, fp, flags); + } + } + } + prlevel--; + if (prlevel == 0) + StopPrint = 0; +} + +object * +reprobject(v) + object *v; +{ + object *w = NULL; + /* Hacks to make converting a long or recursive object interruptible */ + prlevel++; + if (!StopPrint && intrcheck()) { + StopPrint = 1; + err_set(KeyboardInterrupt); + } + if (!StopPrint) { + if (v == NULL) { + w = newstringobject("<NULL>"); + } + else if (v->ob_type->tp_repr == NULL) { + char buf[100]; + sprintf(buf, "<%.80s object at %lx>", + v->ob_type->tp_name, (long)v); + w = newstringobject(buf); + } + else { + w = (*v->ob_type->tp_repr)(v); + } + if (StopPrint) { + XDECREF(w); + w = NULL; + } + } + prlevel--; + if (prlevel == 0) + StopPrint = 0; + return w; +} + +int +cmpobject(v, w) + object *v, *w; +{ + typeobject *tp; + if (v == w) + return 0; + if (v == NULL) + return -1; + if (w == NULL) + return 1; + if ((tp = v->ob_type) != w->ob_type) + return strcmp(tp->tp_name, w->ob_type->tp_name); + if (tp->tp_compare == NULL) + return (v < w) ? -1 : 1; + return ((*tp->tp_compare)(v, w)); +} + +object * +getattr(v, name) + object *v; + char *name; +{ + if (v->ob_type->tp_getattr == NULL) { + err_setstr(TypeError, "attribute-less object"); + return NULL; + } + else { + return (*v->ob_type->tp_getattr)(v, name); + } +} + +int +setattr(v, name, w) + object *v; + char *name; + object *w; +{ + if (v->ob_type->tp_setattr == NULL) { + if (v->ob_type->tp_getattr == NULL) + err_setstr(TypeError, "attribute-less object"); + else + err_setstr(TypeError, "object has read-only attributes"); + return -1; + } + else { + return (*v->ob_type->tp_setattr)(v, name, w); + } +} + + +/* +NoObject is usable as a non-NULL undefined value, used by the macro None. +There is (and should be!) no way to create other objects of this type, +so there is exactly one (which is indestructible, by the way). +*/ + +static void +none_print(op, fp, flags) + object *op; + FILE *fp; + int flags; +{ + fprintf(fp, "None"); +} + +static object * +none_repr(op) + object *op; +{ + return newstringobject("None"); +} + +static typeobject Notype = { + OB_HEAD_INIT(&Typetype) + 0, + "None", + 0, + 0, + 0, /*tp_dealloc*/ /*never called*/ + none_print, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + none_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; + +object NoObject = { + OB_HEAD_INIT(&Notype) +}; + + +#ifdef TRACE_REFS + +static object refchain = {&refchain, &refchain}; + +NEWREF(op) + object *op; +{ + ref_total++; + op->ob_refcnt = 1; + op->_ob_next = refchain._ob_next; + op->_ob_prev = &refchain; + refchain._ob_next->_ob_prev = op; + refchain._ob_next = op; +} + +UNREF(op) + register object *op; +{ + register object *p; + if (op->ob_refcnt < 0) { + fprintf(stderr, "UNREF negative refcnt\n"); + abort(); + } + for (p = refchain._ob_next; p != &refchain; p = p->_ob_next) { + if (p == op) + break; + } + if (p == &refchain) { /* Not found */ + fprintf(stderr, "UNREF unknown object\n"); + abort(); + } + op->_ob_next->_ob_prev = op->_ob_prev; + op->_ob_prev->_ob_next = op->_ob_next; +} + +DELREF(op) + object *op; +{ + UNREF(op); + (*(op)->ob_type->tp_dealloc)(op); +} + +printrefs(fp) + FILE *fp; +{ + object *op; + fprintf(fp, "Remaining objects:\n"); + for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) { + fprintf(fp, "[%d] ", op->ob_refcnt); + printobject(op, fp, 0); + putc('\n', fp); + } +} + +#endif diff --git a/src/object.h b/src/object.h new file mode 100644 index 0000000..f0266c4 --- /dev/null +++ b/src/object.h @@ -0,0 +1,324 @@ +/*********************************************************** +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 NDEBUG +/* Object and type object interface */ + +/* +123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 + +Objects are structures allocated on the heap. Special rules apply to +the use of objects to ensure they are properly garbage-collected. +Objects are never allocated statically or on the stack; they must be +accessed through special macros and functions only. (Type objects are +exceptions to the first rule; the standard types are represented by +statically initialized type objects.) + +An object has a 'reference count' that is increased or decreased when a +pointer to the object is copied or deleted; when the reference count +reaches zero there are no references to the object left and it can be +removed from the heap. + +An object has a 'type' that determines what it represents and what kind +of data it contains. An object's type is fixed when it is created. +Types themselves are represented as objects; an object contains a +pointer to the corresponding type object. The type itself has a type +pointer pointing to the object representing the type 'type', which +contains a pointer to itself!). + +Objects do not float around in memory; once allocated an object keeps +the same size and address. Objects that must hold variable-size data +can contain pointers to variable-size parts of the object. Not all +objects of the same type have the same size; but the size cannot change +after allocation. (These restrictions are made so a reference to an +object can be simply a pointer -- moving an object would require +updating all the pointers, and changing an object's size would require +moving it if there was another object right next to it.) + +Objects are always accessed through pointers of the type 'object *'. +The type 'object' is a structure that only contains the reference count +and the type pointer. The actual memory allocated for an object +contains other data that can only be accessed after casting the pointer +to a pointer to a longer structure type. This longer type must start +with the reference count and type fields; the macro OB_HEAD should be +used for this (to accomodate for future changes). The implementation +of a particular object type can cast the object pointer to the proper +type and back. + +A standard interface exists for objects that contain an array of items +whose size is determined when the object is allocated. + +123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 +*/ + +#ifndef NDEBUG + +/* Turn on heavy reference debugging */ +#define TRACE_REFS + +/* Turn on reference counting */ +#define REF_DEBUG + +#endif /* NDEBUG */ + +#ifdef TRACE_REFS +#define OB_HEAD \ + struct _object *_ob_next, *_ob_prev; \ + int ob_refcnt; \ + struct _typeobject *ob_type; +#define OB_HEAD_INIT(type) 0, 0, 1, type, +#else +#define OB_HEAD \ + unsigned int ob_refcnt; \ + struct _typeobject *ob_type; +#define OB_HEAD_INIT(type) 1, type, +#endif + +#define OB_VARHEAD \ + OB_HEAD \ + unsigned int ob_size; /* Number of items in variable part */ + +typedef struct _object { + OB_HEAD +} object; + +typedef struct { + OB_VARHEAD +} varobject; + + +/* +123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 + +Type objects contain a string containing the type name (to help somewhat +in debugging), the allocation parameters (see newobj() and newvarobj()), +and methods for accessing objects of the type. Methods are optional,a +nil pointer meaning that particular kind of access is not available for +this type. The DECREF() macro uses the tp_dealloc method without +checking for a nil pointer; it should always be implemented except if +the implementation can guarantee that the reference count will never +reach zero (e.g., for type objects). + +NB: the methods for certain type groups are now contained in separate +method blocks. +*/ + +typedef struct { + object *(*nb_add) FPROTO((object *, object *)); + object *(*nb_subtract) FPROTO((object *, object *)); + object *(*nb_multiply) FPROTO((object *, object *)); + object *(*nb_divide) FPROTO((object *, object *)); + object *(*nb_remainder) FPROTO((object *, object *)); + object *(*nb_power) FPROTO((object *, object *)); + object *(*nb_negative) FPROTO((object *)); + object *(*nb_positive) FPROTO((object *)); +} number_methods; + +typedef struct { + int (*sq_length) FPROTO((object *)); + object *(*sq_concat) FPROTO((object *, object *)); + object *(*sq_repeat) FPROTO((object *, int)); + object *(*sq_item) FPROTO((object *, int)); + object *(*sq_slice) FPROTO((object *, int, int)); + int (*sq_ass_item) FPROTO((object *, int, object *)); + int (*sq_ass_slice) FPROTO((object *, int, int, object *)); +} sequence_methods; + +typedef struct { + int (*mp_length) FPROTO((object *)); + object *(*mp_subscript) FPROTO((object *, object *)); + int (*mp_ass_subscript) FPROTO((object *, object *, object *)); +} mapping_methods; + +typedef struct _typeobject { + OB_VARHEAD + char *tp_name; /* For printing */ + unsigned int tp_basicsize, tp_itemsize; /* For allocation */ + + /* Methods to implement standard operations */ + + void (*tp_dealloc) FPROTO((object *)); + void (*tp_print) FPROTO((object *, FILE *, int)); + object *(*tp_getattr) FPROTO((object *, char *)); + int (*tp_setattr) FPROTO((object *, char *, object *)); + int (*tp_compare) FPROTO((object *, object *)); + object *(*tp_repr) FPROTO((object *)); + + /* Method suites for standard classes */ + + number_methods *tp_as_number; + sequence_methods *tp_as_sequence; + mapping_methods *tp_as_mapping; +} typeobject; + +extern typeobject Typetype; /* The type of type objects */ + +#define is_typeobject(op) ((op)->ob_type == &Typetype) + +/* Generic operations on objects */ +extern void printobject PROTO((object *, FILE *, int)); +extern object * reprobject PROTO((object *)); +extern int cmpobject PROTO((object *, object *)); +extern object *getattr PROTO((object *, char *)); +extern int setattr PROTO((object *, char *, object *)); + +/* Flag bits for printing: */ +#define PRINT_RAW 1 /* No string quotes etc. */ + +/* +123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 + +The macros INCREF(op) and DECREF(op) are used to increment or decrement +reference counts. DECREF calls the object's deallocator function; for +objects that don't contain references to other objects or heap memory +this can be the standard function free(). Both macros can be used +whereever a void expression is allowed. The argument shouldn't be a +NIL pointer. The macro NEWREF(op) is used only to initialize reference +counts to 1; it is defined here for convenience. + +We assume that the reference count field can never overflow; this can +be proven when the size of the field is the same as the pointer size +but even with a 16-bit reference count field it is pretty unlikely so +we ignore the possibility. (If you are paranoid, make it a long.) + +Type objects should never be deallocated; the type pointer in an object +is not considered to be a reference to the type object, to save +complications in the deallocation function. (This is actually a +decision that's up to the implementer of each new type so if you want, +you can count such references to the type object.) + +*** WARNING*** The DECREF macro must have a side-effect-free argument +since it may evaluate its argument multiple times. (The alternative +would be to mace it a proper function or assign it to a global temporary +variable first, both of which are slower; and in a multi-threaded +environment the global variable trick is not safe.) +*/ + +#ifdef TRACE_REFS +#ifndef REF_DEBUG +#define REF_DEBUG +#endif +#endif + +#ifndef TRACE_REFS +#define DELREF(op) (*(op)->ob_type->tp_dealloc)((object *)(op)) +#define UNREF(op) /*empty*/ +#endif + +#ifdef REF_DEBUG +extern long ref_total; +#ifndef TRACE_REFS +#define NEWREF(op) (ref_total++, (op)->ob_refcnt = 1) +#endif +#define INCREF(op) (ref_total++, (op)->ob_refcnt++) +#define DECREF(op) \ + if (--ref_total, --(op)->ob_refcnt > 0) \ + ; \ + else \ + DELREF(op) +#else +#define NEWREF(op) ((op)->ob_refcnt = 1) +#define INCREF(op) ((op)->ob_refcnt++) +#define DECREF(op) \ + if (--(op)->ob_refcnt > 0) \ + ; \ + else \ + DELREF(op) +#endif + +/* Macros to use in case the object pointer may be NULL: */ + +#define XINCREF(op) if ((op) == NULL) ; else INCREF(op) +#define XDECREF(op) if ((op) == NULL) ; else DECREF(op) + +/* Definition of NULL, so you don't have to include <stdio.h> */ + +#ifndef NULL +#define NULL 0 +#endif + + +/* +NoObject is an object of undefined type which can be used in contexts +where NULL (nil) is not suitable (since NULL often means 'error'). + +Don't forget to apply INCREF() when returning this value!!! +*/ + +extern object NoObject; /* Don't use this directly */ + +#define None (&NoObject) + + +/* +123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 + +More conventions +================ + +Argument Checking +----------------- + +Functions that take objects as arguments normally don't check for nil +arguments, but they do check the type of the argument, and return an +error if the function doesn't apply to the type. + +Failure Modes +------------- + +Functions may fail for a variety of reasons, including running out of +memory. This is communicated to the caller in two ways: an error string +is set (see errors.h), and the function result differs: functions that +normally return a pointer return NULL for failure, functions returning +an integer return -1 (which could be a legal return value too!), and +other functions return 0 for success and -1 for failure. +Callers should always check for errors before using the result. + +Reference Counts +---------------- + +It takes a while to get used to the proper usage of reference counts. + +Functions that create an object set the reference count to 1; such new +objects must be stored somewhere or destroyed again with DECREF(). +Functions that 'store' objects such as settupleitem() and dictinsert() +don't increment the reference count of the object, since the most +frequent use is to store a fresh object. Functions that 'retrieve' +objects such as gettupleitem() and dictlookup() also don't increment +the reference count, since most frequently the object is only looked at +quickly. Thus, to retrieve an object and store it again, the caller +must call INCREF() explicitly. + +NOTE: functions that 'consume' a reference count like dictinsert() even +consume the reference if the object wasn't stored, to simplify error +handling. + +It seems attractive to make other functions that take an object as +argument consume a reference count; however this may quickly get +confusing (even the current practice is already confusing). Consider +it carefully, it may safe lots of calls to INCREF() and DECREF() at +times. + +123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 +*/ diff --git a/src/objimpl.h b/src/objimpl.h new file mode 100644 index 0000000..7d40718 --- /dev/null +++ b/src/objimpl.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. + +******************************************************************/ + +/* +123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 + +Additional macros for modules that implement new object types. +You must first include "object.h". + +NEWOBJ(type, typeobj) allocates memory for a new object of the given +type; here 'type' must be the C structure type used to represent the +object and 'typeobj' the address of the corresponding type object. +Reference count and type pointer are filled in; the rest of the bytes of +the object are *undefined*! The resulting expression type is 'type *'. +The size of the object is actually determined by the tp_basicsize field +of the type object. + +NEWVAROBJ(type, typeobj, n) is similar but allocates a variable-size +object with n extra items. The size is computer as tp_basicsize plus +n * tp_itemsize. This fills in the ob_size field as well. +*/ + +extern object *newobject PROTO((typeobject *)); +extern varobject *newvarobject PROTO((typeobject *, unsigned int)); + +#define NEWOBJ(type, typeobj) ((type *) newobject(typeobj)) +#define NEWVAROBJ(type, typeobj, n) ((type *) newvarobject(typeobj, n)) + +extern int StopPrint; /* Set when printing is interrupted */ diff --git a/src/opcode.h b/src/opcode.h new file mode 100644 index 0000000..ad6d712 --- /dev/null +++ b/src/opcode.h @@ -0,0 +1,109 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Instruction opcodes for compiled code */ + +#define STOP_CODE 0 +#define POP_TOP 1 +#define ROT_TWO 2 +#define ROT_THREE 3 +#define DUP_TOP 4 + +#define UNARY_POSITIVE 10 +#define UNARY_NEGATIVE 11 +#define UNARY_NOT 12 +#define UNARY_CONVERT 13 +#define UNARY_CALL 14 + +#define BINARY_MULTIPLY 20 +#define BINARY_DIVIDE 21 +#define BINARY_MODULO 22 +#define BINARY_ADD 23 +#define BINARY_SUBTRACT 24 +#define BINARY_SUBSCR 25 +#define BINARY_CALL 26 + +#define SLICE 30 +/* Also uses 31-33 */ + +#define STORE_SLICE 40 +/* Also uses 41-43 */ + +#define DELETE_SLICE 50 +/* Also uses 51-53 */ + +#define STORE_SUBSCR 60 +#define DELETE_SUBSCR 61 + +#define PRINT_EXPR 70 +#define PRINT_ITEM 71 +#define PRINT_NEWLINE 72 + +#define BREAK_LOOP 80 +#define RAISE_EXCEPTION 81 +#define LOAD_LOCALS 82 +#define RETURN_VALUE 83 +#define REQUIRE_ARGS 84 +#define REFUSE_ARGS 85 +#define BUILD_FUNCTION 86 +#define POP_BLOCK 87 +#define END_FINALLY 88 +#define BUILD_CLASS 89 + +#define HAVE_ARGUMENT 90 /* Opcodes from here have an argument: */ + +#define STORE_NAME 90 /* Index in name list */ +#define DELETE_NAME 91 /* "" */ +#define UNPACK_TUPLE 92 /* Number of tuple items */ +#define UNPACK_LIST 93 /* Number of list items */ +/* unused: 94 */ +#define STORE_ATTR 95 /* Index in name list */ +#define DELETE_ATTR 96 /* "" */ + +#define LOAD_CONST 100 /* Index in const list */ +#define LOAD_NAME 101 /* Index in name list */ +#define BUILD_TUPLE 102 /* Number of tuple items */ +#define BUILD_LIST 103 /* Number of list items */ +#define BUILD_MAP 104 /* Always zero for now */ +#define LOAD_ATTR 105 /* Index in name list */ +#define COMPARE_OP 106 /* Comparison operator */ +#define IMPORT_NAME 107 /* Index in name list */ +#define IMPORT_FROM 108 /* Index in name list */ + +#define JUMP_FORWARD 110 /* Number of bytes to skip */ +#define JUMP_IF_FALSE 111 /* "" */ +#define JUMP_IF_TRUE 112 /* "" */ +#define JUMP_ABSOLUTE 113 /* Target byte offset from beginning of code */ +#define FOR_LOOP 114 /* Number of bytes to skip */ + +#define SETUP_LOOP 120 /* Target address (absolute) */ +#define SETUP_EXCEPT 121 /* "" */ +#define SETUP_FINALLY 122 /* "" */ + +#define SET_LINENO 127 /* Current line number */ + +/* Comparison operator codes (argument to COMPARE_OP) */ +enum cmp_op {LT, LE, EQ, NE, GT, GE, IN, NOT_IN, IS, IS_NOT, EXC_MATCH, BAD}; + +#define HAS_ARG(op) ((op) >= HAVE_ARGUMENT) diff --git a/src/panelmodule.c b/src/panelmodule.c new file mode 100644 index 0000000..9edde6b --- /dev/null +++ b/src/panelmodule.c @@ -0,0 +1,1090 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Panel module. + Interface to the NASA Ames "panel library" for the SGI Graphics Library + by David Tristram. + + NOTE: the panel library dumps core if you don't create a window before + calling pnl.mkpanel(). A call to gl.winopen() suffices. + If you don't want a window to be created, call gl.noport() before + gl.winopen(). +*/ + +#include <gl.h> +#include <device.h> +#include <panel.h> + +#include "allobjects.h" +#include "import.h" +#include "modsupport.h" +#include "cgensupport.h" + + +/* The offsetof() macro calculates the offset of a structure member + in its structure. Unfortunately this cannot be written down portably, + hence it is standardized by ANSI C. For pre-ANSI C compilers, + we give a version here that works usually (but watch out!): */ + +#ifndef offsetof +#define offsetof(type, member) ( (int) & ((type*)0) -> member ) +#endif + + +/* Panel objects */ + +typedef struct { + OB_HEAD + Panel *ob_panel; + object *ob_paneldict; +} panelobject; + +extern typeobject Paneltype; /* Really static, forward */ + +#define is_panelobject(v) ((v)->ob_type == &Paneltype) + + +/* Actuator objects */ + +typedef struct { + OB_HEAD + Actuator *ob_actuator; +} actuatorobject; + +extern typeobject Actuatortype; /* Really static, forward */ + +#define is_actuatorobject(v) ((v)->ob_type == &Actuatortype) + +static object *newactuatorobject(); /* Forward */ + + +/* Since we allow different types of members than the functions from + structmember.c, the memberlist stuff is replicated here. + (Historically, it originated in this file and later became a generic + feature.) */ + +/* An array of memberlist structures defines the name, type and offset + of selected members of a C structure. These can be read by + panel_getmember() and set by panel_setmember() (except if their + READONLY flag is set). The array must be terminated with an entry + whose name pointer is NULL. */ + +struct memberlist { + char *name; + int type; + int offset; + int readonly; +}; + +/* Types */ +#define T_SHORT 0 +#define T_DEVICE T_SHORT +#define T_LONG 1 +#define T_INT T_LONG +#define T_BOOL T_LONG +#define T_FLOAT 2 +#define T_COORD T_FLOAT +#define T_STRING 3 +#define T_FUNC 4 +#define T_ACTUATOR 5 + +/* Readonly flag */ +#define READONLY 1 +#define RO READONLY /* Shorthand */ + +static object * +panel_getmember(addr, mlist, name) + char *addr; + struct memberlist *mlist; + char *name; +{ + object *v; + register struct memberlist *l; + + for (l = mlist; l->name != NULL; l++) { + if (strcmp(l->name, name) == 0) { + addr += l->offset; + switch (l->type) { + case T_SHORT: + v = newintobject((long) *(short*)addr); + break; + case T_LONG: + v = newintobject(*(long*)addr); + break; + case T_FLOAT: + v = newfloatobject(*(float*)addr); + break; + case T_STRING: + if (*(char**)addr == NULL) { + INCREF(None); + v = None; + } + else + v = newstringobject(*(char**)addr); + break; + case T_ACTUATOR: + v = newactuatorobject(*(Actuator**)addr); + break; + default: + err_badarg(); + v = NULL; + } + return v; + } + } + err_setstr(NameError, name); + return NULL; +} + +/* Attempt to set a member. Return: 0 if OK; 1 if not found; -1 if error */ + +static int +panel_setmember(addr, mlist, name, v) + char *addr; + struct memberlist *mlist; + char *name; + object *v; +{ + register struct memberlist *l; + + for (l = mlist; l->name != NULL; l++) { + if (strcmp(l->name, name) == 0) { + if (l->readonly) { + err_setstr(TypeError, "read-only member"); + return -1; + } + addr += l->offset; + switch (l->type) { + case T_SHORT: + if (!is_intobject(v)) { + err_setstr(TypeError, "int expected"); + return -1; + } + *(short*)addr = getintvalue(v); + break; + case T_LONG: + if (!is_intobject(v)) { + err_setstr(TypeError, "int expected"); + return -1; + } + *(long*)addr = getintvalue(v); + break; + case T_FLOAT: + if (is_intobject(v)) + *(float*)addr = getintvalue(v); + else if (is_floatobject(v)) + *(float*)addr = getfloatvalue(v); + else { + err_setstr(TypeError,"float expected"); + return -1; + } + break; + case T_STRING: + /* XXX Should free(*(char**)addr) here + but it's dangerous since we don't know + if we set the label ourselves */ + if (v == None) + *(char**)addr = NULL; + else if (!is_stringobject(v)) { + err_setstr(TypeError, + "string expected"); + return -1; + } + else + *(char**)addr = + strdup(getstringvalue(v)); + break; + case T_ACTUATOR: + if (v == None) + *(Actuator**)addr = NULL; + else if (!is_actuatorobject(v)) { + err_setstr(TypeError, + "actuator expected"); + return -1; + } + else + *(Actuator**)addr = + ((actuatorobject *)v)->ob_actuator; + break; + default: + err_setstr(SystemError, "unknown member type"); + return -1; + } + return 0; /* Found it */ + } + } + + return 1; /* Not found */ +} + + +/* Panel object methods */ + +static object * +panel_addpanel(self, args) + panelobject *self; + object *args; +{ + if (!getnoarg(args)) + return NULL; + pnl_addpanel(self->ob_panel); + INCREF(None); + return None; +} + +static object * +panel_endgroup(self, args) + panelobject *self; + object *args; +{ + if (!getnoarg(args)) + return NULL; + pnl_endgroup(self->ob_panel); + INCREF(None); + return None; +} + +static object * +panel_fixpanel(self, args) + panelobject *self; + object *args; +{ + if (!getnoarg(args)) + return NULL; + pnl_fixpanel(self->ob_panel); + INCREF(None); + return None; +} + +static object * +panel_strwidth(self, args) + panelobject *self; + object *args; +{ + object *v; + double width; + if (!getstrarg(args, &v)) + return NULL; + width = pnl_strwidth(self->ob_panel, getstringvalue(v)); + return newfloatobject(width); +} + +static struct methodlist panel_methods[] = { + {"addpanel", panel_addpanel}, + {"endgroup", panel_endgroup}, + {"fixpanel", panel_fixpanel}, + {"strwidth", panel_strwidth}, + {NULL, NULL} /* sentinel */ +}; + +static object * +newpanelobject() +{ + panelobject *p; + p = NEWOBJ(panelobject, &Paneltype); + if (p == NULL) + return NULL; + p->ob_panel = pnl_mkpanel(); + if ((p->ob_paneldict = newdictobject()) == NULL) { + DECREF(p); + return NULL; + } + return (object *)p; +} + +static void +panel_dealloc(p) + panelobject *p; +{ + pnl_delpanel(p->ob_panel); + if (p->ob_paneldict != NULL) + DECREF(p->ob_paneldict); + DEL(p); +} + + +/* Table of panel members */ + +#define PANOFF(member) offsetof(Panel, member) + +static struct memberlist panel_memberlist[] = { + {"id", T_SHORT, PANOFF(id), READONLY}, + {"a", T_ACTUATOR, PANOFF(a), READONLY}, + {"al", T_ACTUATOR, PANOFF(al), READONLY}, + {"lastgroup", T_ACTUATOR, PANOFF(lastgroup), READONLY}, + + {"active", T_BOOL, PANOFF(active)}, + {"selectable", T_BOOL, PANOFF(selectable)}, + + {"x", T_LONG, PANOFF(x)}, + {"y", T_LONG, PANOFF(y)}, + {"w", T_LONG, PANOFF(w)}, + {"h", T_LONG, PANOFF(h)}, + + {"minx", T_COORD, PANOFF(minx)}, + {"maxx", T_COORD, PANOFF(maxx)}, + {"miny", T_COORD, PANOFF(miny)}, + {"maxy", T_COORD, PANOFF(maxy)}, + + {"cw", T_COORD, PANOFF(cw)}, + {"ch", T_COORD, PANOFF(ch)}, + + {"gid", T_LONG, PANOFF(gid), READONLY}, + {"usergid", T_LONG, PANOFF(usergid), READONLY}, + + {"vobj", T_LONG, PANOFF(vobj), READONLY}, + {"ppu", T_FLOAT, PANOFF(ppu)}, + + {"label", T_STRING, PANOFF(label)}, + + /* Panel callbacks are not supported */ + + {"visible", T_BOOL, PANOFF(visible)}, + {"somedirty", T_INT, PANOFF(somedirty)}, + {"dirtycnt", T_INT, PANOFF(dirtycnt)}, + + /* T_PANEL is not supported */ + /* + {"next", T_PANEL, PANOFF(next), READONLY}, + */ + + {NULL, 0, 0} /* Sentinel */ +}; + +static object * +panel_getattr(p, name) + panelobject *p; + char *name; +{ + object *v; + + v = dictlookup(p->ob_paneldict, name); + if (v != NULL) { + INCREF(v); + return v; + } + + v = findmethod(panel_methods, (object *)p, name); + if (v != NULL) + return v; + err_clear(); + return panel_getmember((char *)p->ob_panel, panel_memberlist, name); +} + +static int +panel_setattr(p, name, v) + panelobject *p; + char *name; + object *v; +{ + int err; + + /* We don't allow deletion of attributes */ + if (v == NULL) { + err_setstr(TypeError, "read-only panel attribute"); + return -1; + } + err = panel_setmember((char *)p->ob_panel, panel_memberlist, name, v); + if (err != 1) + return err; + return dictinsert(p->ob_paneldict, name, v); +} + +static typeobject Paneltype = { + OB_HEAD_INIT(&Typetype) + 0, /*ob_size*/ + "panel", /*tp_name*/ + sizeof(panelobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + panel_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + panel_getattr, /*tp_getattr*/ + panel_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; + + +/* Descriptions of actuator-specific data members */ + +struct memberlist slider_spec[] = { + {"mode", T_INT, offsetof(Slider, mode)}, + {"finefactor", T_FLOAT, offsetof(Slider, finefactor)}, + {"differentialfactor", + T_FLOAT, offsetof(Slider, differentialfactor)}, + {"valsave", T_FLOAT, offsetof(Slider, valsave), RO}, + {"wsave", T_COORD, offsetof(Slider, wsave)}, + {"bh", T_COORD, offsetof(Slider, bh)}, + {NULL} +}; + +#define palette_spec slider_spec + +struct memberlist puck_spec[] = { + /* Actuators already have members x and y, so the Puck's x and y + have different names */ + {"puck_x", T_FLOAT, offsetof(Puck, x)}, + {"puck_y", T_FLOAT, offsetof(Puck, y)}, + {NULL} +}; + +struct memberlist dial_spec[] = { + {"mode", T_INT, offsetof(Dial, mode)}, + {"finefactor", T_FLOAT, offsetof(Dial, finefactor)}, + {"valsave", T_FLOAT, offsetof(Dial, valsave), RO}, + {"wsave", T_COORD, offsetof(Dial, wsave)}, + {"winds", T_FLOAT, offsetof(Dial, winds)}, + {NULL} +}; + +struct memberlist slideroid_spec[] = { + {"mode", T_INT, offsetof(Slideroid, mode)}, + {"finemode", T_BOOL, offsetof(Slideroid, finemode)}, + {"resetmode", T_BOOL, offsetof(Slideroid, resetmode)}, + /* XXX Can't do resettarget (pointer to float) */ + /* XXX This makes resetval pretty useless... */ + /* + {"resetval", T_FLOAT, offsetof(Slideroid, resetval)}, + */ + {"valsave", T_FLOAT, offsetof(Slideroid, valsave), RO}, + {"wsave", T_COORD, offsetof(Slideroid, wsave)}, + {NULL} +}; + +struct memberlist stripchart_spec[] = { + {"firstpt", T_INT, offsetof(Stripchart, firstpt), RO}, + {"lastpt", T_INT, offsetof(Stripchart, lastpt), RO}, + {"Bind_Low", T_BOOL, offsetof(Stripchart, Bind_Low)}, + {"Bind_High", T_BOOL, offsetof(Stripchart, Bind_High)}, + /* XXX Can't do y (array of floats) */ + {"lowlabel", T_ACTUATOR, offsetof(Stripchart, lowlabel), RO}, + {"highlabel", T_ACTUATOR, offsetof(Stripchart, highlabel), RO}, + {NULL} +}; + +struct memberlist typein_spec[] = { + /* Note: these should be readonly after the actuator is added + to a panel */ + {"str", T_STRING, offsetof(Typein, str)}, + {"len", T_INT, offsetof(Typein, len)}, + {NULL} +}; + +struct memberlist typeout_spec[] = { + {"mode", T_INT, offsetof(Typeout, mode)}, + /* XXX The buffer is managed by the actuator; but how do we + add text? */ + {"buf", T_STRING, offsetof(Typeout, buf), READONLY}, + {"delimstr", T_STRING, offsetof(Typeout, delimstr)}, + {"start", T_INT, offsetof(Typeout, start)}, + {"dot", T_INT, offsetof(Typeout, dot)}, + {"mark", T_INT, offsetof(Typeout, mark)}, + {"col", T_INT, offsetof(Typeout, col)}, + {"lin", T_INT, offsetof(Typeout, lin)}, + {"len", T_INT, offsetof(Typeout, len)}, + {"size", T_INT, offsetof(Typeout, size)}, + {NULL} +}; + +struct memberlist mouse_spec[] = { + /* Actuators already have members x and y, so the Mouse's x and y + have different names */ + {"mouse_x", T_FLOAT, offsetof(Mouse, x)}, + {"mouse_y", T_FLOAT, offsetof(Mouse, y)}, + {NULL} +}; + +#define MULOFF(member) offsetof(Multislider, member) + +struct memberlist multislider_spec[] = { + {"mode", T_INT, MULOFF(mode)}, + {"n", T_INT, MULOFF(n)}, + {"finefactor", T_FLOAT, MULOFF(finefactor)}, + {"wsave", T_COORD, MULOFF(wsave)}, + {"sa", T_ACTUATOR, MULOFF(sa)}, + {"bh", T_COORD, MULOFF(bh)}, + {"clrx", T_COORD, MULOFF(clrx)}, + {"clry", T_COORD, MULOFF(clry)}, + {"clrw", T_COORD, MULOFF(clrw)}, + {"clrh", T_COORD, MULOFF(clrh)}, + /* XXX acttype? */ + {NULL} +}; + +/* XXX Still to do: + Frame + Icon + Cycle + Scroll + Menu +*/ + +/* List of known actuator initializer functions */ + +struct { + char *name; + void (*func)(); + struct memberlist *spec; +} initializerlist[] = { + {"analog_bar", pnl_analog_bar}, + {"analog_meter", pnl_analog_meter}, + {"button", pnl_button}, + {"cycle", pnl_cycle}, + /* Doesn't exist: */ +/* {"dhslider", pnl_dhslider, slider_spec}, */ + {"dial", pnl_dial, dial_spec}, + {"down_arrow_button", pnl_down_arrow_button}, + {"down_double_arrow_button", pnl_down_double_arrow_button}, + {"dvslider", pnl_dvslider, slider_spec}, + {"filled_hslider", pnl_filled_hslider, slider_spec}, + {"filled_slider", pnl_filled_slider, slider_spec}, + {"filled_vslider", pnl_filled_vslider, slider_spec}, + {"floating_puck", pnl_floating_puck, puck_spec}, + {"frame", pnl_frame}, + {"graphframe", pnl_graphframe}, + {"hmultislider", pnl_hmultislider, multislider_spec}, + {"hmultislider_bar", pnl_hmultislider_bar}, + {"hmultislider_open_bar", pnl_hmultislider_open_bar}, + {"hpalette", pnl_hpalette, palette_spec}, + {"hslider", pnl_hslider, slider_spec}, + {"icon", pnl_icon}, + {"icon_menu", pnl_icon_menu}, + {"label", pnl_label}, + {"left_arrow_button", pnl_left_arrow_button}, + {"left_double_arrow_button", pnl_left_double_arrow_button}, + {"menu", pnl_menu}, + {"menu_item", pnl_menu_item}, + {"meter", pnl_meter}, + {"mouse", pnl_mouse, mouse_spec}, + {"multislider", pnl_multislider, multislider_spec}, + {"multislider_bar", pnl_multislider_bar}, + {"multislider_open_bar", pnl_multislider_open_bar}, + {"palette", pnl_palette, palette_spec}, + {"puck", pnl_puck, puck_spec}, + {"radio_button", pnl_radio_button}, + {"radio_check_button", pnl_radio_check_button}, + {"right_arrow_button", pnl_right_arrow_button}, + {"right_double_arrow_button", pnl_right_double_arrow_button}, + {"rubber_puck", pnl_rubber_puck, puck_spec}, + {"scale_chart", pnl_scale_chart, stripchart_spec}, + {"scroll", pnl_scroll}, + {"signal", pnl_signal}, + {"slider", pnl_slider, slider_spec}, + {"slideroid", pnl_slideroid, slideroid_spec}, + {"strip_chart", pnl_strip_chart, stripchart_spec}, + {"sub_menu", pnl_sub_menu}, + {"toggle_button", pnl_toggle_button}, + {"typein", pnl_typein, typein_spec}, + {"typeout", pnl_typeout, typeout_spec}, + {"up_arrow_button", pnl_up_arrow_button}, + {"up_double_arrow_button", pnl_up_double_arrow_button}, + {"viewframe", pnl_viewframe}, + {"vmultislider", pnl_vmultislider, multislider_spec}, + {"vmultislider_bar", pnl_vmultislider_bar}, + {"vmultislider_open_bar", pnl_vmultislider_open_bar}, + {"vpalette", pnl_vpalette, palette_spec}, + {"vslider", pnl_vslider, slider_spec}, + {"wide_button", pnl_wide_button}, + {NULL, NULL} /* Sentinel */ +}; + + +/* Pseudo downfunc etc. */ + +static Actuator *down_pend, *active_pend, *up_pend; + +static void +downfunc(a) + Actuator *a; +{ + if (down_pend == NULL) + down_pend = a; +} + +static void +activefunc(a) + Actuator *a; +{ + if (active_pend == NULL) + active_pend = a; +} + +static void +upfunc(a) + Actuator *a; +{ + if (up_pend == NULL) + up_pend = a; +} + + +/* Lay-out for the user data */ + +struct userdata { + object *dict; /* Dictionary object for additional attributes */ + struct memberlist *spec; /* Actuator-specific members */ +}; + + +/* Create a new actuator; the actuator type is given as a string */ + +static Actuator * +makeactuator(name) + char *name; +{ + Actuator *act; + void (*initializer)() = NULL; + int i; + struct userdata *u; + for (i = 0; initializerlist[i].name != NULL; i++) { + if (strcmp(initializerlist[i].name, name) == 0) { + initializer = initializerlist[i].func; + break; + } + } + if (initializerlist[i].name == NULL) { + err_badarg(); + return NULL; + } + u = NEW(struct userdata, 1); + if (u == NULL) { + err_nomem(); + return NULL; + } + u->dict = NULL; + u->spec = initializerlist[i].spec; + act = pnl_mkact(initializer); + act->u = (char *)u; + act->downfunc = downfunc; + act->activefunc = activefunc; + act->upfunc = upfunc; + return act; +} + + +/* Actuator objects methods */ + +static object * +actuator_addact(self, args) + actuatorobject *self; + object *args; +{ + Panel *p; + if (!is_panelobject(args)) { + err_badarg(); + return NULL; + } + p = ((panelobject *)args) -> ob_panel; + pnl_addact(self->ob_actuator, p); + INCREF(None); + return None; +} + +static object * +actuator_addsubact(self, args) + actuatorobject *self; + object *args; +{ + Actuator *a; + if (!is_actuatorobject(args)) { + err_badarg(); + return NULL; + } + a = ((actuatorobject *)args) -> ob_actuator; + pnl_addsubact(self->ob_actuator, a); + INCREF(None); + return None; +} + +static object * +actuator_delact(self, args) + actuatorobject *self; + object *args; +{ + Panel *p; + if (!getnoarg(args)) + return NULL; + pnl_delact(self->ob_actuator); + INCREF(None); + return None; +} + +static object * +actuator_fixact(self, args) + actuatorobject *self; + object *args; +{ + Panel *p; + if (!getnoarg(args)) + return NULL; + pnl_fixact(self->ob_actuator); + INCREF(None); + return None; +} + +static object * +actuator_tprint(self, args) + actuatorobject *self; + object *args; +{ + object *str; + if (self->ob_actuator->type != PNL_TYPEOUT) { + err_setstr(TypeError, "tprint for non-typeout panel"); + return NULL; + } + if (!getstrarg(args, &str)) + return NULL; + tprint(self->ob_actuator, getstringvalue(str)); + /* XXX Can't turn tprint's errors into exceptions, sorry */ + INCREF(None); + return None; +} + +static struct methodlist actuator_methods[] = { + {"addact", actuator_addact}, + {"addsubact", actuator_addsubact}, + {"delact", actuator_delact}, + {"fixact", actuator_fixact}, + {"tprint", actuator_tprint}, + {NULL, NULL} /* sentinel */ +}; + +static object * +newactuatorobject(act) + Actuator *act; +{ + actuatorobject *a; + if (act == NULL) { + INCREF(None); + return None; + } + a = NEWOBJ(actuatorobject, &Actuatortype); + if (a == NULL) + return NULL; + a->ob_actuator = act; + return (object *)a; +} + +static void +actuator_dealloc(a) + actuatorobject *a; +{ + /* Do NOT delete the actuator; most actuator objects are created + to hold a temporary reference to an actuator, like one gotten + from pnl_dopanel(). */ + + DEL(a); +} + + +/* Table of actuator members */ + +#define ACTOFF(member) offsetof(Actuator, member) + +struct memberlist act_memberlist[] = { + {"id", T_SHORT, ACTOFF(id), READONLY}, + + /* T_PANEL is not defined */ + /* + {"p", T_PANEL, ACTOFF(p), READONLY}, + */ + + {"pa", T_ACTUATOR, ACTOFF(pa), READONLY}, + {"ca", T_ACTUATOR, ACTOFF(ca), READONLY}, + {"al", T_ACTUATOR, ACTOFF(al), READONLY}, + {"na", T_INT, ACTOFF(na), READONLY}, + {"type", T_INT, ACTOFF(type), READONLY}, + {"active", T_BOOL, ACTOFF(active)}, + + {"x", T_COORD, ACTOFF(x)}, + {"y", T_COORD, ACTOFF(y)}, + {"w", T_COORD, ACTOFF(w)}, + {"h", T_COORD, ACTOFF(h)}, + + {"lx", T_COORD, ACTOFF(lx)}, + {"ly", T_COORD, ACTOFF(ly)}, + {"lw", T_COORD, ACTOFF(lw)}, + {"lh", T_COORD, ACTOFF(lh)}, + {"ld", T_COORD, ACTOFF(ld)}, + + {"val", T_FLOAT, ACTOFF(val)}, + {"extval", T_FLOAT, ACTOFF(extval)}, + {"initval", T_FLOAT, ACTOFF(initval)}, + {"maxval", T_FLOAT, ACTOFF(maxval)}, + {"minval", T_FLOAT, ACTOFF(minval)}, + {"scalefactor", T_FLOAT, ACTOFF(scalefactor)}, + + {"label", T_STRING, ACTOFF(label)}, + {"key", T_DEVICE, ACTOFF(key)}, + {"labeltype", T_INT, ACTOFF(labeltype)}, + + /* Internal callbacks are not supported; + user callbacks are treated special! */ + + {"dirtycnt", T_INT, ACTOFF(dirtycnt)}, + + /* members u and data are accessed differently */ + + {"automatic", T_BOOL, ACTOFF(automatic)}, + {"selectable", T_BOOL, ACTOFF(selectable)}, + {"visible", T_BOOL, ACTOFF(visible)}, + {"beveled", T_BOOL, ACTOFF(beveled)}, + + {"group", T_ACTUATOR, ACTOFF(group), READONLY}, + {"next", T_ACTUATOR, ACTOFF(next), READONLY}, + + {NULL, 0, 0} /* Sentinel */ +}; + + +/* Potential name conflicts between attributes are solved as follows. + - Actuator-specific attributes always override generic attributes. + - When reading, the dictionary has overrides everything else; + when writing, everything else overrides the dictionary. + - When reading, methods are tried last. +*/ + +static object * +actuator_getattr(a, name) + actuatorobject *a; + char *name; +{ + Actuator *act = a->ob_actuator; + struct userdata *u = (struct userdata *) act->u; + object *v; + + if (u != NULL) { + /* 1. Try the dictionary */ + if (u->dict != NULL) { + v = dictlookup(u->dict, name); + if (v != NULL) { + INCREF(v); + return v; + } + } + + /* 2. Try actuator-specific attributes */ + if (u->spec != NULL) { + v = panel_getmember(act->data, u->spec, name); + if (v != NULL) + return v; + err_clear(); + } + } + + /* 3. Try generic actuator attributes */ + v = panel_getmember((char *)act, act_memberlist, name); + if (v != NULL) + return v; + + /* 4. Try methods */ + err_clear(); + return findmethod(actuator_methods, (object *)a, name); +} + +static int +actuator_setattr(a, name, v) + actuatorobject *a; + char *name; + object *v; +{ + Actuator *act = a->ob_actuator; + struct userdata *u = (struct userdata *) act->u; + int err; + + /* 0. We don't allow deletion of attributes */ + if (v == NULL) { + err_setstr(TypeError, "read-only actuator attribute"); + return -1; + } + + /* 1. Try actuator-specific attributes */ + if (u != NULL && u->spec != NULL) { + err = panel_setmember(act->data, u->spec, name, v); + if (err != 1) + return err; + } + + /* 2. Try generic actuator attributes */ + err = panel_setmember((char *)act, act_memberlist, name, v); + if (err != 1) + return err; + + /* 3. Try the dictionary */ + if (u != NULL) { + if (u->dict == NULL && (u->dict = newdictobject()) == NULL) + return NULL; + return dictinsert(u->dict, name, v); + } + + err_setstr(NameError, name); + return -1; +} + +static int +actuator_compare(v, w) + actuatorobject *v, *w; +{ + long i = (long)v->ob_actuator; + long j = (long)w->ob_actuator; + return (i < j) ? -1 : (i > j) ? 1 : 0; +} + +static typeobject Actuatortype = { + OB_HEAD_INIT(&Typetype) + 0, /*ob_size*/ + "actuator", /*tp_name*/ + sizeof(actuatorobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + actuator_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + actuator_getattr, /*tp_getattr*/ + actuator_setattr, /*tp_setattr*/ + actuator_compare, /*tp_compare*/ + 0, /*tp_repr*/ +}; + + +/* The panel module itself */ + +static object * +module_mkpanel(self, args) + object *self; + object *args; +{ + if (!getnoarg(args)) + return NULL; + return newpanelobject(); +} + +static object * +module_mkact(self, args) + object *self; + object *args; +{ + object *v; + Actuator *a; + if (!getstrarg(args, &v)) + return NULL; + a = makeactuator(getstringvalue(v)); + if (a == NULL) + return NULL; + return newactuatorobject(a); +} + +static object * +module_dopanel(self, args) + object *self; + object *args; +{ + Actuator *a; + object *v, *w; + if (!getnoarg(args)) + return NULL; + a = pnl_dopanel(); + v = newtupleobject(4); + if (v == NULL) + return NULL; + settupleitem(v, 0, newactuatorobject(a)); + settupleitem(v, 1, newactuatorobject(down_pend)); + settupleitem(v, 2, newactuatorobject(active_pend)); + settupleitem(v, 3, newactuatorobject(up_pend)); + down_pend = active_pend = up_pend = NULL; + return v; +} + +static object * +module_drawpanel(self, args) + object *self; + object *args; +{ + if (!getnoarg(args)) + return NULL; + pnl_drawpanel(); + INCREF(None); + return None; +} + +static object * +module_needredraw(self, args) + object *self; + object *args; +{ + if (!getnoarg(args)) + return NULL; + pnl_needredraw(); + INCREF(None); + return None; +} + +static object * +module_userredraw(self, args) + object *self; + object *args; +{ + short wid; + if (!getnoarg(args)) + return NULL; + wid = pnl_userredraw(); + return newintobject((long)wid); +} + +static object * +module_block(self, args) + object *self; + object *args; +{ + int flag; + if (!getintarg(args, &flag)) + return NULL; + pnl_block = flag; + INCREF(None); + return None; +} + +static struct methodlist module_methods[] = { + {"block", module_block}, + {"dopanel", module_dopanel}, + {"drawpanel", module_drawpanel}, + {"mkpanel", module_mkpanel}, + {"mkact", module_mkact}, + {"needredraw", module_needredraw}, + {"userredraw", module_userredraw}, + {NULL, NULL} /* sentinel */ +}; + +void +initpanel() +{ + /* Setting pnl_block to 1 would greatly reduce the CPU usage + of an idle application. Unfortunately it also breaks our + little hacks to get callback functions in Python called. + So we clear pnl_block here. You can set/clear pnl_block + from Python using pnl.block(flag). It works if you have + no upfuncs. */ + pnl_block = 0; + initmodule("pnl", module_methods); +} diff --git a/src/parser.c b/src/parser.c new file mode 100644 index 0000000..8ee7e2c --- /dev/null +++ b/src/parser.c @@ -0,0 +1,423 @@ +/*********************************************************** +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 implementation */ + +/* For a description, see the comments at end of this file */ + +/* XXX To do: error recovery */ + +#include "pgenheaders.h" +#include "assert.h" +#include "token.h" +#include "grammar.h" +#include "node.h" +#include "parser.h" +#include "errcode.h" + + +#ifdef DEBUG +extern int debugging; +#define D(x) if (!debugging); else x +#else +#define D(x) +#endif + + +/* STACK DATA TYPE */ + +static void s_reset PROTO((stack *)); + +static void +s_reset(s) + stack *s; +{ + s->s_top = &s->s_base[MAXSTACK]; +} + +#define s_empty(s) ((s)->s_top == &(s)->s_base[MAXSTACK]) + +static int s_push PROTO((stack *, dfa *, node *)); + +static int +s_push(s, d, parent) + register stack *s; + dfa *d; + node *parent; +{ + register stackentry *top; + if (s->s_top == s->s_base) { + fprintf(stderr, "s_push: parser stack overflow\n"); + return -1; + } + top = --s->s_top; + top->s_dfa = d; + top->s_parent = parent; + top->s_state = 0; + return 0; +} + +#ifdef DEBUG + +static void s_pop PROTO((stack *)); + +static void +s_pop(s) + register stack *s; +{ + if (s_empty(s)) { + fprintf(stderr, "s_pop: parser stack underflow -- FATAL\n"); + abort(); + } + s->s_top++; +} + +#else /* !DEBUG */ + +#define s_pop(s) (s)->s_top++ + +#endif + + +/* PARSER CREATION */ + +parser_state * +newparser(g, start) + grammar *g; + int start; +{ + parser_state *ps; + + if (!g->g_accel) + addaccelerators(g); + ps = NEW(parser_state, 1); + if (ps == NULL) + return NULL; + ps->p_grammar = g; + ps->p_tree = newtree(start); + if (ps->p_tree == NULL) { + DEL(ps); + return NULL; + } + s_reset(&ps->p_stack); + (void) s_push(&ps->p_stack, finddfa(g, start), ps->p_tree); + return ps; +} + +void +delparser(ps) + parser_state *ps; +{ + /* NB If you want to save the parse tree, + you must set p_tree to NULL before calling delparser! */ + freetree(ps->p_tree); + DEL(ps); +} + + +/* PARSER STACK OPERATIONS */ + +static int shift PROTO((stack *, int, char *, int, int)); + +static int +shift(s, type, str, newstate, lineno) + register stack *s; + int type; + char *str; + int newstate; + int lineno; +{ + assert(!s_empty(s)); + if (addchild(s->s_top->s_parent, type, str, lineno) == NULL) { + fprintf(stderr, "shift: no mem in addchild\n"); + return -1; + } + s->s_top->s_state = newstate; + return 0; +} + +static int push PROTO((stack *, int, dfa *, int, int)); + +static int +push(s, type, d, newstate, lineno) + register stack *s; + int type; + dfa *d; + int newstate; + int lineno; +{ + register node *n; + n = s->s_top->s_parent; + assert(!s_empty(s)); + if (addchild(n, type, (char *)NULL, lineno) == NULL) { + fprintf(stderr, "push: no mem in addchild\n"); + return -1; + } + s->s_top->s_state = newstate; + return s_push(s, d, CHILD(n, NCH(n)-1)); +} + + +/* PARSER PROPER */ + +static int classify PROTO((grammar *, int, char *)); + +static int +classify(g, type, str) + grammar *g; + register int type; + char *str; +{ + register int n = g->g_ll.ll_nlabels; + + if (type == NAME) { + register char *s = str; + register label *l = g->g_ll.ll_label; + register int i; + for (i = n; i > 0; i--, l++) { + if (l->lb_type == NAME && l->lb_str != NULL && + l->lb_str[0] == s[0] && + strcmp(l->lb_str, s) == 0) { + D(printf("It's a keyword\n")); + return n - i; + } + } + } + + { + register label *l = g->g_ll.ll_label; + register int i; + for (i = n; i > 0; i--, l++) { + if (l->lb_type == type && l->lb_str == NULL) { + D(printf("It's a token we know\n")); + return n - i; + } + } + } + + D(printf("Illegal token\n")); + return -1; +} + +int +addtoken(ps, type, str, lineno) + register parser_state *ps; + register int type; + char *str; + int lineno; +{ + register int ilabel; + + D(printf("Token %s/'%s' ... ", tok_name[type], str)); + + /* Find out which label this token is */ + ilabel = classify(ps->p_grammar, type, str); + if (ilabel < 0) + return E_SYNTAX; + + /* Loop until the token is shifted or an error occurred */ + for (;;) { + /* Fetch the current dfa and state */ + register dfa *d = ps->p_stack.s_top->s_dfa; + register state *s = &d->d_state[ps->p_stack.s_top->s_state]; + + D(printf(" DFA '%s', state %d:", + d->d_name, ps->p_stack.s_top->s_state)); + + /* Check accelerator */ + if (s->s_lower <= ilabel && ilabel < s->s_upper) { + register int x = s->s_accel[ilabel - s->s_lower]; + if (x != -1) { + if (x & (1<<7)) { + /* Push non-terminal */ + int nt = (x >> 8) + NT_OFFSET; + int arrow = x & ((1<<7)-1); + dfa *d1 = finddfa(ps->p_grammar, nt); + if (push(&ps->p_stack, nt, d1, + arrow, lineno) < 0) { + D(printf(" MemError: push.\n")); + return E_NOMEM; + } + D(printf(" Push ...\n")); + continue; + } + + /* Shift the token */ + if (shift(&ps->p_stack, type, str, + x, lineno) < 0) { + D(printf(" MemError: shift.\n")); + return E_NOMEM; + } + D(printf(" Shift.\n")); + /* Pop while we are in an accept-only state */ + while (s = &d->d_state + [ps->p_stack.s_top->s_state], + s->s_accept && s->s_narcs == 1) { + D(printf(" Direct pop.\n")); + s_pop(&ps->p_stack); + if (s_empty(&ps->p_stack)) { + D(printf(" ACCEPT.\n")); + return E_DONE; + } + d = ps->p_stack.s_top->s_dfa; + } + return E_OK; + } + } + + if (s->s_accept) { + /* Pop this dfa and try again */ + s_pop(&ps->p_stack); + D(printf(" Pop ...\n")); + if (s_empty(&ps->p_stack)) { + D(printf(" Error: bottom of stack.\n")); + return E_SYNTAX; + } + continue; + } + + /* Stuck, report syntax error */ + D(printf(" Error.\n")); + return E_SYNTAX; + } +} + + +#ifdef DEBUG + +/* DEBUG OUTPUT */ + +void +dumptree(g, n) + grammar *g; + node *n; +{ + int i; + + if (n == NULL) + printf("NIL"); + else { + label l; + l.lb_type = TYPE(n); + l.lb_str = TYPE(str); + printf("%s", labelrepr(&l)); + if (ISNONTERMINAL(TYPE(n))) { + printf("("); + for (i = 0; i < NCH(n); i++) { + if (i > 0) + printf(","); + dumptree(g, CHILD(n, i)); + } + printf(")"); + } + } +} + +void +showtree(g, n) + grammar *g; + node *n; +{ + int i; + + if (n == NULL) + return; + if (ISNONTERMINAL(TYPE(n))) { + for (i = 0; i < NCH(n); i++) + showtree(g, CHILD(n, i)); + } + else if (ISTERMINAL(TYPE(n))) { + printf("%s", tok_name[TYPE(n)]); + if (TYPE(n) == NUMBER || TYPE(n) == NAME) + printf("(%s)", STR(n)); + printf(" "); + } + else + printf("? "); +} + +void +printtree(ps) + parser_state *ps; +{ + if (debugging) { + printf("Parse tree:\n"); + dumptree(ps->p_grammar, ps->p_tree); + printf("\n"); + printf("Tokens:\n"); + showtree(ps->p_grammar, ps->p_tree); + printf("\n"); + } + printf("Listing:\n"); + listtree(ps->p_tree); + printf("\n"); +} + +#endif /* DEBUG */ + +/* + +Description +----------- + +The parser's interface is different than usual: the function addtoken() +must be called for each token in the input. This makes it possible to +turn it into an incremental parsing system later. The parsing system +constructs a parse tree as it goes. + +A parsing rule is represented as a Deterministic Finite-state Automaton +(DFA). A node in a DFA represents a state of the parser; an arc represents +a transition. Transitions are either labeled with terminal symbols or +with non-terminals. When the parser decides to follow an arc labeled +with a non-terminal, it is invoked recursively with the DFA representing +the parsing rule for that as its initial state; when that DFA accepts, +the parser that invoked it continues. The parse tree constructed by the +recursively called parser is inserted as a child in the current parse tree. + +The DFA's can be constructed automatically from a more conventional +language description. An extended LL(1) grammar (ELL(1)) is suitable. +Certain restrictions make the parser's life easier: rules that can produce +the empty string should be outlawed (there are other ways to put loops +or optional parts in the language). To avoid the need to construct +FIRST sets, we can require that all but the last alternative of a rule +(really: arc going out of a DFA's state) must begin with a terminal +symbol. + +As an example, consider this grammar: + +expr: term (OP term)* +term: CONSTANT | '(' expr ')' + +The DFA corresponding to the rule for expr is: + +------->.---term-->.-------> + ^ | + | | + \----OP----/ + +The parse tree generated for the input a+b is: + +(expr: (term: (NAME: a)), (OP: +), (term: (NAME: b))) + +*/ diff --git a/src/parser.h b/src/parser.h new file mode 100644 index 0000000..3e8090a --- /dev/null +++ b/src/parser.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. + +******************************************************************/ + +/* Parser interface */ + +#define MAXSTACK 100 + +typedef struct _stackentry { + int s_state; /* State in current DFA */ + dfa *s_dfa; /* Current DFA */ + struct _node *s_parent; /* Where to add next node */ +} stackentry; + +typedef struct _stack { + stackentry *s_top; /* Top entry */ + stackentry s_base[MAXSTACK];/* Array of stack entries */ + /* NB The stack grows down */ +} stack; + +typedef struct { + struct _stack p_stack; /* Stack of parser states */ + struct _grammar *p_grammar; /* Grammar to use */ + struct _node *p_tree; /* Top of parse tree */ +} parser_state; + +parser_state *newparser PROTO((struct _grammar *g, int start)); +void delparser PROTO((parser_state *ps)); +int addtoken PROTO((parser_state *ps, int type, char *str, int lineno)); +void addaccelerators PROTO((grammar *g)); diff --git a/src/parsetok.c b/src/parsetok.c new file mode 100644 index 0000000..e19a979 --- /dev/null +++ b/src/parsetok.c @@ -0,0 +1,158 @@ +/*********************************************************** +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-tokenizer link implementation */ + +#include "pgenheaders.h" +#include "tokenizer.h" +#include "node.h" +#include "grammar.h" +#include "parser.h" +#include "parsetok.h" +#include "errcode.h" + + +/* Forward */ +static int parsetok PROTO((struct tok_state *, grammar *, int, node **)); + + +/* Parse input coming from a string. Return error code, print some errors. */ + +int +parsestring(s, g, start, n_ret) + char *s; + grammar *g; + int start; + node **n_ret; +{ + struct tok_state *tok = tok_setups(s); + int ret; + + if (tok == NULL) { + fprintf(stderr, "no mem for tok_setups\n"); + return E_NOMEM; + } + ret = parsetok(tok, g, start, n_ret); + if (ret == E_TOKEN || ret == E_SYNTAX) { + fprintf(stderr, "String parsing error at line %d\n", + tok->lineno); + } + tok_free(tok); + return ret; +} + + +/* Parse input coming from a file. Return error code, print some errors. */ + +int +parsefile(fp, filename, g, start, ps1, ps2, n_ret) + FILE *fp; + char *filename; + grammar *g; + int start; + char *ps1, *ps2; + node **n_ret; +{ + struct tok_state *tok = tok_setupf(fp, ps1, ps2); + int ret; + + if (tok == NULL) { + fprintf(stderr, "no mem for tok_setupf\n"); + return E_NOMEM; + } + ret = parsetok(tok, g, start, n_ret); + if (ret == E_TOKEN || ret == E_SYNTAX) { + char *p; + fprintf(stderr, "Parsing error: file %s, line %d:\n", + filename, tok->lineno); + *tok->inp = '\0'; + if (tok->inp > tok->buf && tok->inp[-1] == '\n') + tok->inp[-1] = '\0'; + fprintf(stderr, "%s\n", tok->buf); + for (p = tok->buf; p < tok->cur; p++) { + if (*p == '\t') + putc('\t', stderr); + else + putc(' ', stderr); + } + fprintf(stderr, "^\n"); + } + tok_free(tok); + return ret; +} + + +/* Parse input coming from the given tokenizer structure. + Return error code. */ + +static int +parsetok(tok, g, start, n_ret) + struct tok_state *tok; + grammar *g; + int start; + node **n_ret; +{ + parser_state *ps; + int ret; + + if ((ps = newparser(g, start)) == NULL) { + fprintf(stderr, "no mem for new parser\n"); + return E_NOMEM; + } + + for (;;) { + char *a, *b; + int type; + int len; + char *str; + + type = tok_get(tok, &a, &b); + if (type == ERRORTOKEN) { + ret = tok->done; + break; + } + len = b - a; + str = NEW(char, len + 1); + if (str == NULL) { + fprintf(stderr, "no mem for next token\n"); + ret = E_NOMEM; + break; + } + strncpy(str, a, len); + str[len] = '\0'; + ret = addtoken(ps, (int)type, str, tok->lineno); + if (ret != E_OK) { + if (ret == E_DONE) { + *n_ret = ps->p_tree; + ps->p_tree = NULL; + } + else if (tok->lineno <= 1 && tok->done == E_EOF) + ret = E_EOF; + break; + } + } + + delparser(ps); + return ret; +} diff --git a/src/parsetok.h b/src/parsetok.h new file mode 100644 index 0000000..e05fdb5 --- /dev/null +++ b/src/parsetok.h @@ -0,0 +1,29 @@ +/*********************************************************** +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-tokenizer link interface */ + +extern int parsestring PROTO((char *, grammar *, int start, node **n_ret)); +extern int parsefile PROTO((FILE *, char *, grammar *, int start, + char *ps1, char *ps2, node **n_ret)); diff --git a/src/patchlevel.h b/src/patchlevel.h new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/src/patchlevel.h @@ -0,0 +1 @@ +1 diff --git a/src/pgen.c b/src/pgen.c new file mode 100644 index 0000000..6d3ecaf --- /dev/null +++ b/src/pgen.c @@ -0,0 +1,751 @@ +/*********************************************************** +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 generator */ +/* XXX This file is not yet fully PROTOized */ + +/* For a description, see the comments at end of this file */ + +#include "pgenheaders.h" +#include "assert.h" +#include "token.h" +#include "node.h" +#include "grammar.h" +#include "metagrammar.h" +#include "pgen.h" + +extern int debugging; + + +/* PART ONE -- CONSTRUCT NFA -- Cf. Algorithm 3.2 from [Aho&Ullman 77] */ + +typedef struct _nfaarc { + int ar_label; + int ar_arrow; +} nfaarc; + +typedef struct _nfastate { + int st_narcs; + nfaarc *st_arc; +} nfastate; + +typedef struct _nfa { + int nf_type; + char *nf_name; + int nf_nstates; + nfastate *nf_state; + int nf_start, nf_finish; +} nfa; + +static int +addnfastate(nf) + nfa *nf; +{ + nfastate *st; + + RESIZE(nf->nf_state, nfastate, nf->nf_nstates + 1); + if (nf->nf_state == NULL) + fatal("out of mem"); + st = &nf->nf_state[nf->nf_nstates++]; + st->st_narcs = 0; + st->st_arc = NULL; + return st - nf->nf_state; +} + +static void +addnfaarc(nf, from, to, lbl) + nfa *nf; + int from, to, lbl; +{ + nfastate *st; + nfaarc *ar; + + st = &nf->nf_state[from]; + RESIZE(st->st_arc, nfaarc, st->st_narcs + 1); + if (st->st_arc == NULL) + fatal("out of mem"); + ar = &st->st_arc[st->st_narcs++]; + ar->ar_label = lbl; + ar->ar_arrow = to; +} + +static nfa * +newnfa(name) + char *name; +{ + nfa *nf; + static type = NT_OFFSET; /* All types will be disjunct */ + + nf = NEW(nfa, 1); + if (nf == NULL) + fatal("no mem for new nfa"); + nf->nf_type = type++; + nf->nf_name = name; /* XXX strdup(name) ??? */ + nf->nf_nstates = 0; + nf->nf_state = NULL; + nf->nf_start = nf->nf_finish = -1; + return nf; +} + +typedef struct _nfagrammar { + int gr_nnfas; + nfa **gr_nfa; + labellist gr_ll; +} nfagrammar; + +static nfagrammar * +newnfagrammar() +{ + nfagrammar *gr; + + gr = NEW(nfagrammar, 1); + if (gr == NULL) + fatal("no mem for new nfa grammar"); + gr->gr_nnfas = 0; + gr->gr_nfa = NULL; + gr->gr_ll.ll_nlabels = 0; + gr->gr_ll.ll_label = NULL; + addlabel(&gr->gr_ll, ENDMARKER, "EMPTY"); + return gr; +} + +static nfa * +addnfa(gr, name) + nfagrammar *gr; + char *name; +{ + nfa *nf; + + nf = newnfa(name); + RESIZE(gr->gr_nfa, nfa *, gr->gr_nnfas + 1); + if (gr->gr_nfa == NULL) + fatal("out of mem"); + gr->gr_nfa[gr->gr_nnfas++] = nf; + addlabel(&gr->gr_ll, NAME, nf->nf_name); + return nf; +} + +#ifdef DEBUG + +static char REQNFMT[] = "metacompile: less than %d children\n"; + +#define REQN(i, count) \ + if (i < count) { \ + fprintf(stderr, REQNFMT, count); \ + abort(); \ + } else + +#else +#define REQN(i, count) /* empty */ +#endif + +static nfagrammar * +metacompile(n) + node *n; +{ + nfagrammar *gr; + int i; + + printf("Compiling (meta-) parse tree into NFA grammar\n"); + gr = newnfagrammar(); + REQ(n, MSTART); + i = n->n_nchildren - 1; /* Last child is ENDMARKER */ + n = n->n_child; + for (; --i >= 0; n++) { + if (n->n_type != NEWLINE) + compile_rule(gr, n); + } + return gr; +} + +static +compile_rule(gr, n) + nfagrammar *gr; + node *n; +{ + nfa *nf; + + REQ(n, RULE); + REQN(n->n_nchildren, 4); + n = n->n_child; + REQ(n, NAME); + nf = addnfa(gr, n->n_str); + n++; + REQ(n, COLON); + n++; + REQ(n, RHS); + compile_rhs(&gr->gr_ll, nf, n, &nf->nf_start, &nf->nf_finish); + n++; + REQ(n, NEWLINE); +} + +static +compile_rhs(ll, nf, n, pa, pb) + labellist *ll; + nfa *nf; + node *n; + int *pa, *pb; +{ + int i; + int a, b; + + REQ(n, RHS); + i = n->n_nchildren; + REQN(i, 1); + n = n->n_child; + REQ(n, ALT); + compile_alt(ll, nf, n, pa, pb); + if (--i <= 0) + return; + n++; + a = *pa; + b = *pb; + *pa = addnfastate(nf); + *pb = addnfastate(nf); + addnfaarc(nf, *pa, a, EMPTY); + addnfaarc(nf, b, *pb, EMPTY); + for (; --i >= 0; n++) { + REQ(n, VBAR); + REQN(i, 1); + --i; + n++; + REQ(n, ALT); + compile_alt(ll, nf, n, &a, &b); + addnfaarc(nf, *pa, a, EMPTY); + addnfaarc(nf, b, *pb, EMPTY); + } +} + +static +compile_alt(ll, nf, n, pa, pb) + labellist *ll; + nfa *nf; + node *n; + int *pa, *pb; +{ + int i; + int a, b; + + REQ(n, ALT); + i = n->n_nchildren; + REQN(i, 1); + n = n->n_child; + REQ(n, ITEM); + compile_item(ll, nf, n, pa, pb); + --i; + n++; + for (; --i >= 0; n++) { + if (n->n_type == COMMA) { /* XXX Temporary */ + REQN(i, 1); + --i; + n++; + } + REQ(n, ITEM); + compile_item(ll, nf, n, &a, &b); + addnfaarc(nf, *pb, a, EMPTY); + *pb = b; + } +} + +static +compile_item(ll, nf, n, pa, pb) + labellist *ll; + nfa *nf; + node *n; + int *pa, *pb; +{ + int i; + int a, b; + + REQ(n, ITEM); + i = n->n_nchildren; + REQN(i, 1); + n = n->n_child; + if (n->n_type == LSQB) { + REQN(i, 3); + n++; + REQ(n, RHS); + *pa = addnfastate(nf); + *pb = addnfastate(nf); + addnfaarc(nf, *pa, *pb, EMPTY); + compile_rhs(ll, nf, n, &a, &b); + addnfaarc(nf, *pa, a, EMPTY); + addnfaarc(nf, b, *pb, EMPTY); + REQN(i, 1); + n++; + REQ(n, RSQB); + } + else { + compile_atom(ll, nf, n, pa, pb); + if (--i <= 0) + return; + n++; + addnfaarc(nf, *pb, *pa, EMPTY); + if (n->n_type == STAR) + *pb = *pa; + else + REQ(n, PLUS); + } +} + +static +compile_atom(ll, nf, n, pa, pb) + labellist *ll; + nfa *nf; + node *n; + int *pa, *pb; +{ + int i; + + REQ(n, ATOM); + i = n->n_nchildren; + REQN(i, 1); + n = n->n_child; + if (n->n_type == LPAR) { + REQN(i, 3); + n++; + REQ(n, RHS); + compile_rhs(ll, nf, n, pa, pb); + n++; + REQ(n, RPAR); + } + else if (n->n_type == NAME || n->n_type == STRING) { + *pa = addnfastate(nf); + *pb = addnfastate(nf); + addnfaarc(nf, *pa, *pb, addlabel(ll, n->n_type, n->n_str)); + } + else + REQ(n, NAME); +} + +static void +dumpstate(ll, nf, istate) + labellist *ll; + nfa *nf; + int istate; +{ + nfastate *st; + int i; + nfaarc *ar; + + printf("%c%2d%c", + istate == nf->nf_start ? '*' : ' ', + istate, + istate == nf->nf_finish ? '.' : ' '); + st = &nf->nf_state[istate]; + ar = st->st_arc; + for (i = 0; i < st->st_narcs; i++) { + if (i > 0) + printf("\n "); + printf("-> %2d %s", ar->ar_arrow, + labelrepr(&ll->ll_label[ar->ar_label])); + ar++; + } + printf("\n"); +} + +static void +dumpnfa(ll, nf) + labellist *ll; + nfa *nf; +{ + int i; + + printf("NFA '%s' has %d states; start %d, finish %d\n", + nf->nf_name, nf->nf_nstates, nf->nf_start, nf->nf_finish); + for (i = 0; i < nf->nf_nstates; i++) + dumpstate(ll, nf, i); +} + + +/* PART TWO -- CONSTRUCT DFA -- Algorithm 3.1 from [Aho&Ullman 77] */ + +static int +addclosure(ss, nf, istate) + bitset ss; + nfa *nf; + int istate; +{ + if (addbit(ss, istate)) { + nfastate *st = &nf->nf_state[istate]; + nfaarc *ar = st->st_arc; + int i; + + for (i = st->st_narcs; --i >= 0; ) { + if (ar->ar_label == EMPTY) + addclosure(ss, nf, ar->ar_arrow); + ar++; + } + } +} + +typedef struct _ss_arc { + bitset sa_bitset; + int sa_arrow; + int sa_label; +} ss_arc; + +typedef struct _ss_state { + bitset ss_ss; + int ss_narcs; + ss_arc *ss_arc; + int ss_deleted; + int ss_finish; + int ss_rename; +} ss_state; + +typedef struct _ss_dfa { + int sd_nstates; + ss_state *sd_state; +} ss_dfa; + +static +makedfa(gr, nf, d) + nfagrammar *gr; + nfa *nf; + dfa *d; +{ + int nbits = nf->nf_nstates; + bitset ss; + int xx_nstates; + ss_state *xx_state, *yy; + ss_arc *zz; + int istate, jstate, iarc, jarc, ibit; + nfastate *st; + nfaarc *ar; + + ss = newbitset(nbits); + addclosure(ss, nf, nf->nf_start); + xx_state = NEW(ss_state, 1); + if (xx_state == NULL) + fatal("no mem for xx_state in makedfa"); + xx_nstates = 1; + yy = &xx_state[0]; + yy->ss_ss = ss; + yy->ss_narcs = 0; + yy->ss_arc = NULL; + yy->ss_deleted = 0; + yy->ss_finish = testbit(ss, nf->nf_finish); + if (yy->ss_finish) + printf("Error: nonterminal '%s' may produce empty.\n", + nf->nf_name); + + /* This algorithm is from a book written before + the invention of structured programming... */ + + /* For each unmarked state... */ + for (istate = 0; istate < xx_nstates; ++istate) { + yy = &xx_state[istate]; + ss = yy->ss_ss; + /* For all its states... */ + for (ibit = 0; ibit < nf->nf_nstates; ++ibit) { + if (!testbit(ss, ibit)) + continue; + st = &nf->nf_state[ibit]; + /* For all non-empty arcs from this state... */ + for (iarc = 0; iarc < st->st_narcs; iarc++) { + ar = &st->st_arc[iarc]; + if (ar->ar_label == EMPTY) + continue; + /* Look up in list of arcs from this state */ + for (jarc = 0; jarc < yy->ss_narcs; ++jarc) { + zz = &yy->ss_arc[jarc]; + if (ar->ar_label == zz->sa_label) + goto found; + } + /* Add new arc for this state */ + RESIZE(yy->ss_arc, ss_arc, yy->ss_narcs + 1); + if (yy->ss_arc == NULL) + fatal("out of mem"); + zz = &yy->ss_arc[yy->ss_narcs++]; + zz->sa_label = ar->ar_label; + zz->sa_bitset = newbitset(nbits); + zz->sa_arrow = -1; + found: ; + /* Add destination */ + addclosure(zz->sa_bitset, nf, ar->ar_arrow); + } + } + /* Now look up all the arrow states */ + for (jarc = 0; jarc < xx_state[istate].ss_narcs; jarc++) { + zz = &xx_state[istate].ss_arc[jarc]; + for (jstate = 0; jstate < xx_nstates; jstate++) { + if (samebitset(zz->sa_bitset, + xx_state[jstate].ss_ss, nbits)) { + zz->sa_arrow = jstate; + goto done; + } + } + RESIZE(xx_state, ss_state, xx_nstates + 1); + if (xx_state == NULL) + fatal("out of mem"); + zz->sa_arrow = xx_nstates; + yy = &xx_state[xx_nstates++]; + yy->ss_ss = zz->sa_bitset; + yy->ss_narcs = 0; + yy->ss_arc = NULL; + yy->ss_deleted = 0; + yy->ss_finish = testbit(yy->ss_ss, nf->nf_finish); + done: ; + } + } + + if (debugging) + printssdfa(xx_nstates, xx_state, nbits, &gr->gr_ll, + "before minimizing"); + + simplify(xx_nstates, xx_state); + + if (debugging) + printssdfa(xx_nstates, xx_state, nbits, &gr->gr_ll, + "after minimizing"); + + convert(d, xx_nstates, xx_state); + + /* XXX cleanup */ +} + +static +printssdfa(xx_nstates, xx_state, nbits, ll, msg) + int xx_nstates; + ss_state *xx_state; + int nbits; + labellist *ll; + char *msg; +{ + int i, ibit, iarc; + ss_state *yy; + ss_arc *zz; + + printf("Subset DFA %s\n", msg); + for (i = 0; i < xx_nstates; i++) { + yy = &xx_state[i]; + if (yy->ss_deleted) + continue; + printf(" Subset %d", i); + if (yy->ss_finish) + printf(" (finish)"); + printf(" { "); + for (ibit = 0; ibit < nbits; ibit++) { + if (testbit(yy->ss_ss, ibit)) + printf("%d ", ibit); + } + printf("}\n"); + for (iarc = 0; iarc < yy->ss_narcs; iarc++) { + zz = &yy->ss_arc[iarc]; + printf(" Arc to state %d, label %s\n", + zz->sa_arrow, + labelrepr(&ll->ll_label[zz->sa_label])); + } + } +} + + +/* PART THREE -- SIMPLIFY DFA */ + +/* Simplify the DFA by repeatedly eliminating states that are + equivalent to another oner. This is NOT Algorithm 3.3 from + [Aho&Ullman 77]. It does not always finds the minimal DFA, + but it does usually make a much smaller one... (For an example + of sub-optimal behaviour, try S: x a b+ | y a b+.) +*/ + +static int +samestate(s1, s2) + ss_state *s1, *s2; +{ + int i; + + if (s1->ss_narcs != s2->ss_narcs || s1->ss_finish != s2->ss_finish) + return 0; + for (i = 0; i < s1->ss_narcs; i++) { + if (s1->ss_arc[i].sa_arrow != s2->ss_arc[i].sa_arrow || + s1->ss_arc[i].sa_label != s2->ss_arc[i].sa_label) + return 0; + } + return 1; +} + +static void +renamestates(xx_nstates, xx_state, from, to) + int xx_nstates; + ss_state *xx_state; + int from, to; +{ + int i, j; + + if (debugging) + printf("Rename state %d to %d.\n", from, to); + for (i = 0; i < xx_nstates; i++) { + if (xx_state[i].ss_deleted) + continue; + for (j = 0; j < xx_state[i].ss_narcs; j++) { + if (xx_state[i].ss_arc[j].sa_arrow == from) + xx_state[i].ss_arc[j].sa_arrow = to; + } + } +} + +static +simplify(xx_nstates, xx_state) + int xx_nstates; + ss_state *xx_state; +{ + int changes; + int i, j, k; + + do { + changes = 0; + for (i = 1; i < xx_nstates; i++) { + if (xx_state[i].ss_deleted) + continue; + for (j = 0; j < i; j++) { + if (xx_state[j].ss_deleted) + continue; + if (samestate(&xx_state[i], &xx_state[j])) { + xx_state[i].ss_deleted++; + renamestates(xx_nstates, xx_state, i, j); + changes++; + break; + } + } + } + } while (changes); +} + + +/* PART FOUR -- GENERATE PARSING TABLES */ + +/* Convert the DFA into a grammar that can be used by our parser */ + +static +convert(d, xx_nstates, xx_state) + dfa *d; + int xx_nstates; + ss_state *xx_state; +{ + int i, j; + ss_state *yy; + ss_arc *zz; + + for (i = 0; i < xx_nstates; i++) { + yy = &xx_state[i]; + if (yy->ss_deleted) + continue; + yy->ss_rename = addstate(d); + } + + for (i = 0; i < xx_nstates; i++) { + yy = &xx_state[i]; + if (yy->ss_deleted) + continue; + for (j = 0; j < yy->ss_narcs; j++) { + zz = &yy->ss_arc[j]; + addarc(d, yy->ss_rename, + xx_state[zz->sa_arrow].ss_rename, + zz->sa_label); + } + if (yy->ss_finish) + addarc(d, yy->ss_rename, yy->ss_rename, 0); + } + + d->d_initial = 0; +} + + +/* PART FIVE -- GLUE IT ALL TOGETHER */ + +static grammar * +maketables(gr) + nfagrammar *gr; +{ + int i; + nfa *nf; + dfa *d; + grammar *g; + + if (gr->gr_nnfas == 0) + return NULL; + g = newgrammar(gr->gr_nfa[0]->nf_type); + /* XXX first rule must be start rule */ + g->g_ll = gr->gr_ll; + + for (i = 0; i < gr->gr_nnfas; i++) { + nf = gr->gr_nfa[i]; + if (debugging) { + printf("Dump of NFA for '%s' ...\n", nf->nf_name); + dumpnfa(&gr->gr_ll, nf); + } + printf("Making DFA for '%s' ...\n", nf->nf_name); + d = adddfa(g, nf->nf_type, nf->nf_name); + makedfa(gr, gr->gr_nfa[i], d); + } + + return g; +} + +grammar * +pgen(n) + node *n; +{ + nfagrammar *gr; + grammar *g; + + gr = metacompile(n); + g = maketables(gr); + translatelabels(g); + addfirstsets(g); + return g; +} + + +/* + +Description +----------- + +Input is a grammar in extended BNF (using * for repetition, + for +at-least-once repetition, [] for optional parts, | for alternatives and +() for grouping). This has already been parsed and turned into a parse +tree. + +Each rule is considered as a regular expression in its own right. +It is turned into a Non-deterministic Finite Automaton (NFA), which +is then turned into a Deterministic Finite Automaton (DFA), which is then +optimized to reduce the number of states. See [Aho&Ullman 77] chapter 3, +or similar compiler books (this technique is more often used for lexical +analyzers). + +The DFA's are used by the parser as parsing tables in a special way +that's probably unique. Before they are usable, the FIRST sets of all +non-terminals are computed. + +Reference +--------- + +[Aho&Ullman 77] + Aho&Ullman, Principles of Compiler Design, Addison-Wesley 1977 + (first edition) + +*/ diff --git a/src/pgen.h b/src/pgen.h new file mode 100644 index 0000000..940bf9a --- /dev/null +++ b/src/pgen.h @@ -0,0 +1,30 @@ +/*********************************************************** +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 generator interface */ + +extern grammar gram; + +extern grammar *meta_grammar PROTO((void)); +extern grammar *pgen PROTO((struct _node *)); diff --git a/src/pgenheaders.h b/src/pgenheaders.h new file mode 100644 index 0000000..059915a --- /dev/null +++ b/src/pgenheaders.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. + +******************************************************************/ + +/* Include files and extern declarations used by most of the parser. + This is a precompiled header for THINK C. */ + +#include <stdio.h> +#include <string.h> + +#ifdef THINK_C +/* #define THINK_C_3_0 /*** TURN THIS ON FOR THINK C 3.0 ****/ +#define label label_ +#undef label +#endif + +#ifdef THINK_C_3_0 +#include <proto.h> +#endif + +#ifdef THINK_C +#ifndef THINK_C_3_0 +#include <stdlib.h> +#endif +#endif + +#include "PROTO.h" +#include "malloc.h" + +extern void fatal PROTO((char *)); diff --git a/src/pgenmain.c b/src/pgenmain.c new file mode 100644 index 0000000..80f6f2d --- /dev/null +++ b/src/pgenmain.c @@ -0,0 +1,148 @@ +/*********************************************************** +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 generator main program */ + +/* This expects a filename containing the grammar as argv[1] (UNIX) + or asks the console for such a file name (THINK C). + It writes its output on two files in the current directory: + - "graminit.c" gets the grammar as a bunch of initialized data + - "graminit.h" gets the grammar's non-terminals as #defines. + Error messages and status info during the generation process are + written to stdout, or sometimes to stderr. */ + +#include "pgenheaders.h" +#include "grammar.h" +#include "node.h" +#include "parsetok.h" +#include "pgen.h" + +int debugging; + +/* Forward */ +grammar *getgrammar PROTO((char *filename)); +#ifdef THINK_C +int main PROTO((int, char **)); +char *askfile PROTO((void)); +#endif + +int +main(argc, argv) + int argc; + char **argv; +{ + grammar *g; + node *n; + FILE *fp; + char *filename; + +#ifdef THINK_C + filename = askfile(); +#else + if (argc != 2) { + fprintf(stderr, "usage: %s grammar\n", argv[0]); + exit(2); + } + filename = argv[1]; +#endif + g = getgrammar(filename); + fp = fopen("graminit.c", "w"); + if (fp == NULL) { + perror("graminit.c"); + exit(1); + } + printf("Writing graminit.c ...\n"); + printgrammar(g, fp); + fclose(fp); + fp = fopen("graminit.h", "w"); + if (fp == NULL) { + perror("graminit.h"); + exit(1); + } + printf("Writing graminit.h ...\n"); + printnonterminals(g, fp); + fclose(fp); + exit(0); +} + +grammar * +getgrammar(filename) + char *filename; +{ + FILE *fp; + node *n; + grammar *g0, *g; + + fp = fopen(filename, "r"); + if (fp == NULL) { + perror(filename); + exit(1); + } + g0 = meta_grammar(); + n = NULL; + parsefile(fp, filename, g0, g0->g_start, (char *)NULL, (char *)NULL, &n); + fclose(fp); + if (n == NULL) { + fprintf(stderr, "Parsing error.\n"); + exit(1); + } + g = pgen(n); + if (g == NULL) { + printf("Bad grammar.\n"); + exit(1); + } + return g; +} + +#ifdef THINK_C +char * +askfile() +{ + char buf[256]; + static char name[256]; + printf("Input file name: "); + if (fgets(buf, sizeof buf, stdin) == NULL) { + printf("EOF\n"); + exit(1); + } + /* XXX The (unsigned char *) case is needed by THINK C 3.0 */ + if (sscanf(/*(unsigned char *)*/buf, " %s ", name) != 1) { + printf("No file\n"); + exit(1); + } + return name; +} +#endif + +void +fatal(msg) + char *msg; +{ + fprintf(stderr, "pgen: FATAL ERROR: %s\n", msg); + exit(1); +} + +/* XXX TO DO: + - check for duplicate definitions of names (instead of fatal err) +*/ diff --git a/src/posixmodule.c b/src/posixmodule.c new file mode 100644 index 0000000..9729376 --- /dev/null +++ b/src/posixmodule.c @@ -0,0 +1,427 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* POSIX module implementation */ + +#include <signal.h> +#include <string.h> +#include <setjmp.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#ifdef SYSV +#include <dirent.h> +#define direct dirent +#else +#include <sys/dir.h> +#endif + +#include "allobjects.h" +#include "modsupport.h" + +extern char *strerror PROTO((int)); + +#ifdef AMOEBA +#define NO_LSTAT +#endif + + +/* Return a dictionary corresponding to the POSIX environment table */ + +extern char **environ; + +static object * +convertenviron() +{ + object *d; + char **e; + d = newdictobject(); + if (d == NULL) + return NULL; + if (environ == NULL) + return d; + /* XXX This part ignores errors */ + for (e = environ; *e != NULL; e++) { + object *v; + char *p = strchr(*e, '='); + if (p == NULL) + continue; + v = newstringobject(p+1); + if (v == NULL) + continue; + *p = '\0'; + (void) dictinsert(d, *e, v); + *p = '='; + DECREF(v); + } + return d; +} + + +static object *PosixError; /* Exception posix.error */ + +/* Set a POSIX-specific error from errno, and return NULL */ + +static object * +posix_error() +{ + return err_errno(PosixError); +} + + +/* POSIX generic methods */ + +static object * +posix_1str(args, func) + object *args; + int (*func) FPROTO((const char *)); +{ + object *path1; + if (!getstrarg(args, &path1)) + return NULL; + if ((*func)(getstringvalue(path1)) < 0) + return posix_error(); + INCREF(None); + return None; +} + +static object * +posix_2str(args, func) + object *args; + int (*func) FPROTO((const char *, const char *)); +{ + object *path1, *path2; + if (!getstrstrarg(args, &path1, &path2)) + return NULL; + if ((*func)(getstringvalue(path1), getstringvalue(path2)) < 0) + return posix_error(); + INCREF(None); + return None; +} + +static object * +posix_strint(args, func) + object *args; + int (*func) FPROTO((const char *, int)); +{ + object *path1; + int i; + if (!getstrintarg(args, &path1, &i)) + return NULL; + if ((*func)(getstringvalue(path1), i) < 0) + return posix_error(); + INCREF(None); + return None; +} + +static object * +posix_do_stat(self, args, statfunc) + object *self; + object *args; + int (*statfunc) FPROTO((const char *, struct stat *)); +{ + struct stat st; + object *path; + object *v; + if (!getstrarg(args, &path)) + return NULL; + if ((*statfunc)(getstringvalue(path), &st) != 0) + return posix_error(); + v = newtupleobject(10); + if (v == NULL) + return NULL; +#define SET(i, st_member) settupleitem(v, i, newintobject((long)st.st_member)) + SET(0, st_mode); + SET(1, st_ino); + SET(2, st_dev); + SET(3, st_nlink); + SET(4, st_uid); + SET(5, st_gid); + SET(6, st_size); + SET(7, st_atime); + SET(8, st_mtime); + SET(9, st_ctime); +#undef SET + if (err_occurred()) { + DECREF(v); + return NULL; + } + return v; +} + + +/* POSIX methods */ + +static object * +posix_chdir(self, args) + object *self; + object *args; +{ + extern int chdir PROTO((const char *)); + return posix_1str(args, chdir); +} + +static object * +posix_chmod(self, args) + object *self; + object *args; +{ + extern int chmod PROTO((const char *, mode_t)); + return posix_strint(args, chmod); +} + +static object * +posix_getcwd(self, args) + object *self; + object *args; +{ + char buf[1026]; + extern char *getcwd PROTO((char *, int)); + if (!getnoarg(args)) + return NULL; + if (getcwd(buf, sizeof buf) == NULL) + return posix_error(); + return newstringobject(buf); +} + +static object * +posix_link(self, args) + object *self; + object *args; +{ + extern int link PROTO((const char *, const char *)); + return posix_2str(args, link); +} + +static object * +posix_listdir(self, args) + object *self; + object *args; +{ + object *name, *d, *v; + DIR *dirp; + struct direct *ep; + if (!getstrarg(args, &name)) + return NULL; + if ((dirp = opendir(getstringvalue(name))) == NULL) + return posix_error(); + if ((d = newlistobject(0)) == NULL) { + closedir(dirp); + return NULL; + } + while ((ep = readdir(dirp)) != NULL) { + v = newstringobject(ep->d_name); + if (v == NULL) { + DECREF(d); + d = NULL; + break; + } + if (addlistitem(d, v) != 0) { + DECREF(v); + DECREF(d); + d = NULL; + break; + } + DECREF(v); + } + closedir(dirp); + return d; +} + +static object * +posix_mkdir(self, args) + object *self; + object *args; +{ + extern int mkdir PROTO((const char *, mode_t)); + return posix_strint(args, mkdir); +} + +static object * +posix_rename(self, args) + object *self; + object *args; +{ + extern int rename PROTO((const char *, const char *)); + return posix_2str(args, rename); +} + +static object * +posix_rmdir(self, args) + object *self; + object *args; +{ + extern int rmdir PROTO((const char *)); + return posix_1str(args, rmdir); +} + +static object * +posix_stat(self, args) + object *self; + object *args; +{ + extern int stat PROTO((const char *, struct stat *)); + return posix_do_stat(self, args, stat); +} + +static object * +posix_system(self, args) + object *self; + object *args; +{ + object *command; + int sts; + if (!getstrarg(args, &command)) + return NULL; + sts = system(getstringvalue(command)); + return newintobject((long)sts); +} + +static object * +posix_umask(self, args) + object *self; + object *args; +{ + int i; + if (!getintarg(args, &i)) + return NULL; + i = umask(i); + if (i < 0) + return posix_error(); + return newintobject((long)i); +} + +static object * +posix_unlink(self, args) + object *self; + object *args; +{ + extern int unlink PROTO((const char *)); + return posix_1str(args, unlink); +} + +static object * +posix_utimes(self, args) + object *self; + object *args; +{ + object *path; + struct timeval tv[2]; + if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2) { + err_badarg(); + return NULL; + } + if (!getstrarg(gettupleitem(args, 0), &path) || + !getlonglongargs(gettupleitem(args, 1), + &tv[0].tv_sec, &tv[1].tv_sec)) + return NULL; + tv[0].tv_usec = tv[1].tv_usec = 0; + if (utimes(getstringvalue(path), tv) < 0) + return posix_error(); + INCREF(None); + return None; +} + + +#ifndef NO_LSTAT + +static object * +posix_lstat(self, args) + object *self; + object *args; +{ + extern int lstat PROTO((const char *, struct stat *)); + return posix_do_stat(self, args, lstat); +} + +static object * +posix_readlink(self, args) + object *self; + object *args; +{ + char buf[1024]; /* XXX Should use MAXPATHLEN */ + object *path; + int n; + if (!getstrarg(args, &path)) + return NULL; + n = readlink(getstringvalue(path), buf, sizeof buf); + if (n < 0) + return posix_error(); + return newsizedstringobject(buf, n); +} + +static object * +posix_symlink(self, args) + object *self; + object *args; +{ + extern int symlink PROTO((const char *, const char *)); + return posix_2str(args, symlink); +} + +#endif /* NO_LSTAT */ + + +static struct methodlist posix_methods[] = { + {"chdir", posix_chdir}, + {"chmod", posix_chmod}, + {"getcwd", posix_getcwd}, + {"link", posix_link}, + {"listdir", posix_listdir}, + {"mkdir", posix_mkdir}, + {"rename", posix_rename}, + {"rmdir", posix_rmdir}, + {"stat", posix_stat}, + {"system", posix_system}, + {"umask", posix_umask}, + {"unlink", posix_unlink}, + {"utimes", posix_utimes}, +#ifndef NO_LSTAT + {"lstat", posix_lstat}, + {"readlink", posix_readlink}, + {"symlink", posix_symlink}, +#endif + {NULL, NULL} /* Sentinel */ +}; + + +void +initposix() +{ + object *m, *d, *v; + + m = initmodule("posix", posix_methods); + d = getmoduledict(m); + + /* Initialize posix.environ dictionary */ + v = convertenviron(); + if (v == NULL || dictinsert(d, "environ", v) != 0) + fatal("can't define posix.environ"); + DECREF(v); + + /* Initialize posix.error exception */ + PosixError = newstringobject("posix.error"); + if (PosixError == NULL || dictinsert(d, "error", PosixError) != 0) + fatal("can't define posix.error"); +} diff --git a/src/printgrammar.c b/src/printgrammar.c new file mode 100644 index 0000000..c48262d --- /dev/null +++ b/src/printgrammar.c @@ -0,0 +1,149 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Print a bunch of C initializers that represent a grammar */ + +#include "pgenheaders.h" +#include "grammar.h" + +/* Forward */ +static void printarcs PROTO((int, dfa *, FILE *)); +static void printstates PROTO((grammar *, FILE *)); +static void printdfas PROTO((grammar *, FILE *)); +static void printlabels PROTO((grammar *, FILE *)); + +void +printgrammar(g, fp) + grammar *g; + FILE *fp; +{ + fprintf(fp, "#include \"pgenheaders.h\"\n"); + fprintf(fp, "#include \"grammar.h\"\n"); + printdfas(g, fp); + printlabels(g, fp); + fprintf(fp, "grammar gram = {\n"); + fprintf(fp, "\t%d,\n", g->g_ndfas); + fprintf(fp, "\tdfas,\n"); + fprintf(fp, "\t{%d, labels},\n", g->g_ll.ll_nlabels); + fprintf(fp, "\t%d\n", g->g_start); + fprintf(fp, "};\n"); +} + +void +printnonterminals(g, fp) + grammar *g; + FILE *fp; +{ + dfa *d; + int i; + + d = g->g_dfa; + for (i = g->g_ndfas; --i >= 0; d++) + fprintf(fp, "#define %s %d\n", d->d_name, d->d_type); +} + +static void +printarcs(i, d, fp) + int i; + dfa *d; + FILE *fp; +{ + arc *a; + state *s; + int j, k; + + s = d->d_state; + for (j = 0; j < d->d_nstates; j++, s++) { + fprintf(fp, "static arc arcs_%d_%d[%d] = {\n", + i, j, s->s_narcs); + a = s->s_arc; + for (k = 0; k < s->s_narcs; k++, a++) + fprintf(fp, "\t{%d, %d},\n", a->a_lbl, a->a_arrow); + fprintf(fp, "};\n"); + } +} + +static void +printstates(g, fp) + grammar *g; + FILE *fp; +{ + state *s; + dfa *d; + int i, j; + + d = g->g_dfa; + for (i = 0; i < g->g_ndfas; i++, d++) { + printarcs(i, d, fp); + fprintf(fp, "static state states_%d[%d] = {\n", + i, d->d_nstates); + s = d->d_state; + for (j = 0; j < d->d_nstates; j++, s++) + fprintf(fp, "\t{%d, arcs_%d_%d},\n", + s->s_narcs, i, j); + fprintf(fp, "};\n"); + } +} + +static void +printdfas(g, fp) + grammar *g; + FILE *fp; +{ + dfa *d; + int i, j; + + printstates(g, fp); + fprintf(fp, "static dfa dfas[%d] = {\n", g->g_ndfas); + d = g->g_dfa; + for (i = 0; i < g->g_ndfas; i++, d++) { + fprintf(fp, "\t{%d, \"%s\", %d, %d, states_%d,\n", + d->d_type, d->d_name, d->d_initial, d->d_nstates, i); + fprintf(fp, "\t \""); + for (j = 0; j < NBYTES(g->g_ll.ll_nlabels); j++) + fprintf(fp, "\\%03o", d->d_first[j] & 0xff); + fprintf(fp, "\"},\n"); + } + fprintf(fp, "};\n"); +} + +static void +printlabels(g, fp) + grammar *g; + FILE *fp; +{ + label *l; + int i; + + fprintf(fp, "static label labels[%d] = {\n", g->g_ll.ll_nlabels); + l = g->g_ll.ll_label; + for (i = g->g_ll.ll_nlabels; --i >= 0; l++) { + if (l->lb_str == NULL) + fprintf(fp, "\t{%d, 0},\n", l->lb_type); + else + fprintf(fp, "\t{%d, \"%s\"},\n", + l->lb_type, l->lb_str); + } + fprintf(fp, "};\n"); +} diff --git a/src/profmain.c b/src/profmain.c new file mode 100644 index 0000000..eff57bf --- /dev/null +++ b/src/profmain.c @@ -0,0 +1,133 @@ +/*********************************************************** +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. + +******************************************************************/ + +#include <stdio.h> +#include "string.h" + +#include "PROTO.h" +#include "grammar.h" +#include "node.h" +#include "parsetok.h" +#include "graminit.h" +#include "tokenizer.h" +#include "errcode.h" +#include "malloc.h" + +extern int _profile; + +extern grammar gram; /* From graminit.c */ + +int debugging = 1; + +FILE *getopenfile() +{ + char buf[256]; + char *p; + FILE *fp; + for (;;) { + fprintf(stderr, "File name: "); + if (fgets(buf, sizeof buf, stdin) == NULL) { + fprintf(stderr, "EOF\n"); + exit(1); + } + p = strchr(buf, '\n'); + if (p != NULL) + *p = '\0'; + if ((fp = fopen(buf, "r")) != NULL) + break; + fprintf(stderr, "Sorry, try again.\n"); + } + return fp; +} + +main() +{ + FILE *fp; + _profile = 0; + fp = getopenfile(); +#if 0 + askgo("Start tokenizing"); + runtokenizer(fp); + fseek(fp, 0L, 0); +#endif + if (!gram.g_accel) + addaccelerators(&gram); + askgo("Start parsing"); + _profile = 1; + runparser(fp); + _profile = 0; + freopen("prof.out", "w", stdout); + DumpProfile(); + fflush(stdout); + exit(0); +} + +static int +runtokenizer(fp) + FILE *fp; +{ + struct tok_state *tok; + tok = tok_setupf(fp, "Tokenizing", "."); + for (;;) { + char *a, *b; + register char *str; + register int len; + (void) tok_get(tok, &a, &b); + if (tok->done != E_OK) + break; + len = b - a; + str = NEW(char, len + 1); + if (str == NULL) { + fprintf(stderr, "no mem for next token"); + break; + } + strncpy(str, a, len); + str[len] = '\0'; + } + fprintf(stderr, "done (%d)\n", tok->done); +} + +static +runparser(fp, start) + FILE *fp; +{ + node *n; + int ret; + ret = parsefile(fp, &gram, module_input, "Parsing", ".", &n); + fprintf(stderr, "done (%d)\n", ret); +#if 0 + _profile = 0; + if (ret == E_DONE) + listtree(n); +#endif +} + +static int +askgo(prompt) + char *prompt; +{ + char buf[256]; + fprintf(stderr, "%s: hit return when ready: ", prompt); + fgets(buf, sizeof buf, stdin); +} diff --git a/src/pythonmain.c b/src/pythonmain.c new file mode 100644 index 0000000..8c86d8c --- /dev/null +++ b/src/pythonmain.c @@ -0,0 +1,440 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Python interpreter main program */ + +#include "patchlevel.h" + +#include "allobjects.h" + +#include "grammar.h" +#include "node.h" +#include "parsetok.h" +#include "graminit.h" +#include "errcode.h" +#include "sysmodule.h" +#include "compile.h" +#include "ceval.h" +#include "pythonrun.h" +#include "import.h" + +extern char *getpythonpath(); + +extern grammar gram; /* From graminit.c */ + +#ifdef DEBUG +int debugging; /* Needed by parser.c */ +#endif + +main(argc, argv) + int argc; + char **argv; +{ + char *filename = NULL; + FILE *fp = stdin; + + initargs(&argc, &argv); + + if (argc > 1 && strcmp(argv[1], "-") != 0) + filename = argv[1]; + + if (filename != NULL) { + if ((fp = fopen(filename, "r")) == NULL) { + fprintf(stderr, "python: can't open file '%s'\n", + filename); + exit(2); + } + } + + initall(); + + setpythonpath(getpythonpath()); + setpythonargv(argc-1, argv+1); + + goaway(run(fp, filename == NULL ? "<stdin>" : filename)); + /*NOTREACHED*/ +} + +/* Initialize all */ + +void +initall() +{ + static int inited; + + if (inited) + return; + inited = 1; + + initimport(); + + /* Modules 'builtin' and 'sys' are initialized here, + they are needed by random bits of the interpreter. + All other modules are optional and should be initialized + by the initcalls() of a specific configuration. */ + + initbuiltin(); /* Also initializes builtin exceptions */ + initsys(); + + initcalls(); /* Configuration-dependent initializations */ + + initintr(); /* For intrcheck() */ +} + +/* Parse input from a file and execute it */ + +int +run(fp, filename) + FILE *fp; + char *filename; +{ + if (filename == NULL) + filename = "???"; + if (isatty(fileno(fp))) + return run_tty_loop(fp, filename); + else + return run_script(fp, filename); +} + +int +run_tty_loop(fp, filename) + FILE *fp; + char *filename; +{ + object *v; + int ret; + v = sysget("ps1"); + if (v == NULL) { + sysset("ps1", v = newstringobject(">>> ")); + XDECREF(v); + } + v = sysget("ps2"); + if (v == NULL) { + sysset("ps2", v = newstringobject("... ")); + XDECREF(v); + } + for (;;) { + ret = run_tty_1(fp, filename); +#ifdef REF_DEBUG + fprintf(stderr, "[%ld refs]\n", ref_total); +#endif + if (ret == E_EOF) + return 0; + /* + if (ret == E_NOMEM) + return -1; + */ + } +} + +int +run_tty_1(fp, filename) + FILE *fp; + char *filename; +{ + object *m, *d, *v, *w; + node *n; + char *ps1, *ps2; + int err; + v = sysget("ps1"); + w = sysget("ps2"); + if (v != NULL && is_stringobject(v)) { + INCREF(v); + ps1 = getstringvalue(v); + } + else { + v = NULL; + ps1 = ""; + } + if (w != NULL && is_stringobject(w)) { + INCREF(w); + ps2 = getstringvalue(w); + } + else { + w = NULL; + ps2 = ""; + } + err = parsefile(fp, filename, &gram, single_input, ps1, ps2, &n); + XDECREF(v); + XDECREF(w); + if (err == E_EOF) + return E_EOF; + if (err != E_DONE) { + err_input(err); + print_error(); + return err; + } + m = add_module("__main__"); + if (m == NULL) + return -1; + d = getmoduledict(m); + v = run_node(n, filename, d, d); + flushline(); + if (v == NULL) { + print_error(); + return -1; + } + DECREF(v); + return 0; +} + +int +run_script(fp, filename) + FILE *fp; + char *filename; +{ + object *m, *d, *v; + m = add_module("__main__"); + if (m == NULL) + return -1; + d = getmoduledict(m); + v = run_file(fp, filename, file_input, d, d); + flushline(); + if (v == NULL) { + print_error(); + return -1; + } + DECREF(v); + return 0; +} + +void +print_error() +{ + object *exception, *v; + err_get(&exception, &v); + fprintf(stderr, "Unhandled exception: "); + printobject(exception, stderr, PRINT_RAW); + if (v != NULL && v != None) { + fprintf(stderr, ": "); + printobject(v, stderr, PRINT_RAW); + } + fprintf(stderr, "\n"); + XDECREF(exception); + XDECREF(v); + printtraceback(stderr); +} + +object * +run_string(str, start, globals, locals) + char *str; + int start; + /*dict*/object *globals, *locals; +{ + node *n; + int err; + err = parse_string(str, start, &n); + return run_err_node(err, n, "<string>", globals, locals); +} + +object * +run_file(fp, filename, start, globals, locals) + FILE *fp; + char *filename; + int start; + /*dict*/object *globals, *locals; +{ + node *n; + int err; + err = parse_file(fp, filename, start, &n); + return run_err_node(err, n, filename, globals, locals); +} + +object * +run_err_node(err, n, filename, globals, locals) + int err; + node *n; + char *filename; + /*dict*/object *globals, *locals; +{ + if (err != E_DONE) { + err_input(err); + return NULL; + } + return run_node(n, filename, globals, locals); +} + +object * +run_node(n, filename, globals, locals) + node *n; + char *filename; + /*dict*/object *globals, *locals; +{ + if (globals == NULL) { + globals = getglobals(); + if (locals == NULL) + locals = getlocals(); + } + else { + if (locals == NULL) + locals = globals; + } + return eval_node(n, filename, globals, locals); +} + +object * +eval_node(n, filename, globals, locals) + node *n; + char *filename; + object *globals; + object *locals; +{ + codeobject *co; + object *v; + co = compile(n, filename); + freetree(n); + if (co == NULL) + return NULL; + v = eval_code(co, globals, locals, (object *)NULL); + DECREF(co); + return v; +} + +/* Simplified interface to parsefile */ + +int +parse_file(fp, filename, start, n_ret) + FILE *fp; + char *filename; + int start; + node **n_ret; +{ + return parsefile(fp, filename, &gram, start, + (char *)0, (char *)0, n_ret); +} + +/* Simplified interface to parsestring */ + +int +parse_string(str, start, n_ret) + char *str; + int start; + node **n_ret; +{ + int err = parsestring(str, &gram, start, n_ret); + /* Don't confuse early end of string with early end of input */ + if (err == E_EOF) + err = E_SYNTAX; + return err; +} + +/* Print fatal error message and abort */ + +void +fatal(msg) + char *msg; +{ + fprintf(stderr, "Fatal error: %s\n", msg); + abort(); +} + +/* Clean up and exit */ + +void +goaway(sts) + int sts; +{ + flushline(); + + /* XXX Call doneimport() before donecalls(), since donecalls() + calls wdone(), and doneimport() may close windows */ + doneimport(); + donecalls(); + + err_clear(); + +#ifdef REF_DEBUG + fprintf(stderr, "[%ld refs]\n", ref_total); +#endif + +#ifdef THINK_C_3_0 + if (sts == 0) + Click_On(0); +#endif + +#ifdef TRACE_REFS + if (askyesno("Print left references?")) { +#ifdef THINK_C_3_0 + Click_On(1); +#endif + printrefs(stderr); + } +#endif /* TRACE_REFS */ + + exit(sts); + /*NOTREACHED*/ +} + +static +finaloutput() +{ +#ifdef TRACE_REFS + if (!askyesno("Print left references?")) + return; +#ifdef THINK_C_3_0 + Click_On(1); +#endif + printrefs(stderr); +#endif /* TRACE_REFS */ +} + +/* Ask a yes/no question */ + +static int +askyesno(prompt) + char *prompt; +{ + char buf[256]; + + printf("%s [ny] ", prompt); + if (fgets(buf, sizeof buf, stdin) == NULL) + return 0; + return buf[0] == 'y' || buf[0] == 'Y'; +} + +#ifdef THINK_C_3_0 + +/* Check for file descriptor connected to interactive device. + Pretend that stdin is always interactive, other files never. */ + +int +isatty(fd) + int fd; +{ + return fd == fileno(stdin); +} + +#endif + +/* XXX WISH LIST + + - possible new types: + - iterator (for range, keys, ...) + - improve interpreter error handling, e.g., true tracebacks + - save precompiled modules on file? + - fork threads, locking + - allow syntax extensions +*/ + +/* "Floccinaucinihilipilification" */ diff --git a/src/pythonrun.h b/src/pythonrun.h new file mode 100644 index 0000000..30c8667 --- /dev/null +++ b/src/pythonrun.h @@ -0,0 +1,47 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Interfaces to parse and execute pieces of python code */ + +void initall PROTO((void)); + +int run PROTO((FILE *, char *)); + +int run_script PROTO((FILE *, char *)); +int run_tty_1 PROTO((FILE *, char *)); +int run_tty_loop PROTO((FILE *, char *)); + +int parse_string PROTO((char *, int, struct _node **)); +int parse_file PROTO((FILE *, char *, int, struct _node **)); + +object *eval_node PROTO((struct _node *, char *, object *, object *)); + +object *run_string PROTO((char *, int, object *, object *)); +object *run_file PROTO((FILE *, char *, int, object *, object *)); +object *run_err_node PROTO((int, struct _node *, char *, object *, object *)); +object *run_node PROTO((struct _node *, char *, object *, object *)); + +void print_error PROTO((void)); + +void goaway PROTO((int)); diff --git a/src/regexp.c b/src/regexp.c new file mode 100644 index 0000000..50ce9b6 --- /dev/null +++ b/src/regexp.c @@ -0,0 +1,1394 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* + * regcomp and regexec -- regsub and regerror are elsewhere + * + * Copyright (c) 1986 by University of Toronto. + * Written by Henry Spencer. Not derived from licensed software. +#ifdef MULTILINE + * Changed by Guido van Rossum, CWI, Amsterdam + * for multi-line support. +#endif + * + * Permission is granted to anyone to use this software for any + * purpose on any computer system, and to redistribute it freely, + * subject to the following restrictions: + * + * 1. The author is not responsible for the consequences of use of + * this software, no matter how awful, even if they arise + * from defects in it. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. + * + * 3. Altered versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * Beware that some of this code is subtly aware of the way operator + * precedence is structured in regular expressions. Serious changes in + * regular-expression syntax might require a total rethink. + */ +#include <stdio.h> +#include "PROTO.h" +#include "malloc.h" +#undef ANY /* Conflicting identifier defined in malloc.h */ +#include <string.h> /* XXX Remove if not found */ +#include "regexp.h" +#include "regmagic.h" + +#ifdef MULTILINE +/* + * Defining MULTILINE turns on the following changes in the semantics: + * 1. The '.' operator matches all characters except a newline. + * 2. The '^' operator matches at the beginning of the string or after + * a newline. (Anchored matches are retried after each newline.) + * 3. The '$' operator matches at the end of the string or before + * a newline. + * 4. A '\' followed by an 'n' matches a newline. (This is an + * unfortunate exception to the rule that '\' followed by a + * character matches that character...) + * + * Also, there is a new function reglexec(prog, string, offset) + * which searches for a match starting at 'string+offset'; + * it differs from regexec(prog, string+offset) in assuming + * that the line begins at 'string'. + */ +#endif + +/* + * The "internal use only" fields in regexp.h are present to pass info from + * compile to execute that permits the execute phase to run lots faster on + * simple cases. They are: + * + * regstart char that must begin a match; '\0' if none obvious + * reganch is the match anchored (at beginning-of-line only)? + * regmust string (pointer into program) that match must include, or NULL + * regmlen length of regmust string + * + * Regstart and reganch permit very fast decisions on suitable starting points + * for a match, cutting down the work a lot. Regmust permits fast rejection + * of lines that cannot possibly match. The regmust tests are costly enough + * that regcomp() supplies a regmust only if the r.e. contains something + * potentially expensive (at present, the only such thing detected is * or + + * at the start of the r.e., which can involve a lot of backup). Regmlen is + * supplied because the test in regexec() needs it and regcomp() is computing + * it anyway. + */ + +/* + * Structure for regexp "program". This is essentially a linear encoding + * of a nondeterministic finite-state machine (aka syntax charts or + * "railroad normal form" in parsing technology). Each node is an opcode + * plus a "next" pointer, possibly plus an operand. "Next" pointers of + * all nodes except BRANCH implement concatenation; a "next" pointer with + * a BRANCH on both ends of it is connecting two alternatives. (Here we + * have one of the subtle syntax dependencies: an individual BRANCH (as + * opposed to a collection of them) is never concatenated with anything + * because of operator precedence.) The operand of some types of node is + * a literal string; for others, it is a node leading into a sub-FSM. In + * particular, the operand of a BRANCH node is the first node of the branch. + * (NB this is *not* a tree structure: the tail of the branch connects + * to the thing following the set of BRANCHes.) The opcodes are: + */ + +/* definition number opnd? meaning */ +#define END 0 /* no End of program. */ +#define BOL 1 /* no Match "" at beginning of line. */ +#define EOL 2 /* no Match "" at end of line. */ +#define ANY 3 /* no Match any one character. */ +#define ANYOF 4 /* str Match any character in this string. */ +#define ANYBUT 5 /* str Match any character not in this string. */ +#define BRANCH 6 /* node Match this alternative, or the next... */ +#define BACK 7 /* no Match "", "next" ptr points backward. */ +#define EXACTLY 8 /* str Match this string. */ +#define NOTHING 9 /* no Match empty string. */ +#define STAR 10 /* node Match this (simple) thing 0 or more times. */ +#define PLUS 11 /* node Match this (simple) thing 1 or more times. */ +#define OPEN 20 /* no Mark this point in input as start of #n. */ + /* OPEN+1 is number 1, etc. */ +#define CLOSE 30 /* no Analogous to OPEN. */ + +/* + * Opcode notes: + * + * BRANCH The set of branches constituting a single choice are hooked + * together with their "next" pointers, since precedence prevents + * anything being concatenated to any individual branch. The + * "next" pointer of the last BRANCH in a choice points to the + * thing following the whole choice. This is also where the + * final "next" pointer of each individual branch points; each + * branch starts with the operand node of a BRANCH node. + * + * BACK Normal "next" pointers all implicitly point forward; BACK + * exists to make loop structures possible. + * + * STAR,PLUS '?', and complex '*' and '+', are implemented as circular + * BRANCH structures using BACK. Simple cases (one character + * per match) are implemented with STAR and PLUS for speed + * and to minimize recursive plunges. + * + * OPEN,CLOSE ...are numbered at compile time. + */ + +/* + * A node is one char of opcode followed by two chars of "next" pointer. + * "Next" pointers are stored as two 8-bit pieces, high order first. The + * value is a positive offset from the opcode of the node containing it. + * An operand, if any, simply follows the node. (Note that much of the + * code generation knows about this implicit relationship.) + * + * Using two bytes for the "next" pointer is vast overkill for most things, + * but allows patterns to get big without disasters. + */ +#define OP(p) (*(p)) +#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377)) +#define OPERAND(p) ((p) + 3) + +/* + * See regmagic.h for one further detail of program structure. + */ + + +/* + * Utility definitions. + */ +#ifndef CHARBITS +#define UCHARAT(p) ((int)*(unsigned char *)(p)) +#else +#define UCHARAT(p) ((int)*(p)&CHARBITS) +#endif + +#define FAIL(m) { regerror(m); return(NULL); } +#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?') +#define META "^$.[()|?+*\\" + +/* + * Flags to be passed up and down. + */ +#define HASWIDTH 01 /* Known never to match null string. */ +#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */ +#define SPSTART 04 /* Starts with * or +. */ +#define WORST 0 /* Worst case. */ + +/* + * Global work variables for regcomp(). + */ +static char *regparse; /* Input-scan pointer. */ +static int regnpar; /* () count. */ +static char regdummy; +static char *regcode; /* Code-emit pointer; ®dummy = don't. */ +static long regsize; /* Code size. */ +#ifdef MULTILINE +static int regnl; /* '\n' detected. */ +#endif + +/* + * Forward declarations for regcomp()'s friends. + */ +#ifndef STATIC +#define STATIC static +#endif +STATIC char *reg(); +STATIC char *regbranch(); +STATIC char *regpiece(); +STATIC char *regatom(); +STATIC char *regnode(); +STATIC char *regnext(); +STATIC void regc(); +STATIC void reginsert(); +STATIC void regtail(); +STATIC void regoptail(); +#ifdef STRCSPN +STATIC int strcspn(); +#endif + +/* + - regcomp - compile a regular expression into internal code + * + * We can't allocate space until we know how big the compiled form will be, + * but we can't compile it (and thus know how big it is) until we've got a + * place to put the code. So we cheat: we compile it twice, once with code + * generation turned off and size counting turned on, and once "for real". + * This also means that we don't allocate space until we are sure that the + * thing really will compile successfully, and we never have to move the + * code and thus invalidate pointers into it. (Note that it has to be in + * one piece because free() must be able to free it all.) + * + * Beware that the optimization-preparation code in here knows about some + * of the structure of the compiled regexp. + */ +regexp * +regcomp(exp) +char *exp; +{ + register regexp *r; + register char *scan; + register char *longest; + register int len; + int flags; + + if (exp == NULL) + FAIL("NULL argument"); + + /* First pass: determine size, legality. */ + regparse = exp; + regnpar = 1; + regsize = 0L; + regcode = ®dummy; +#ifdef MULTILINE + regnl = 0; +#endif + regc(MAGIC); + if (reg(0, &flags) == NULL) + return(NULL); + + /* Small enough for pointer-storage convention? */ + if (regsize >= 32767L) /* Probably could be 65535L. */ + FAIL("regexp too big"); + + /* Allocate space. */ + r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize); + if (r == NULL) + FAIL("out of space"); + + /* Second pass: emit code. */ + regparse = exp; + regnpar = 1; + regcode = r->program; + regc(MAGIC); + if (reg(0, &flags) == NULL) + return(NULL); + + /* Dig out information for optimizations. */ + r->regstart = '\0'; /* Worst-case defaults. */ + r->reganch = 0; + r->regmust = NULL; + r->regmlen = 0; + scan = r->program+1; /* First BRANCH. */ + if (OP(regnext(scan)) == END) { /* Only one top-level choice. */ + scan = OPERAND(scan); + + /* Starting-point info. */ + if (OP(scan) == EXACTLY) + r->regstart = *OPERAND(scan); + else if (OP(scan) == BOL) + r->reganch++; + + /* + * If there's something expensive in the r.e., find the + * longest literal string that must appear and make it the + * regmust. Resolve ties in favor of later strings, since + * the regstart check works with the beginning of the r.e. + * and avoiding duplication strengthens checking. Not a + * strong reason, but sufficient in the absence of others. + */ +#ifdef MULTILINE + if ((flags&SPSTART) && !regnl) { +#else + if (flags&SPSTART) { +#endif + longest = NULL; + len = 0; + for (; scan != NULL; scan = regnext(scan)) + if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) { + longest = OPERAND(scan); + len = strlen(OPERAND(scan)); + } + r->regmust = longest; + r->regmlen = len; + } + } + + return(r); +} + +/* + - reg - regular expression, i.e. main body or parenthesized thing + * + * Caller must absorb opening parenthesis. + * + * Combining parenthesis handling with the base level of regular expression + * is a trifle forced, but the need to tie the tails of the branches to what + * follows makes it hard to avoid. + */ +static char * +reg(paren, flagp) +int paren; /* Parenthesized? */ +int *flagp; +{ + register char *ret; + register char *br; + register char *ender; + register int parno; + int flags; + + *flagp = HASWIDTH; /* Tentatively. */ + + /* Make an OPEN node, if parenthesized. */ + if (paren) { + if (regnpar >= NSUBEXP) + FAIL("too many ()"); + parno = regnpar; + regnpar++; + ret = regnode(OPEN+parno); + } else + ret = NULL; + + /* Pick up the branches, linking them together. */ + br = regbranch(&flags); + if (br == NULL) + return(NULL); + if (ret != NULL) + regtail(ret, br); /* OPEN -> first. */ + else + ret = br; + if (!(flags&HASWIDTH)) + *flagp &= ~HASWIDTH; + *flagp |= flags&SPSTART; + while (*regparse == '|') { + regparse++; + br = regbranch(&flags); + if (br == NULL) + return(NULL); + regtail(ret, br); /* BRANCH -> BRANCH. */ + if (!(flags&HASWIDTH)) + *flagp &= ~HASWIDTH; + *flagp |= flags&SPSTART; + } + + /* Make a closing node, and hook it on the end. */ + ender = regnode((paren) ? CLOSE+parno : END); + regtail(ret, ender); + + /* Hook the tails of the branches to the closing node. */ + for (br = ret; br != NULL; br = regnext(br)) + regoptail(br, ender); + + /* Check for proper termination. */ + if (paren && *regparse++ != ')') { + FAIL("unmatched ()"); + } else if (!paren && *regparse != '\0') { + if (*regparse == ')') { + FAIL("unmatched ()"); + } else + FAIL("junk on end"); /* "Can't happen". */ + /* NOTREACHED */ + } + + return(ret); +} + +/* + - regbranch - one alternative of an | operator + * + * Implements the concatenation operator. + */ +static char * +regbranch(flagp) +int *flagp; +{ + register char *ret; + register char *chain; + register char *latest; + int flags; + + *flagp = WORST; /* Tentatively. */ + + ret = regnode(BRANCH); + chain = NULL; + while (*regparse != '\0' && *regparse != '|' && *regparse != ')') { + latest = regpiece(&flags); + if (latest == NULL) + return(NULL); + *flagp |= flags&HASWIDTH; + if (chain == NULL) /* First piece. */ + *flagp |= flags&SPSTART; + else + regtail(chain, latest); + chain = latest; + } + if (chain == NULL) /* Loop ran zero times. */ + (void) regnode(NOTHING); + + return(ret); +} + +/* + - regpiece - something followed by possible [*+?] + * + * Note that the branching code sequences used for ? and the general cases + * of * and + are somewhat optimized: they use the same NOTHING node as + * both the endmarker for their branch list and the body of the last branch. + * It might seem that this node could be dispensed with entirely, but the + * endmarker role is not redundant. + */ +static char * +regpiece(flagp) +int *flagp; +{ + register char *ret; + register char op; + register char *next; + int flags; + + ret = regatom(&flags); + if (ret == NULL) + return(NULL); + + op = *regparse; + if (!ISMULT(op)) { + *flagp = flags; + return(ret); + } + + if (!(flags&HASWIDTH) && op != '?') + FAIL("*+ operand could be empty"); + *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH); + + if (op == '*' && (flags&SIMPLE)) + reginsert(STAR, ret); + else if (op == '*') { + /* Emit x* as (x&|), where & means "self". */ + reginsert(BRANCH, ret); /* Either x */ + regoptail(ret, regnode(BACK)); /* and loop */ + regoptail(ret, ret); /* back */ + regtail(ret, regnode(BRANCH)); /* or */ + regtail(ret, regnode(NOTHING)); /* null. */ + } else if (op == '+' && (flags&SIMPLE)) + reginsert(PLUS, ret); + else if (op == '+') { + /* Emit x+ as x(&|), where & means "self". */ + next = regnode(BRANCH); /* Either */ + regtail(ret, next); + regtail(regnode(BACK), ret); /* loop back */ + regtail(next, regnode(BRANCH)); /* or */ + regtail(ret, regnode(NOTHING)); /* null. */ + } else if (op == '?') { + /* Emit x? as (x|) */ + reginsert(BRANCH, ret); /* Either x */ + regtail(ret, regnode(BRANCH)); /* or */ + next = regnode(NOTHING); /* null. */ + regtail(ret, next); + regoptail(ret, next); + } + regparse++; + if (ISMULT(*regparse)) + FAIL("nested *?+"); + + return(ret); +} + +/* + - regatom - the lowest level + * + * Optimization: gobbles an entire sequence of ordinary characters so that + * it can turn them into a single node, which is smaller to store and + * faster to run. Backslashed characters are exceptions, each becoming a + * separate node; the code is simpler that way and it's not worth fixing. + */ +static char * +regatom(flagp) +int *flagp; +{ + register char *ret; + int flags; + + *flagp = WORST; /* Tentatively. */ + + switch (*regparse++) { + case '^': + ret = regnode(BOL); + break; + case '$': + ret = regnode(EOL); + break; + case '.': + ret = regnode(ANY); + *flagp |= HASWIDTH|SIMPLE; + break; + case '[': { + register int class; + register int classend; + + if (*regparse == '^') { /* Complement of range. */ + ret = regnode(ANYBUT); + regparse++; + } else + ret = regnode(ANYOF); + if (*regparse == ']' || *regparse == '-') + regc(*regparse++); + while (*regparse != '\0' && *regparse != ']') { + if (*regparse == '-') { + regparse++; + if (*regparse == ']' || *regparse == '\0') + regc('-'); + else { + class = UCHARAT(regparse-2)+1; + classend = UCHARAT(regparse); + if (class > classend+1) + FAIL("invalid [] range"); + for (; class <= classend; class++) + regc(class); + regparse++; + } + } else + regc(*regparse++); + } + regc('\0'); + if (*regparse != ']') + FAIL("unmatched []"); + regparse++; + *flagp |= HASWIDTH|SIMPLE; + } + break; + case '(': + ret = reg(1, &flags); + if (ret == NULL) + return(NULL); + *flagp |= flags&(HASWIDTH|SPSTART); + break; + case '\0': + case '|': + case ')': + FAIL("internal urp"); /* Supposed to be caught earlier. */ + break; + case '?': + case '+': + case '*': + FAIL("?+* follows nothing"); + break; + case '\\': + if (*regparse == '\0') + FAIL("trailing \\"); + ret = regnode(EXACTLY); +#ifdef MULTILINE + if (*regparse == 'n') { + regc('\n'); + regparse++; + regnl++; + } + else +#endif + regc(*regparse++); + regc('\0'); + *flagp |= HASWIDTH|SIMPLE; + break; + default: { + register int len; + register char ender; + + regparse--; + len = strcspn(regparse, META); + if (len <= 0) + FAIL("internal disaster"); + ender = *(regparse+len); + if (len > 1 && ISMULT(ender)) + len--; /* Back off clear of ?+* operand. */ + *flagp |= HASWIDTH; + if (len == 1) + *flagp |= SIMPLE; + ret = regnode(EXACTLY); + while (len > 0) { +#ifdef MULTILINE + if (*regparse == '\n') + regnl++; +#endif + regc(*regparse++); + len--; + } + regc('\0'); + } + break; + } + + return(ret); +} + +/* + - regnode - emit a node + */ +static char * /* Location. */ +regnode(op) +char op; +{ + register char *ret; + register char *ptr; + + ret = regcode; + if (ret == ®dummy) { + regsize += 3; + return(ret); + } + + ptr = ret; + *ptr++ = op; + *ptr++ = '\0'; /* Null "next" pointer. */ + *ptr++ = '\0'; + regcode = ptr; + + return(ret); +} + +/* + - regc - emit (if appropriate) a byte of code + */ +static void +regc(b) +char b; +{ + if (regcode != ®dummy) + *regcode++ = b; + else + regsize++; +} + +/* + - reginsert - insert an operator in front of already-emitted operand + * + * Means relocating the operand. + */ +static void +reginsert(op, opnd) +char op; +char *opnd; +{ + register char *src; + register char *dst; + register char *place; + + if (regcode == ®dummy) { + regsize += 3; + return; + } + + src = regcode; + regcode += 3; + dst = regcode; + while (src > opnd) + *--dst = *--src; + + place = opnd; /* Op node, where operand used to be. */ + *place++ = op; + *place++ = '\0'; + *place++ = '\0'; +} + +/* + - regtail - set the next-pointer at the end of a node chain + */ +static void +regtail(p, val) +char *p; +char *val; +{ + register char *scan; + register char *temp; + register int offset; + + if (p == ®dummy) + return; + + /* Find last node. */ + scan = p; + for (;;) { + temp = regnext(scan); + if (temp == NULL) + break; + scan = temp; + } + + if (OP(scan) == BACK) + offset = scan - val; + else + offset = val - scan; + *(scan+1) = (offset>>8)&0377; + *(scan+2) = offset&0377; +} + +/* + - regoptail - regtail on operand of first argument; nop if operandless + */ +static void +regoptail(p, val) +char *p; +char *val; +{ + /* "Operandless" and "op != BRANCH" are synonymous in practice. */ + if (p == NULL || p == ®dummy || OP(p) != BRANCH) + return; + regtail(OPERAND(p), val); +} + +/* + * regexec and friends + */ + +/* + * Global work variables for regexec(). + */ +static char *reginput; /* String-input pointer. */ +static char *regbol; /* Beginning of input, for ^ check. */ +static char **regstartp; /* Pointer to startp array. */ +static char **regendp; /* Ditto for endp. */ + +/* + * Forwards. + */ +STATIC int regtry(); +STATIC int regmatch(); +STATIC int regrepeat(); + +#ifdef DEBUG +int regnarrate = 0; +void regdump(); +STATIC char *regprop(); +#endif + +/* + - regexec - match a regexp against a string + */ +int +regexec(prog, string) +register regexp *prog; +register char *string; +{ + register char *s; + extern char *strchr(); + + /* Be paranoid... */ + if (prog == NULL || string == NULL) { + regerror("NULL parameter"); + return(0); + } + +#ifdef MULTILINE + /* Check for \n in string, and if so, call the more general routine. */ + if (strchr(string, '\n') != NULL) + return reglexec(prog, string, 0); +#endif + + /* Check validity of program. */ + if (UCHARAT(prog->program) != MAGIC) { + regerror("corrupted program"); + return(0); + } + + /* If there is a "must appear" string, look for it. */ + if (prog->regmust != NULL) { + s = string; + while ((s = strchr(s, prog->regmust[0])) != NULL) { + if (strncmp(s, prog->regmust, prog->regmlen) == 0) + break; /* Found it. */ + s++; + } + if (s == NULL) /* Not present. */ + return(0); + } + + /* Mark beginning of line for ^ . */ + regbol = string; + + /* Simplest case: anchored match need be tried only once. */ + if (prog->reganch) + return(regtry(prog, string)); + + /* Messy cases: unanchored match. */ + s = string; + if (prog->regstart != '\0') + /* We know what char it must start with. */ + while ((s = strchr(s, prog->regstart)) != NULL) { + if (regtry(prog, s)) + return(1); + s++; + } + else + /* We don't -- general case. */ + do { + if (regtry(prog, s)) + return(1); + } while (*s++ != '\0'); + + /* Failure. */ + return(0); +} + +#ifdef MULTILINE +/* + - reglexec - match a regexp against a long string buffer, starting at offset + */ +int +reglexec(prog, string, offset) +register regexp *prog; +register char *string; +{ + register char *s; + extern char *strchr(); + + /* Be paranoid... */ + if (prog == NULL || string == NULL) { + regerror("NULL parameter"); + return(0); + } + + /* Check validity of program. */ + if (UCHARAT(prog->program) != MAGIC) { + regerror("corrupted program"); + return(0); + } + + /* (Don't look for "must appear" string -- string can be long.) */ + + /* Mark beginning of line for ^ . */ + regbol = string; + + /* Apply offset. + Assume 0 <= offset <= strlen(string), but don't check, + as string can be long. */ + s= string + offset; + + /* Anchored match need be tried only at line starts. */ + if (prog->reganch) { + while (!regtry(prog, s)) { + s = strchr(s, '\n'); + if (s == NULL) + return(0); + s++; + } + return(1); + } + + /* Messy cases: unanchored match. */ + if (prog->regstart != '\0') + /* We know what char it must start with. */ + while ((s = strchr(s, prog->regstart)) != NULL) { + if (regtry(prog, s)) + return(1); + s++; + } + else + /* We don't -- general case. */ + do { + if (regtry(prog, s)) + return(1); + } while (*s++ != '\0'); + + /* Failure. */ + return(0); +} +#endif + +/* + - regtry - try match at specific point + */ +static int /* 0 failure, 1 success */ +regtry(prog, string) +regexp *prog; +char *string; +{ + register int i; + register char **sp; + register char **ep; + + reginput = string; + regstartp = prog->startp; + regendp = prog->endp; + + sp = prog->startp; + ep = prog->endp; + for (i = NSUBEXP; i > 0; i--) { + *sp++ = NULL; + *ep++ = NULL; + } + if (regmatch(prog->program + 1)) { + prog->startp[0] = string; + prog->endp[0] = reginput; + return(1); + } else + return(0); +} + +/* + - regmatch - main matching routine + * + * Conceptually the strategy is simple: check to see whether the current + * node matches, call self recursively to see whether the rest matches, + * and then act accordingly. In practice we make some effort to avoid + * recursion, in particular by going through "ordinary" nodes (that don't + * need to know whether the rest of the match failed) by a loop instead of + * by recursion. + */ +static int /* 0 failure, 1 success */ +regmatch(prog) +char *prog; +{ + register char *scan; /* Current node. */ + char *next; /* Next node. */ + extern char *strchr(); + + scan = prog; +#ifdef DEBUG + if (scan != NULL && regnarrate) + fprintf(stderr, "%s(\n", regprop(scan)); +#endif + while (scan != NULL) { +#ifdef DEBUG + if (regnarrate) + fprintf(stderr, "%s...\n", regprop(scan)); +#endif + next = regnext(scan); + + switch (OP(scan)) { + case BOL: +#ifdef MULTILINE + if (!(reginput == regbol || + reginput > regbol && *(reginput-1) == '\n')) +#else + if (reginput != regbol) +#endif + return(0); + break; + case EOL: +#ifdef MULTILINE + if (*reginput != '\0' && *reginput != '\n') +#else + if (*reginput != '\0') +#endif + return(0); + break; + case ANY: +#ifdef MULTILINE + if (*reginput == '\0' || *reginput == '\n') +#else + if (*reginput == '\0') +#endif + return(0); + reginput++; + break; + case EXACTLY: { + register int len; + register char *opnd; + + opnd = OPERAND(scan); + /* Inline the first character, for speed. */ + if (*opnd != *reginput) + return(0); + len = strlen(opnd); + if (len > 1 && strncmp(opnd, reginput, len) != 0) + return(0); + reginput += len; + } + break; + case ANYOF: + if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL) + return(0); + reginput++; + break; + case ANYBUT: +#ifdef MULTILINE + if (*reginput == '\0' || *reginput == '\n' || + strchr(OPERAND(scan), *reginput) != NULL) +#else + if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL) +#endif + return(0); + reginput++; + break; + case NOTHING: + break; + case BACK: + break; + case OPEN+1: + case OPEN+2: + case OPEN+3: + case OPEN+4: + case OPEN+5: + case OPEN+6: + case OPEN+7: + case OPEN+8: + case OPEN+9: { + register int no; + register char *save; + + no = OP(scan) - OPEN; + save = reginput; + + if (regmatch(next)) { + /* + * Don't set startp if some later + * invocation of the same parentheses + * already has. + */ + if (regstartp[no] == NULL) + regstartp[no] = save; + return(1); + } else + return(0); + } + break; + case CLOSE+1: + case CLOSE+2: + case CLOSE+3: + case CLOSE+4: + case CLOSE+5: + case CLOSE+6: + case CLOSE+7: + case CLOSE+8: + case CLOSE+9: { + register int no; + register char *save; + + no = OP(scan) - CLOSE; + save = reginput; + + if (regmatch(next)) { + /* + * Don't set endp if some later + * invocation of the same parentheses + * already has. + */ + if (regendp[no] == NULL) + regendp[no] = save; + return(1); + } else + return(0); + } + break; + case BRANCH: { + register char *save; + + if (OP(next) != BRANCH) /* No choice. */ + next = OPERAND(scan); /* Avoid recursion. */ + else { + do { + save = reginput; + if (regmatch(OPERAND(scan))) + return(1); + reginput = save; + scan = regnext(scan); + } while (scan != NULL && OP(scan) == BRANCH); + return(0); + /* NOTREACHED */ + } + } + break; + case STAR: + case PLUS: { + register char nextch; + register int no; + register char *save; + register int min; + + /* + * Lookahead to avoid useless match attempts + * when we know what character comes next. + */ + nextch = '\0'; + if (OP(next) == EXACTLY) + nextch = *OPERAND(next); + min = (OP(scan) == STAR) ? 0 : 1; + save = reginput; + no = regrepeat(OPERAND(scan)); + while (no >= min) { + /* If it could work, try it. */ + if (nextch == '\0' || *reginput == nextch) + if (regmatch(next)) + return(1); + /* Couldn't or didn't -- back up. */ + no--; + reginput = save + no; + } + return(0); + } + break; + case END: + return(1); /* Success! */ + break; + default: + regerror("memory corruption"); + return(0); + break; + } + + scan = next; + } + + /* + * We get here only if there's trouble -- normally "case END" is + * the terminating point. + */ + regerror("corrupted pointers"); + return(0); +} + +/* + - regrepeat - repeatedly match something simple, report how many + */ +static int +regrepeat(p) +char *p; +{ + register int count = 0; + register char *scan; + register char *opnd; +#ifdef MULTILINE + register char *eol; +#endif + + scan = reginput; + opnd = OPERAND(p); + switch (OP(p)) { + case ANY: +#ifdef MULTILINE + if ((eol = strchr(scan, '\n')) != NULL) { + count += eol - scan; + scan = eol; + break; + } +#endif + count = strlen(scan); + scan += count; + break; + case EXACTLY: + while (*opnd == *scan) { + count++; + scan++; + } + break; + case ANYOF: + while (*scan != '\0' && strchr(opnd, *scan) != NULL) { + count++; + scan++; + } + break; + case ANYBUT: +#ifdef MULTILINE + while (*scan != '\0' && *scan != '\n' && + strchr(opnd, *scan) == NULL) { +#else + while (*scan != '\0' && strchr(opnd, *scan) == NULL) { +#endif + count++; + scan++; + } + break; + default: /* Oh dear. Called inappropriately. */ + regerror("internal foulup"); + count = 0; /* Best compromise. */ + break; + } + reginput = scan; + + return(count); +} + +/* + - regnext - dig the "next" pointer out of a node + */ +static char * +regnext(p) +register char *p; +{ + register int offset; + + if (p == ®dummy) + return(NULL); + + offset = NEXT(p); + if (offset == 0) + return(NULL); + + if (OP(p) == BACK) + return(p-offset); + else + return(p+offset); +} + +#ifdef DEBUG + +STATIC char *regprop(); + +/* + - regdump - dump a regexp onto stdout in vaguely comprehensible form + */ +void +regdump(r) +regexp *r; +{ + register char *s; + register char op = EXACTLY; /* Arbitrary non-END op. */ + register char *next; + extern char *strchr(); + + + s = r->program + 1; + while (op != END) { /* While that wasn't END last time... */ + op = OP(s); + printf("%2d%s", (int)(s-r->program), regprop(s)); /* Where, what. */ + next = regnext(s); + if (next == NULL) /* Next ptr. */ + printf("(0)"); + else + printf("(%d)", (int)((s-r->program)+(next-s))); + s += 3; + if (op == ANYOF || op == ANYBUT || op == EXACTLY) { + /* Literal string, where present. */ + while (*s != '\0') { +#ifdef MULTILINE + if (*s == '\n') + printf("\\n"); + else +#endif + putchar(*s); + s++; + } + s++; + } + putchar('\n'); + } + + /* Header fields of interest. */ + if (r->regstart != '\0') + printf("start `%c' ", r->regstart); + if (r->reganch) + printf("anchored "); + if (r->regmust != NULL) + printf("must have \"%s\"", r->regmust); + printf("\n"); +} + +/* + - regprop - printable representation of opcode + */ +static char * +regprop(op) +char *op; +{ + register char *p; + static char buf[50]; + + (void) strcpy(buf, ":"); + + switch (OP(op)) { + case BOL: + p = "BOL"; + break; + case EOL: + p = "EOL"; + break; + case ANY: + p = "ANY"; + break; + case ANYOF: + p = "ANYOF"; + break; + case ANYBUT: + p = "ANYBUT"; + break; + case BRANCH: + p = "BRANCH"; + break; + case EXACTLY: + p = "EXACTLY"; + break; + case NOTHING: + p = "NOTHING"; + break; + case BACK: + p = "BACK"; + break; + case END: + p = "END"; + break; + case OPEN+1: + case OPEN+2: + case OPEN+3: + case OPEN+4: + case OPEN+5: + case OPEN+6: + case OPEN+7: + case OPEN+8: + case OPEN+9: + sprintf(buf+strlen(buf), "OPEN%d", (int)(OP(op)-OPEN)); + p = NULL; + break; + case CLOSE+1: + case CLOSE+2: + case CLOSE+3: + case CLOSE+4: + case CLOSE+5: + case CLOSE+6: + case CLOSE+7: + case CLOSE+8: + case CLOSE+9: + sprintf(buf+strlen(buf), "CLOSE%d", (int)(OP(op)-CLOSE)); + p = NULL; + break; + case STAR: + p = "STAR"; + break; + case PLUS: + p = "PLUS"; + break; + default: + regerror("corrupted opcode"); + break; + } + if (p != NULL) + (void) strcat(buf, p); + return(buf); +} +#endif + +/* + * The following is provided for those people who do not have strcspn() in + * their C libraries. They should get off their butts and do something + * about it; at least one public-domain implementation of those (highly + * useful) string routines has been published on Usenet. + */ +#ifdef STRCSPN +/* + * strcspn - find length of initial segment of s1 consisting entirely + * of characters not from s2 + */ + +static int +strcspn(s1, s2) +char *s1; +char *s2; +{ + register char *scan1; + register char *scan2; + register int count; + + count = 0; + for (scan1 = s1; *scan1 != '\0'; scan1++) { + for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */ + if (*scan1 == *scan2++) + return(count); + count++; + } + return(count); +} +#endif diff --git a/src/regexp.h b/src/regexp.h new file mode 100644 index 0000000..cbb1856 --- /dev/null +++ b/src/regexp.h @@ -0,0 +1,51 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* + * Definitions etc. for regexp(3) routines. + * + * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], + * not the System V one. + */ + +#define MULTILINE + +#define NSUBEXP 10 +typedef struct regexp { + char *startp[NSUBEXP]; + char *endp[NSUBEXP]; + char regstart; /* Internal use only. */ + char reganch; /* Internal use only. */ + char *regmust; /* Internal use only. */ + int regmlen; /* Internal use only. */ + char program[1]; /* Unwarranted chumminess with compiler. */ +} regexp; + +extern regexp *regcomp(); +extern int regexec(); +#ifdef MULTILINE +extern int reglexec(); +#endif +extern void regsub(); +extern void regerror(); diff --git a/src/regexpmodule.c b/src/regexpmodule.c new file mode 100644 index 0000000..7c87217 --- /dev/null +++ b/src/regexpmodule.c @@ -0,0 +1,191 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Regular expression objects */ +/* This needs V8 or Henry Spencer's regexp! */ + +#include "allobjects.h" +#include "modsupport.h" + +#include "regexp.h" + +static object *RegexpError; /* Exception */ + +typedef struct { + OB_HEAD + object *re_string; /* The string (for printing) */ + regexp *re_prog; /* The compiled regular expression */ +} regexpobject; + +extern typeobject Regexptype; /* Really static, forward */ + +static regexpobject * +newregexpobject(string, prog) + object *string; + regexp *prog; +{ + regexpobject *re; + re = NEWOBJ(regexpobject, &Regexptype); + if (re != NULL) { + XINCREF(string); + re->re_string = string; + re->re_prog = prog; + } + return re; +} + +/* Regexp methods */ + +static void +regexp_dealloc(re) + regexpobject *re; +{ + XDECREF(re->re_string); + XDEL(re->re_prog); + DEL(re); +} + +static object * +makeresult(prog, buffer) + regexp *prog; + char *buffer; +{ + int n; + object *v; + /* Count substrings found, including \0, the main one */ + for (n = 0; n < 10 && prog->startp[n] != NULL; n++) + ; + v = newtupleobject(n); + if (v != NULL) { + int i; + for (i = 0; i < n; i++) { + object *w, *u; + long start, end; + start = prog->startp[i] - buffer; + end = prog->endp[i] - buffer; + if ( (w = newtupleobject(2)) == NULL || + (u = newintobject(start)) == NULL || + settupleitem(w, 0, u) != 0 || + (u = newintobject(end)) == NULL || + settupleitem(w, 1, u) != 0) { + XDECREF(w); + DECREF(v); + return NULL; + } + settupleitem(v, i, w); + } + } + return v; +} + +static object * +regexp_exec(re, args) + regexpobject *re; + object *args; +{ + object *v; + char *buffer; + int offset; + if (args != NULL && is_stringobject(args)) { + v = args; + offset = 0; + } + else if (!getstrintarg(args, &v, &offset)) + return NULL; + buffer = getstringvalue(v); +#ifndef MULTILINE +#define reglexec(prog, str, offset) regexec((prog), (str)+(offset)) +#endif + if (!reglexec(re->re_prog, buffer, offset)) + return newtupleobject(0); + return makeresult(re->re_prog, buffer); +} + +static struct methodlist regexp_methods[] = { + "exec", regexp_exec, + {NULL, NULL} /* sentinel */ +}; + +static object * +regexp_getattr(re, name) + regexpobject *re; + char *name; +{ + return findmethod(regexp_methods, (object *)re, name); +} + +static typeobject Regexptype = { + OB_HEAD_INIT(&Typetype) + 0, /*ob_size*/ + "regexp", /*tp_name*/ + sizeof(regexpobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + regexp_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + regexp_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; + +void +regerror(str) + char *str; +{ + err_setstr(RegexpError, str); +} + +static object * +regexp_compile(self, args) + object *self; + object *args; +{ + object *string; + regexp *prog; + if (!getstrarg(args, &string)) + return NULL; + prog = regcomp(getstringvalue(string)); + if (prog == NULL) + return NULL; /* regerror() has called err_seterr() */ + return (object *)newregexpobject(string, prog); +} + +static struct methodlist regexp_global_methods[] = { + {"compile", regexp_compile}, + {NULL, NULL} /* sentinel */ +}; + +initregexp() +{ + object *m, *d; + + m = initmodule("regexp", regexp_global_methods); + d = getmoduledict(m); + + /* Initialize regexp.error exception */ + RegexpError = newstringobject("regexp.error"); + if (RegexpError == NULL || dictinsert(d, "error", RegexpError) != 0) + fatal("can't define regexp.error"); +} diff --git a/src/regmagic.h b/src/regmagic.h new file mode 100644 index 0000000..d9da879 --- /dev/null +++ b/src/regmagic.h @@ -0,0 +1,29 @@ +/*********************************************************** +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 first byte of the regexp internal "program" is actually this magic + * number; the start node begins in the second byte. + */ +#define MAGIC 0234 diff --git a/src/regsub.c b/src/regsub.c new file mode 100644 index 0000000..d589f26 --- /dev/null +++ b/src/regsub.c @@ -0,0 +1,115 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* + * regsub + * + * Copyright (c) 1986 by University of Toronto. + * Written by Henry Spencer. Not derived from licensed software. +#ifdef MULTILINE + * Changed by Guido van Rossum, CWI, Amsterdam + * for multi-line support. +#endif + * + * Permission is granted to anyone to use this software for any + * purpose on any computer system, and to redistribute it freely, + * subject to the following restrictions: + * + * 1. The author is not responsible for the consequences of use of + * this software, no matter how awful, even if they arise + * from defects in it. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. + * + * 3. Altered versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + */ +#include <stdio.h> +#include "regexp.h" +#include "regmagic.h" + +#ifndef CHARBITS +#define UCHARAT(p) ((int)*(unsigned char *)(p)) +#else +#define UCHARAT(p) ((int)*(p)&CHARBITS) +#endif + +/* + - regsub - perform substitutions after a regexp match + */ +void +regsub(prog, source, dest) +regexp *prog; +char *source; +char *dest; +{ + register char *src; + register char *dst; + register char c; + register int no; + register int len; + extern char *strncpy(); + + if (prog == NULL || source == NULL || dest == NULL) { + regerror("NULL parm to regsub"); + return; + } + if (UCHARAT(prog->program) != MAGIC) { + regerror("damaged regexp fed to regsub"); + return; + } + + src = source; + dst = dest; + while ((c = *src++) != '\0') { + if (c == '&') + no = 0; + else if (c == '\\' && '0' <= *src && *src <= '9') + no = *src++ - '0'; + else + no = -1; + + if (no < 0) { /* Ordinary character. */ + if (c == '\\' && (*src == '\\' || *src == '&')) + c = *src++; +#ifdef MULTILINE + else if (c == '\\' && *src == 'n') { + c = '\n'; + src++; + } +#endif + *dst++ = c; + } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) { + len = prog->endp[no] - prog->startp[no]; + (void) strncpy(dst, prog->startp[no], len); + dst += len; + if (len != 0 && *(dst-1) == '\0') { /* strncpy hit NUL. */ + regerror("damaged match string"); + return; + } + } + } + *dst++ = '\0'; +} diff --git a/src/rltokenizer.c b/src/rltokenizer.c new file mode 100644 index 0000000..6069148 --- /dev/null +++ b/src/rltokenizer.c @@ -0,0 +1,26 @@ +/*********************************************************** +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 USE_READLINE +#include "tokenizer.c" diff --git a/src/sc_errors.c b/src/sc_errors.c new file mode 100644 index 0000000..be815a1 --- /dev/null +++ b/src/sc_errors.c @@ -0,0 +1,145 @@ +/*********************************************************** +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. + +******************************************************************/ + + +#include <stdio.h> + +#include "PROTO.h" +#include "object.h" +#include "errors.h" +#include "sc_errors.h" +#include "stringobject.h" +#include "tupleobject.h" + +object * +err_scerr(sc_errno) + int sc_errno; +{ + switch(sc_errno) { + + case NoBufSize: + err_setstr(StubcodeError, "Stubcode didn't start with BufSize"); + break; + + case TwoBufSize: + err_setstr(StubcodeError, "Stubcode can't have more then one BufSize"); + break; + + case ElementIsNull: + err_setstr(StubcodeError, "Trying to access an NIL object"); + break; + + case StackOverflow: + err_setstr(StubcodeError, "Stack overflow"); + return NULL; + + case StackUnderflow: + err_setstr(StubcodeError, "Stack underflow"); + return NULL; + + case NoEndLoop: + err_setstr(StubcodeError, "LoopXXX with no EndLoop"); + return NULL; + + case BufferOverflow: + err_setstr(StubcodeError, "Buffer overflow"); + return NULL; + + } + return NULL; +} + +err_scerrset(sc_errno, value, instr) + int sc_errno; + object *value; + char *instr; +{ + object *str, *str1, *t; + + if ((t = newtupleobject(3)) == NULL) { + return -1; + } + if ((str = newstringobject(instr)) == NULL) { + return -1; + } + if (settupleitem(t, 2, str) != 0) { + return -1; + } + INCREF(value); + if (settupleitem(t, 1, value) != 0) { + DECREF(t); + return -1; + } + switch(sc_errno) { + + case TypeFailure: + if ((str1 = newstringobject("Unexpected type")) == NULL) { + DECREF(t); + return -1; + } + break; + + case RangeError: + if ((str1 = newstringobject("Value out of range")) == NULL) { + DECREF(t); + return -1; + } + break; + + case SizeError: + if ((str1 = newstringobject("Value doesn't have the right size")) == NULL) { + DECREF(t); + return -1; + } + break; + + case FlagError: + if ((str1 = newstringobject("Illegal flag value")) == NULL) { + DECREF(t); + return -1; + } + break; + + case TransError: + if ((str1 = newstringobject("hdr.h_status != 0")) == NULL) { + DECREF(t); + return -1; + } + break; + + default: + if ((str1 = newstringobject("sc_errno not found")) == NULL) { + DECREF(t); + return -1; + } + break; + } + if (settupleitem(t, 0, str1) != 0) { + DECREF(t); + return -1; + } + err_setval(StubcodeError, t); + DECREF(t); + return -1; +} diff --git a/src/sc_errors.h b/src/sc_errors.h new file mode 100644 index 0000000..d9fcd01 --- /dev/null +++ b/src/sc_errors.h @@ -0,0 +1,41 @@ +/*********************************************************** +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 NoBufSize 1 +#define TwoBufSize 2 +#define StackOverflow 3 +#define StackUnderflow 4 +#define TypeFailure 5 +#define RangeError 6 +#define SizeError 7 +#define BufferOverflow 8 +#define NoEndLoop 9 +#define FlagError 10 +#define ElementIsNull 11 +#define TransError 12 + +extern object *err_scerr PROTO((int sc_errno)); +extern err_scerrset PROTO((int sc_errno, object *value, char *instr)); +extern object *StubcodeError; diff --git a/src/sc_global.h b/src/sc_global.h new file mode 100644 index 0000000..ec03b15 --- /dev/null +++ b/src/sc_global.h @@ -0,0 +1,137 @@ +/*********************************************************** +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. + +******************************************************************/ + + +/* +** This file contains the data used in Ail, Python and sc2txt. +** +** If you want to add an instuction to the instructions just define +** it here and add the instruction in the function sc_interpreter in +** the file sc_interpreter.c in the switch. You also have to make a +** new function with the name x{instruction_name} in the file +** sc_interpreter. +*/ + +/* +** When you want to change the types of the opcode or the operand +** you maybe need to adjust the options to mypf. And the defines : +** SwapOpcode, SwapOperand. +*/ + +typedef unsigned char TscOpcode; +typedef long TscOperand; + +#define SC_MAGIC 0x19901991 + +#define SwapOpcode(x) x = x +#define SwapOperand(l) ((l))=(((((l))>>24)&0xFF)|((((l))>>8)&0xFF00)|((((l))<<8)&0xFF0000)|((((l))<<24)&0xFF000000)) + +#define STKSIZE 256 + +#define OPERAND 0x80 +#define FLAGS 0x40 + +/* +** The headerfields. The value of the flag is the index of the fields +** array from the file mhdr.c plus one +*/ + +#define H_EXTRA 0x00000001 +#define H_SIZE 0x00000002 +#define H_OFFSET 0x00000003 +#define H_PORT 0x00000004 +#define H_PRIV 0x00000005 +#define PSEUDOFIELD 0x00000006 +#define ALL_FIELDS 0x000000ff + +/* +** The specefiers for the integers +*/ + +#define NOSIGN 0x00000100 +#define INT32 0x00000200 +#define ALLTYPES 0xffffff00 + +/* +** The opcode with no operand +*/ + +#define ListS 0x00 +#define PutVS 0x01 +#define GetVS 0x02 +#define StringS 0x03 +#define Equal 0x04 +#define NoArgs 0x05 + +/* + * Between 0x10 and 0x3f there is space for predefined marshal + * and unmarshal functions or macros that do not have an operand + */ + +#define MarshTC 0x10 +#define UnMarshTC 0x11 + +/* +** The opcode with a number as operand +*/ + +#define BufSize 0x80 +#define Trans 0x81 +#define TTupleS 0x82 +#define Unpack 0x83 +#define PutFS 0x84 +#define TStringSeq 0x85 +#define TStringSlt 0x86 +#define TListSeq 0x87 +#define TListSlt 0x88 +#define LoopPut 0x89 +#define EndLoop 0x8a +#define Dup 0x8b +#define Pop 0x8c +#define Align 0x8d +#define Pack 0x8e +#define LoopGet 0x8f +#define GetFS 0x90 +#define PushI 0x91 + +/* +** Between 0xa0 and 0xbf there is space for predefined marshal +** and unmarshal functions or macros with a numberas operand +*/ + + +/* +** The opcodes with flags as operand +*/ + +#define AilWord 0xc0 +#define PutI 0xc1 +#define PutC 0xc2 +#define GetI 0xc3 +#define GetC 0xc4 + +/* +** Between 0xe0 and 0xff there is space for predefined marshal +** and unmarshal functions or macros with flags as operand +*/ diff --git a/src/sc_interpr.c b/src/sc_interpr.c new file mode 100644 index 0000000..10eb1b2 --- /dev/null +++ b/src/sc_interpr.c @@ -0,0 +1,1352 @@ +/*********************************************************** +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. + +******************************************************************/ + +#if 0 +#define STACK_TRACE +#define SCDEBUG +#endif +#include <stdio.h> + +#include <ailamoeba.h> + +#include "PROTO.h" +#include "sc_global.h" +#include "object.h" +#include "objimpl.h" +#include "stringobject.h" +#include "errors.h" +#include "sc_errors.h" +#include "stubcode.h" +#include "tupleobject.h" +#include "intobject.h" +#include "listobject.h" + +typedef struct s_loopstruct { + struct s_loopstruct *l_next; /* Make a list of it */ + TscOperand l_label; /* Indentify the loop */ + int l_index; /* The index of the list */ + int l_size; /* The size of the list */ + int l_retaddr; /* Addres to jump back */ + int l_endaddr; /* Addres to jump to end */ + object *l_list; /* The list to append to */ +} TsLoop, *TpsLoop; + + +/* +** This file contains the Stubcode interpreter. +** All the instructions have there own function. The interpreter +** reads an instruction from the data and if needed also an operand. +** After this it calls the function that executes the instruction. +*/ + +struct sc_ProcessBlock { + object **stack; + unsigned char *buffer, *data; + int sp, bp, pc, maxbufsize, datsize; + header hdr; + TpsLoop loops; +}; + +extern getcapability(); + +/* + * Clean up the mess the loops make. + */ + +static void +xCleanUpLoops(sc_pb) + struct sc_ProcessBlock *sc_pb; +{ + TpsLoop prev, this; + + if (sc_pb->loops == NULL) + return; + prev = sc_pb->loops; + this = sc_pb->loops->l_next; + while(this) { + free((char *)prev); + prev = this; + this = this->l_next; + } + free((char *)prev); +} + +static int +findendloop(label, sc_pb) + TscOperand label; + struct sc_ProcessBlock *sc_pb; +{ + TscOperand operand; + TscOpcode opcode; + int walk = sc_pb->pc, found = 0; + + while (!found && (walk < sc_pb->datsize)) { + memcpy(&opcode, &sc_pb->data[walk], sizeof(TscOpcode)); + walk += sizeof(TscOpcode); + if (opcode & (FLAGS | OPERAND)) { + memcpy(&operand, &sc_pb->data[walk], sizeof(TscOperand)); + walk += sizeof(TscOperand); + } + if (opcode == EndLoop) + if (operand == label) found = 1; + } + if (found) + return walk; + return -1; +} + +static int +findloop(ret, label, sc_pb) + TpsLoop *ret; + TscOperand label; + struct sc_ProcessBlock *sc_pb; +{ + TpsLoop walk; + + for (walk = sc_pb->loops; walk != NULL; walk = walk->l_next) { + if (walk->l_label == label) break; + } + if (walk == NULL) { + TpsLoop newloop; + + newloop = (TpsLoop)malloc(sizeof(TsLoop)); + if (newloop == NULL) { + err_nomem(); + return -1; + } + newloop->l_label = label; + newloop->l_index = 0; + newloop->l_retaddr = sc_pb->pc - (sizeof(TscOpcode) + sizeof(TscOperand)); + /* + ** We need a correction because the pc points to + ** the instruction after the XXXLoop. + */ + if ((newloop->l_endaddr = findendloop(label, sc_pb)) < 0) { + free((char *)newloop); + err_scerr(NoEndLoop); + return -1; + } + newloop->l_list = NULL; + newloop->l_next = sc_pb->loops; + sc_pb->loops = newloop; + *ret = newloop; + return 1; + } + *ret = walk; + return 0; +} + +#ifdef 0 + +static void +removeloop(this, sc_pb) + TpsLoop this; + struct sc_ProcessBlock *sc_pb; +{ + TpsLoop walk, prev = NULL; + + for (walk = sc_pb->loops; walk != NULL; walk = walk->l_next) { + if (walk->l_label == this->l_label) { + if (prev != NULL) { + prev->l_next = walk->l_next; + } else { + loop = walk->l_next; + } + free((char *)this); + break; + } + prev = walk; + } +} + +#endif + +static int +init(self, sc_pb) + object *self; + struct sc_ProcessBlock *sc_pb; +{ +object *string; +int datasize; + + string = gettupleitem(self, STUBC); + if (string == NULL) + return -1; + sc_pb->data = getstringvalue(string); + if (sc_pb->data == NULL) + return -1; + datasize = (int)getstringsize(string); + if (datasize == -1) + return -1; + sc_pb->stack = (object **)malloc(STKSIZE * sizeof(object *)); + if (sc_pb->stack == NULL) { + err_nomem(); + return -1; + } + sc_pb->bp = sc_pb->sp = sc_pb->pc = 0; + sc_pb->loops = NULL; + return datasize; +} + +static void reinit(sc_pb) + struct sc_ProcessBlock *sc_pb; +{ + int i; + + sc_pb->bp = 0; + for (i = 0; i < sc_pb->sp; i++) { + DECREF(sc_pb->stack[i]); + } + sc_pb->sp = 0; +} + +static void UnInit(self, sc_pb) + object *self; + struct sc_ProcessBlock *sc_pb; +{ + int i; + + free(sc_pb->buffer); + reinit(sc_pb); + free((char *)sc_pb->stack); + xCleanUpLoops(sc_pb); +} + +static object * +stacktop(sc_pb) + struct sc_ProcessBlock *sc_pb; +{ + + if (sc_pb->sp == 0) + return err_scerr(StackUnderflow); + if (sc_pb->sp == (STKSIZE + 1)) + return err_scerr(StackOverflow); + return sc_pb->stack[sc_pb->sp - 1]; +} + +/* + * Push an object on the stack. + */ +static int +xPush(element, sc_pb) + object *element; + struct sc_ProcessBlock *sc_pb; +{ + + if (sc_pb->sp >= STKSIZE) { + err_scerr(StackOverflow); + return -1; + } + if (element == NULL) { + err_scerr(ElementIsNull); + return -1; + } + INCREF(element); +#ifdef STACK_TRACE + printf("pushed :"); + printobject(element, stdout, 0); + printf("\n"); +#endif + sc_pb->stack[sc_pb->sp++] = element; + return 0; +} + +/* + * Perform the RPC. + */ +static int +xTrans(self,cmd, sc_pb) + object *self; + TscOperand cmd; + struct sc_ProcessBlock *sc_pb; +{ + short ret; + capability cap; + object *capobj; + + if ((capobj = gettupleitem(self, CAP)) == NULL) + return -1; + if (getcapability(capobj, &cap) == -1) + return -1; + sc_pb->hdr.h_port = cap.cap_port; + sc_pb->hdr.h_priv = cap.cap_priv; + sc_pb->hdr.h_command = (command)cmd; +#ifdef SCDEBUG + printf("bp = %d maxbufsize = %d\n",sc_pb->bp, sc_pb->maxbufsize); + { + int i; + + for (i = 0; i < sc_pb->bp; i++) { + printf("%x ", sc_pb->buffer[i]); + } + } + printf("\n"); +#endif + ret = trans(&sc_pb->hdr, sc_pb->buffer, (bufsize) sc_pb->bp, + &sc_pb->hdr, sc_pb->buffer, (bufsize)sc_pb->maxbufsize); +#ifdef SCDEBUG + printf("after Trans:ret = %d\n",ret); + { + int i; + + for (i = 0; i < ret; i++) { + printf("%x ", sc_pb->buffer[i]); + } + } + printf("\n"); +#endif + if (ERR_STATUS(ret)) { + amoeba_error(ERR_CONVERT(ret)); + return -1; + } + if (sc_pb->hdr.h_status != 0) { + object *v; + + if ((v = newintobject(sc_pb->hdr.h_status)) == NULL) + return -1; + err_scerrset(TransError, v, "Trans"); + DECREF(v); + return -1; + } + reinit(sc_pb); + return 0; +} + +/* + * Test the tuple size. + */ +static int +xTTupleS(size, sc_pb) + TscOperand size; + struct sc_ProcessBlock *sc_pb; +{ + object *tuple; + + if ((tuple = stacktop(sc_pb)) == NULL) + return -1; + if (!is_tupleobject(tuple)) + return err_scerrset(TypeFailure, tuple, "TTupleS"); + if (gettuplesize(tuple) != (unsigned int)size) + return err_scerrset(SizeError, tuple, "TTupleS"); + return 0; +} + +/* + * Unpack a tuple + */ +static int +xUnpack(size, sc_pb) + TscOperand size; + struct sc_ProcessBlock *sc_pb; +{ + object *tuple, *element; + int i; + + if (size < (TscOperand)2) { + element = newintobject(size); + if (element == NULL) + return -1; + return err_scerrset(SizeError, element, "Unpack"); + } + if ((tuple = stacktop(sc_pb)) == NULL) + return -1; + INCREF(tuple); + if (xPop((TscOperand) 1, sc_pb) != 0) { + DECREF(tuple); + return -1; + } + for (i = 0; i < (int)size; i++) { + if ((element = gettupleitem(tuple, i)) == NULL) { + DECREF(tuple); + return -1; + } + if (xPush(element, sc_pb) != 0) { + DECREF(tuple); + return -1; + } + } + DECREF(tuple); + return 0; +} + +/* + * Marshal the Ailword to a headerfiels. + */ +static int +xAilword(headerfield, sc_pb) + TscOperand headerfield; + struct sc_ProcessBlock *sc_pb; +{ + + switch(headerfield) { + + case H_EXTRA: + sc_pb->hdr.h_extra = (uint16)_ailword; + return 0; + + case H_SIZE: + sc_pb->hdr.h_size = (bufsize)_ailword; + return 0; + + case H_OFFSET: + sc_pb->hdr.h_offset = (int32)_ailword; + return 0; + + default: + { + object *v; + + if ((v = newintobject(headerfield)) == NULL) + return -1; + return err_scerrset(FlagError, v, "Ailword"); + } + } +} + +static int +xStringS(sc_pb) + struct sc_ProcessBlock *sc_pb; +{ + object *size, *string; + int s; + + if ((string = stacktop(sc_pb)) == NULL) + return -1; + if (!is_stringobject(string)) + return err_scerrset(TypeFailure, string, "StringS"); + if ((s = getstringsize(string)) < 0) + return -1; + if (xPop((TscOperand) 1, sc_pb) != 0) + return -1; + if ((size = newintobject(s)) == NULL) + return -1; + if (xPush(size, sc_pb) != 0) { + DECREF(size); + return -1; + } + DECREF(size); + return 0; +} + +/* + * + */ +static int +xListS(sc_pb) + struct sc_ProcessBlock *sc_pb; +{ + object *size, *list; + int s; + + if ((list = stacktop(sc_pb)) == NULL) + return -1; + if (!is_listobject(list)) + return err_scerrset(TypeFailure, list, "ListS"); + if ((s = getlistsize(list)) < 0) + return -1; + if (xPop((TscOperand) 1, sc_pb) != 0) + return -1; + if ((size = newintobject(s)) == NULL) + return -1; + if (xPush(size, sc_pb) != 0) { + DECREF(size); + return -1; + } + DECREF(size); + return 0; +} + +/* + * Marshal a fixed string to the buffer. + */ +static int +xPutFS(size, sc_pb) + TscOperand size; + struct sc_ProcessBlock *sc_pb; +{ + object *string; + char *str; + + if ((string = stacktop(sc_pb)) == NULL) { + return -1; + } + if (!is_stringobject(string)) + return err_scerrset(TypeFailure, string, "PutFS"); + if (getstringsize(string) != size) + return err_scerrset(SizeError, string, "PutFS"); + if ((str = getstringvalue(string)) == NULL) + return -1; + if ((size + sc_pb->bp) > sc_pb->maxbufsize) { + err_scerr(BufferOverflow); + return -1; + } + memcpy(&sc_pb->buffer[sc_pb->bp], str, (int)size); + sc_pb->bp += size; + return xPop((TscOperand) 1, sc_pb); +} + + +/* + * Test the size of a string or list + */ +static int +xTStringSeq(size, sc_pb) + TscOperand size; + struct sc_ProcessBlock *sc_pb; +{ + object *string; + + if ((string = stacktop(sc_pb)) == NULL) + return -1; + if (!is_stringobject(string)) + return err_scerrset(TypeFailure, string, "TStringSeq"); + if (getstringsize(string) != size) + return err_scerrset(SizeError, string, "TStringSeq"); + return 0; +} + +static int +xTStringSlt(size, sc_pb) + TscOperand size; + struct sc_ProcessBlock *sc_pb; +{ + object *string; + + if ((string = stacktop(sc_pb)) == NULL) + return -1; + if (!is_stringobject(string)) + return err_scerrset(TypeFailure, string, "TStringSlt"); + if (getstringsize(string) > size) + return err_scerrset(SizeError, string, "TStringSlt"); + return 0; +} + +static int +xTListSeq(size, sc_pb) + TscOperand size; + struct sc_ProcessBlock *sc_pb; +{ + object *list; + + if ((list = stacktop(sc_pb)) == NULL) + return -1; + if (!is_listobject(list)) + return err_scerrset(TypeFailure, list, "TListSeq"); + if (getlistsize(list) != size) + return err_scerrset(SizeError, list, "TListSeq"); + return 0; +} + +static int +xTListSlt(size, sc_pb) + TscOperand size; + struct sc_ProcessBlock *sc_pb; +{ + object *list; + + if ((list = stacktop(sc_pb)) == NULL) + return -1; + if (!is_listobject(list)) + return err_scerrset(TypeFailure, list, "TListSlt"); + if (getlistsize(list) > size) + return err_scerrset(SizeError, list, "TListSlt"); + return 0; +} + +static int +xPutVS(sc_pb) + struct sc_ProcessBlock *sc_pb; +{ + object *string; + char *str; + int size; + + if ((string = stacktop(sc_pb)) == NULL) + return -1; + if ((size = getstringsize(string)) < 0) + return (size == -1 ? -1 : err_scerrset(SizeError, string, "PutVS")); + if ((str = getstringvalue(string)) == NULL) + return -1; + if (sc_pb->bp + size > sc_pb->maxbufsize) { + err_scerr(BufferOverflow); + return -1; + } + memcpy(&sc_pb->buffer[sc_pb->bp], str, size); + sc_pb->bp += size; + return xPop((TscOperand) 1, sc_pb); +} + +/* + * The loop instructions. + */ +static int +xLoopPut(label, sc_pb) + TscOperand label; + struct sc_ProcessBlock *sc_pb; +{ + TpsLoop this; + object *list, *element; + + if (findloop(&this, label, sc_pb) < 0) + return -1; + if ((list = stacktop(sc_pb)) == NULL) + return -1; + if (!is_listobject(list)) + return err_scerrset(TypeFailure, list, "LoopPut"); + if (this->l_index >= getlistsize(list)) { + sc_pb->pc = this->l_endaddr; + /* + ** Pop the list from the stack + */ + return xPop((TscOperand)1, sc_pb); + } + if ((element = getlistitem(list, this->l_index)) == NULL) + return -1; + return xPush(element, sc_pb); +} + +static int +xLoopGet(label, sc_pb) + TscOperand label; + struct sc_ProcessBlock *sc_pb; +{ + TpsLoop this; + object *element, *integer; + int i; + + if ((i = findloop(&this, label, sc_pb)) < 0) + return -1; + else if (i == 1) { + /* + * It is the first time we enter LoopGet label + */ + if ((this->l_list = newlistobject(0)) == NULL) + return -1; + if ((integer = stacktop(sc_pb)) == NULL) + return -1; + if (!is_intobject(integer)) + return err_scerrset(TypeFailure, integer, "LoopGet"); + this->l_size = getintvalue(integer); + if (xPop((TscOperand) 1, sc_pb) != 0) + return -1; + } else { + if ((element = stacktop(sc_pb)) == NULL) + return -1; + if (addlistitem(this->l_list, element) != 0) + return -1; + if (xPop((TscOperand) 1, sc_pb) != 0) + return -1; + } + if (this->l_index >= this->l_size) { + int ret; + + sc_pb->pc = this->l_endaddr; + ret = xPush(this->l_list, sc_pb); + DECREF(this->l_list); + return ret; + } + return 0; +} + +static int +xEndLoop(label, sc_pb) + TscOperand label; + struct sc_ProcessBlock *sc_pb; +{ + TpsLoop this; + + if (findloop(&this, label, sc_pb) < 0) + return -1; + this ->l_index += 1; + sc_pb->pc = this->l_retaddr; + return 0; +} + +static int +xPutI(flags, sc_pb) + TscOperand flags; + struct sc_ProcessBlock *sc_pb; +{ + object *integer; + + if ((integer = stacktop(sc_pb)) == NULL) + return -1; + if (!is_intobject(integer)) + return err_scerrset(TypeFailure, integer, "PutI"); + if (flags & ALL_FIELDS) { + long i; + + /* + * The integer must be marshalles in the header. + * No type casting according to the type flag because + * we have to cast to the headerfield types. + */ + i = getintvalue(integer); + switch(flags & ALL_FIELDS) { + + case H_EXTRA: + sc_pb->hdr.h_extra = (uint16)i; + break; + + case H_SIZE: + sc_pb->hdr.h_size = (bufsize)i; + break; + + case H_OFFSET: + sc_pb->hdr.h_offset = (int32)i; + break; + + default: + if ((integer = newintobject(flags & ALL_FIELDS)) == NULL) + return -1; + err_scerrset(FlagError, integer, "Ailword"); + DECREF(integer); + return -1; + } + } else { + long i; + + i = getintvalue(integer); + switch(flags & ALLTYPES) { + + case 0: + { + int16 x; + + x = (int16)i; + if ((sc_pb->bp + sizeof(int16)) > sc_pb->maxbufsize) { + err_scerr(BufferOverflow); + return -1; + } + memcpy(&sc_pb->buffer[sc_pb->bp], &x, sizeof(int16)); + sc_pb->bp += sizeof(int16); + break; + } + + case NOSIGN: + { + uint16 x; + + x = (uint16)i; + if ((sc_pb->bp + sizeof(uint16)) > sc_pb->maxbufsize) { + err_scerr(BufferOverflow); + return -1; + } + memcpy(&sc_pb->buffer[sc_pb->bp], &x, sizeof(uint16)); + sc_pb->bp += sizeof(uint16); + break; + } + + case INT32: + { + int32 x; + + x = (int32)i; + if ((sc_pb->bp + sizeof(int32)) > sc_pb->maxbufsize) { + err_scerr(BufferOverflow); + return -1; + } + memcpy(&sc_pb->buffer[sc_pb->bp], &x, sizeof(int32)); + sc_pb->bp += sizeof(int32); + break; + } + + case INT32 | NOSIGN: + { + uint32 x; + + x = (uint32)i; + if ((sc_pb->bp + sizeof(uint32)) > sc_pb->maxbufsize) { + err_scerr(BufferOverflow); + return -1; + } + memcpy(&sc_pb->buffer[sc_pb->bp], &x, sizeof(uint32)); + sc_pb->bp += sizeof(uint32); + break; + } + default: + { + object *x; + + if ((x = newintobject(flags)) == NULL) + return -1; + err_scerrset(FlagError, x, "PutI"); + DECREF(x); + return -1; + } + } + } + return xPop((TscOperand)1, sc_pb); +} + +static int +xPutC(sc_pb) + struct sc_ProcessBlock *sc_pb; +{ + capability cap; + object *capobj; + + if ((capobj = stacktop(sc_pb)) == NULL) + return -1; + if (!is_capobj(capobj)) + return err_scerrset(TypeFailure, capobj, "xPutC"); + if (getcapability(capobj, &cap) != 0) + return -1; + if ((sc_pb->bp + CAPSIZE) > sc_pb->maxbufsize) { + err_scerr(BufferOverflow); + return -1; + } + memcpy(&sc_pb->buffer[sc_pb->bp], &cap, CAPSIZE); + sc_pb->bp += CAPSIZE; + return xPop((TscOperand) 1, sc_pb); +} + +static int +xDup(n, sc_pb) + TscOperand n; + struct sc_ProcessBlock *sc_pb; +{ + + if ((int)n > sc_pb->sp) { + object *i; + + if ((i = newintobject((long)n)) == NULL) + return -1; + err_scerrset(RangeError, i, "Dup"); + DECREF(i); + return -1; + } + return xPush(sc_pb->stack[sc_pb->sp - n], sc_pb); +} + +static int +xPop(n, sc_pb) + TscOperand n; + struct sc_ProcessBlock *sc_pb; +{ + int i; + + if ((sc_pb->sp - (int)n) < 0) { + err_scerr(StackUnderflow); + return -1; + } + for (i = 0; i < (int)n; i++) { + sc_pb->sp--; +#ifdef STACK_TRACE + printf("popped :"); + printobject(sc_pb->stack[sc_pb->sp], stdout, 0); + printf("\n"); +#endif + DECREF(sc_pb->stack[sc_pb->sp]); + } + return 0; +} + +static int +xAlign(n, sc_pb) + TscOperand n; + struct sc_ProcessBlock *sc_pb; +{ + int align = sc_pb->bp % (int)n; + +#ifdef SCDEBUG + printf("Old bp = %d\n", sc_pb->bp); +#endif + sc_pb->bp += (align == 0) ? 0 : ((int)n - align); +#ifdef SCDEBUG + printf("New bp = %d\n", sc_pb->bp); +#endif + return 0; +} + +static int +xPack(size, sc_pb) + TscOperand size; + struct sc_ProcessBlock *sc_pb; +{ + object *element, *tuple; + int i, ret; + + if ((tuple = newtupleobject((int)size)) == NULL) + return -1; + for (i = 0; i < (int)size; i++) { + if ((element = stacktop(sc_pb)) == NULL) + return -1; + if (settupleitem(tuple, (int)size - i - 1, element) != 0) + return -1; + INCREF(element); + if (xPop((TscOperand) 1, sc_pb) != 0) + return -1; + } + ret = xPush(tuple, sc_pb); + DECREF(tuple); + return ret; +} + +static int +xGetVS(sc_pb) + struct sc_ProcessBlock *sc_pb; +{ + object *string, *integer; + int size; + + if ((integer = stacktop(sc_pb)) == NULL) + return -1; + if (!is_intobject(integer)) + return err_scerrset(TypeFailure, integer, "GetVS"); + size = getintvalue(integer); + if ((sc_pb->bp + size) > sc_pb->maxbufsize) { + err_scerr(BufferOverflow); + return -1; + } + if ((string = newsizedstringobject(&sc_pb->buffer[sc_pb->bp], size)) == NULL) + return -1; + sc_pb->bp += size; + if (xPop((TscOperand) 1, sc_pb) != 0) + return -1; + if (xPush(string, sc_pb) != 0) { + return -1; + } + DECREF(string); + return 0; +} + +static int +xGetFS(size, sc_pb) + TscOperand size; + struct sc_ProcessBlock *sc_pb; +{ + object *string; + + if ((sc_pb->bp + (int)size) > sc_pb->maxbufsize) { + err_scerr(BufferOverflow); + return -1; + } + if ((string = newsizedstringobject(&sc_pb->buffer[sc_pb->bp], (int)size)) == NULL) + return -1; + sc_pb->bp += (int)size; + if(xPush(string, sc_pb) != 0) { + return -1; + } + DECREF(string); + return 0; +} + +static int +xGetI(flags, sc_pb) + TscOperand flags; + struct sc_ProcessBlock *sc_pb; +{ + object *integer; + long i; + + if (flags & ALL_FIELDS) { + + switch(flags & ALL_FIELDS) { + + case H_EXTRA: + i = (long)sc_pb->hdr.h_extra; + break; + + case H_SIZE: + i = (long)sc_pb->hdr.h_size; + break; + + case H_OFFSET: + i = (long)sc_pb->hdr.h_offset; + break; + + default: + if ((integer = newintobject(flags & ALL_FIELDS)) == NULL) + return -1; + err_scerrset(FlagError, integer, "Ailword"); + DECREF(integer); + return -1; + } + } else { + switch(flags & ALLTYPES) { + + case 0: + { + int16 x; + + if ((sc_pb->bp + sizeof(int16)) > sc_pb->maxbufsize) { + err_scerr(BufferOverflow); + return -1; + } + memcpy(&x, &sc_pb->buffer[sc_pb->bp], sizeof(int16)); + sc_pb->bp += sizeof(int16); + i = (long)x; + break; + } + + case NOSIGN: + { + uint16 x; + + if ((sc_pb->bp + sizeof(uint16)) > sc_pb->maxbufsize) { + err_scerr(BufferOverflow); + return -1; + } + memcpy(&x, &sc_pb->buffer[sc_pb->bp], sizeof(uint16)); + sc_pb->bp += sizeof(uint16); + i = (long)x; + break; + } + + case INT32: + { + int32 x; + + if ((sc_pb->bp + sizeof(int32)) > sc_pb->maxbufsize) { + err_scerr(BufferOverflow); + return -1; + } + memcpy(&x, &sc_pb->buffer[sc_pb->bp], sizeof(int32)); + sc_pb->bp += sizeof(int32); + i = (long)x; + break; + } + + case INT32 | NOSIGN: + { + uint32 x; + + if ((sc_pb->bp + sizeof(uint32)) > sc_pb->maxbufsize) { + err_scerr(BufferOverflow); + return -1; + } + memcpy(&x, &sc_pb->buffer[sc_pb->bp], sizeof(uint32)); + sc_pb->bp += sizeof(uint32); + i = (long)x; + break; + } + default: + { + if ((integer = newintobject(flags)) == NULL) + return -1; + err_scerrset(FlagError, integer, "GetI"); + DECREF(integer); + return -1; + } + } + } + if ((integer = newintobject(i)) == NULL) + return -1; + if (xPush(integer, sc_pb) != 0) { + DECREF(integer); + return -1; + } + DECREF(integer); + return 0; +} + +static int +xGetC(flags, sc_pb) + TscOperand flags; + struct sc_ProcessBlock *sc_pb; +{ + extern object *newcapobject(); + object *capobj; + capability cap; + + if ((int)flags != 0) { + switch ((int)flags) { + + case PSEUDOFIELD: + cap.cap_port = sc_pb->hdr.h_port; + cap.cap_priv = sc_pb->hdr.h_priv; + break; + } + } else { + if ((CAPSIZE + sc_pb->bp) > sc_pb->maxbufsize) { + err_scerr(BufferOverflow); + return -1; + } + memcpy(&cap, &sc_pb->buffer[sc_pb->bp], CAPSIZE); + } + if ((capobj = newcapobject(&cap)) == NULL) + return -1; + return xPush(capobj, sc_pb); +} + +static int +xEqual(sc_pb) + struct sc_ProcessBlock *sc_pb; +{ + object *int1, *int2; + + if (sc_pb->sp < 2) { + err_scerr(StackUnderflow); + return -1; + } + int1 = sc_pb->stack[sc_pb->sp - 1]; + int2 = sc_pb->stack[sc_pb->sp - 2]; + if ((int1 == NULL) || (int2 == NULL)) + return -1; + if (!is_intobject(int1)) + return err_scerrset(TypeFailure, int1, "Equal"); + if (!is_intobject(int2)) + return err_scerrset(TypeFailure, int2, "Equal"); + if (getintvalue(int1) != getintvalue(int2)) { + object *tmptuple; + + if ((tmptuple = newtupleobject(2)) == NULL) + return -1; + INCREF(int1); + if (settupleitem(tmptuple, 0, int1) != 0) { + DECREF(tmptuple); + DECREF(int1); + return -1; + } + if (settupleitem(tmptuple, 1, int2) != 0) { + DECREF(tmptuple); + DECREF(int2); + return -1; + } + return err_scerrset(SizeError, tmptuple, "Equal"); + } + return 0; +} + +object * +sc_interpreter(self, args) + object *self, *args; +{ +TscOpcode opcode; +TscOperand operand; +int datasize, ret; +object *returnobject; +struct sc_ProcessBlock sc_pb; + + if ((datasize = init(self, &sc_pb)) < 0) + return NULL; + memcpy(&opcode, sc_pb.data, sizeof(TscOpcode)); + sc_pb.datsize = datasize; + sc_pb.pc += sizeof(TscOpcode); + if (opcode != BufSize) { + free((char *)sc_pb.stack); + return err_scerr(NoBufSize); + } + memcpy(&operand, &sc_pb.data[sc_pb.pc], sizeof(TscOperand)); + sc_pb.pc += sizeof(TscOperand); + sc_pb.buffer = (unsigned char *)malloc(operand); + sc_pb.maxbufsize = (int)operand; + if (sc_pb.buffer == NULL) { + free((char *)sc_pb.stack); + return err_nomem(); + } + memcpy(&opcode, &sc_pb.data[sc_pb.pc], sizeof(TscOpcode)); + if (opcode != NoArgs) { + if (xPush(args, &sc_pb) != 0) { + UnInit(self, &sc_pb); + return NULL; + } + } + while (sc_pb.pc < datasize) { + memcpy(&opcode, &sc_pb.data[sc_pb.pc], sizeof(TscOpcode)); + sc_pb.pc += sizeof(TscOpcode); + if (opcode & (OPERAND | FLAGS)) { + memcpy(&operand, &sc_pb.data[sc_pb.pc], sizeof(TscOperand)); + sc_pb.pc += sizeof(TscOperand); + } +#ifdef SCDEBUG + xPrintCode(opcode); + if ((opcode & FLAGS) && (opcode & OPERAND)) + xPrintFlags(operand); + else if (opcode & OPERAND) + xPrintNum(operand); + printf("\n"); + fflush(stdout); +#endif +#ifdef STACK_TRACE + { + register i; + + printf("Stack trace :\n"); + for(i = 0; i < sc_pb.sp; i++) { + printobject(sc_pb.stack[i], stdout, 0); + printf("\n"); + } + } +#endif + switch(opcode) { + + case NoArgs: + ret = 0; + if (args != NULL) { + err_scerrset(TypeFailure, args, "NoArgs"); + ret = -1; + } + break; + + case BufSize: + UnInit(self, &sc_pb); + return err_scerr(TwoBufSize); + + case Trans: + ret = xTrans(self, operand, &sc_pb); + break; + + case TTupleS: + ret = xTTupleS(operand, &sc_pb); + break; + + case Unpack: + ret = xUnpack(operand, &sc_pb); + break; + + case AilWord: + ret = xAilword(operand, &sc_pb); + break; + + case StringS: + ret = xStringS(&sc_pb); + break; + + case ListS: + ret = xListS(&sc_pb); + break; + + case PutFS: + ret = xPutFS(operand, &sc_pb); + break; + + case TStringSeq: + ret = xTStringSeq(operand, &sc_pb); + break; + + case TStringSlt: + ret = xTStringSlt(operand, &sc_pb); + break; + + case PutVS: + ret = xPutVS(&sc_pb); + break; + + case TListSeq: + ret = xTListSeq(operand, &sc_pb); + break; + + case TListSlt: + +ret = xTListSlt(operand, &sc_pb); + break; + + case LoopPut: + ret = xLoopPut(operand, &sc_pb); + break; + + case EndLoop: + ret = xEndLoop(operand, &sc_pb); + break; + + case PutI: + ret = xPutI(operand, &sc_pb); + break; + + case PutC: + ret = xPutC(&sc_pb); + break; + + case Dup: + ret = xDup(operand, &sc_pb); + break; + + case Pop: + ret = xPop(operand, &sc_pb); + break; + + case Align: + ret = xAlign(operand, &sc_pb); + break; + + case Pack: + ret = xPack(operand, &sc_pb); + break; + + case GetVS: + ret = xGetVS(&sc_pb); + break; + + case LoopGet: + ret = xLoopGet(operand, &sc_pb); + break; + + case GetFS: + ret = xGetFS(operand, &sc_pb); + break; + + case GetI: + ret = xGetI(operand, &sc_pb); + break; + + case GetC: + ret = xGetC(operand, &sc_pb); + break; + + case PushI: + { + object *element; + + element = newintobject((long)operand); + if (element == NULL) { + UnInit(self, &sc_pb); + return NULL; + } + ret = xPush(element, &sc_pb); + if (ret == 0) + DECREF(element); + } + break; + + case Equal: + ret = xEqual(&sc_pb); + break; + + default: + { + char errstr[256]; + + UnInit(self, &sc_pb); + sprintf(errstr, "Unknow stubcode %d", opcode); + err_setstr(RuntimeError, errstr); + return NULL; + } + } + if (ret != 0) { + UnInit(self, &sc_pb); + return NULL; + } + } + if (sc_pb.sp > 0) { + INCREF(sc_pb.stack[sc_pb.sp - 1]); + returnobject = sc_pb.stack[sc_pb.sp - 1]; + } else { + INCREF(None); + returnobject = None; + } + UnInit(self, &sc_pb); + return returnobject; +} diff --git a/src/scdbg.c b/src/scdbg.c new file mode 100644 index 0000000..4510896 --- /dev/null +++ b/src/scdbg.c @@ -0,0 +1,152 @@ +/*********************************************************** +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. + +******************************************************************/ + + +#include "sc_global.h" + +void xPrintNum(Num) +TscOperand Num; +{ + + printf(" %ld",(long)Num); +} + +void xPrintFlags(Flags) +TscOperand Flags; +{ +long x; + + x = (long)Flags; + x = x & 0x0000000F; + if (x == H_EXTRA) printf(" h_extra"); + if (x == H_SIZE) printf(" h_size"); + if (x == H_OFFSET) printf(" h_offset"); + if (x == H_PORT) printf(" h_port"); + if (x == H_PRIV) printf(" h_priv"); + if (x == PSEUDOFIELD) printf(" h_port and h_priv"); + x = (long)Flags; + if (x & NOSIGN) printf(" unsigned"); + if (x & INT32) printf(" int32"); +} + +void xPrintCode(Opcode) +TscOpcode Opcode; +{ + + switch (Opcode) { + + case BufSize: printf("BufSize"); + break; + + case Trans: printf("Trans"); + break; + + case TTupleS: printf("TTupleS"); + break; + + case Unpack: printf("Unpack"); + break; + + case AilWord: printf("AilWord"); + break; + + case ListS: printf("ListS"); + break; + + case StringS: printf("StringS"); + break; + + case PutFS: printf("PutFS"); + break; + + case TStringSeq: printf("TStringSeq"); + break; + + case TStringSlt: printf("TStringSlt"); + break; + + case PutVS: printf("PutVS"); + break; + + case TListSeq: printf("TListSeq"); + break; + + case TListSlt: printf("TListSlt"); + break; + + case LoopPut: printf("LoopPut"); + break; + + case EndLoop: printf("EndLoop"); + break; + + case PutI: printf("PutI"); + break; + + case PutC: printf("PutC"); + break; + + case Dup: printf("Dup"); + break; + + case Pop: printf("Pop"); + break; + + case Align: printf("Align"); + break; + + case Pack: printf("Pack"); + break; + + case GetVS: printf("GetVS"); + break; + + case LoopGet: printf("LoopGet"); + break; + + case GetFS: printf("GetFS"); + break; + + case GetI: printf("GetI"); + break; + + case GetC: printf("GetC"); + break; + + case PushI: printf("PushI"); + break; + + case MarshTC: printf("MarshTC"); + break; + + case UnMarshTC: printf("UnMarshTC"); + break; + + case Equal: printf("Equal"); + break; + + default: printf("Unknown opcode %04x",(int)Opcode); + break; + } +} diff --git a/src/sigtype.h b/src/sigtype.h new file mode 100644 index 0000000..5cfd4b3 --- /dev/null +++ b/src/sigtype.h @@ -0,0 +1,51 @@ +/*********************************************************** +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 type of signal handlers is somewhat problematic. + This file encapsulates my knowledge about it: + - on the Mac (THINK C), it's int for 3.0, void for 4.0 + - on other systems, it's usually void, except it's int on vax Ultrix. + Pass -DSIGTYPE=... to cc if you know better. */ + +#ifndef SIGTYPE + +#ifdef THINK_C + +#ifdef THINK_C_3_0 +#define SIGTYPE int +#else +#define SIGTYPE void +#endif + +#else /* !THINK_C */ + +#if defined(vax) && !defined(AMOEBA) +#define SIGTYPE int +#else +#define SIGTYPE void +#endif + +#endif /* !THINK_C */ + +#endif /* !SIGTYPE */ diff --git a/src/stdwinmodule.c b/src/stdwinmodule.c new file mode 100644 index 0000000..75b1fc8 --- /dev/null +++ b/src/stdwinmodule.c @@ -0,0 +1,1697 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Stdwin module */ + +/* Stdwin itself is a module, not a separate object type. + Object types defined here: + wp: a window + dp: a drawing structure (only one can exist at a time) + mp: a menu + tp: a textedit block +*/ + +/* Rules for translating C stdwin function calls into Python stwin: + - All names drop their initial letter 'w' + - Functions with a window as first parameter are methods of window objects + - There is no equivalent for wclose(); just delete the window object + (all references to it!) (XXX maybe this is a bad idea) + - w.begindrawing() returns a drawing object + - There is no equivalent for wenddrawing(win); just delete the drawing + object (all references to it!) (XXX maybe this is a bad idea) + - Functions that may only be used inside wbegindrawing / wendddrawing + are methods of the drawing object; this includes the text measurement + functions (which however have doubles as module functions). + - Methods of the drawing object drop an initial 'draw' from their name + if they have it, e.g., wdrawline() --> d.line() + - The obvious type conversions: int --> intobject; string --> stringobject + - A text parameter followed by a length parameter is only a text (string) + parameter in Python + - A point or other pair of horizontal and vertical coordinates is always + a pair of integers in Python + - Two points forming a rectangle or endpoints of a line segment are a + pair of points in Python + - The arguments to d.elarc() are three points. + - The functions wgetclip() and wsetclip() are translated into + stdwin.getcutbuffer() and stdwin.setcutbuffer(); 'clip' is really + a bad word for what these functions do (clipping has a different + meaning in the drawing world), while cutbuffer is standard X jargon. + XXX This must change again in the light of changes to stdwin! + - For textedit, similar rules hold, but they are less strict. + XXX more? +*/ + +#include "allobjects.h" + +#include "modsupport.h" + +#include "stdwin.h" + +/* Window and menu object types declared here because of forward references */ + +typedef struct { + OB_HEAD + object *w_title; + WINDOW *w_win; + object *w_attr; /* Attributes dictionary */ +} windowobject; + +extern typeobject Windowtype; /* Really static, forward */ + +#define is_windowobject(wp) ((wp)->ob_type == &Windowtype) + +typedef struct { + OB_HEAD + MENU *m_menu; + int m_id; + object *m_attr; /* Attributes dictionary */ +} menuobject; + +extern typeobject Menutype; /* Really static, forward */ + +#define is_menuobject(mp) ((mp)->ob_type == &Menutype) + + +/* Strongly stdwin-specific argument handlers */ + +static int +getmousedetail(v, ep) + object *v; + EVENT *ep; +{ + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 4) + return err_badarg(); + return getintintarg(gettupleitem(v, 0), + &ep->u.where.h, &ep->u.where.v) && + getintarg(gettupleitem(v, 1), &ep->u.where.clicks) && + getintarg(gettupleitem(v, 2), &ep->u.where.button) && + getintarg(gettupleitem(v, 3), &ep->u.where.mask); +} + +static int +getmenudetail(v, ep) + object *v; + EVENT *ep; +{ + object *mp; + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 2) + return err_badarg(); + mp = gettupleitem(v, 0); + if (mp == NULL || !is_menuobject(mp)) + return err_badarg(); + ep->u.m.id = ((menuobject *)mp) -> m_id; + return getintarg(gettupleitem(v, 1), &ep->u.m.item); +} + +static int +geteventarg(v, ep) + object *v; + EVENT *ep; +{ + object *wp, *detail; + int a[4]; + if (v == NULL || !is_tupleobject(v) || gettuplesize(v) != 3) + return err_badarg(); + if (!getintarg(gettupleitem(v, 0), &ep->type)) + return 0; + wp = gettupleitem(v, 1); + if (wp == None) + ep->window = NULL; + else if (wp == NULL || !is_windowobject(wp)) + return err_badarg(); + else + ep->window = ((windowobject *)wp) -> w_win; + detail = gettupleitem(v, 2); + switch (ep->type) { + case WE_CHAR: + if (!is_stringobject(detail) || getstringsize(detail) != 1) + return err_badarg(); + ep->u.character = getstringvalue(detail)[0]; + return 1; + case WE_COMMAND: + return getintarg(detail, &ep->u.command); + case WE_DRAW: + if (!getrectarg(detail, a)) + return 0; + ep->u.area.left = a[0]; + ep->u.area.top = a[1]; + ep->u.area.right = a[2]; + ep->u.area.bottom = a[3]; + return 1; + case WE_MOUSE_DOWN: + case WE_MOUSE_UP: + case WE_MOUSE_MOVE: + return getmousedetail(detail, ep); + case WE_MENU: + return getmenudetail(detail, ep); + default: + return 1; + } +} + + +/* Return construction tools */ + +static object * +makepoint(a, b) + int a, b; +{ + object *v; + object *w; + if ((v = newtupleobject(2)) == NULL) + return NULL; + if ((w = newintobject((long)a)) == NULL || + settupleitem(v, 0, w) != 0 || + (w = newintobject((long)b)) == NULL || + settupleitem(v, 1, w) != 0) { + DECREF(v); + return NULL; + } + return v; +} + +static object * +makerect(a, b, c, d) + int a, b, c, d; +{ + object *v; + object *w; + if ((v = newtupleobject(2)) == NULL) + return NULL; + if ((w = makepoint(a, b)) == NULL || + settupleitem(v, 0, w) != 0 || + (w = makepoint(c, d)) == NULL || + settupleitem(v, 1, w) != 0) { + DECREF(v); + return NULL; + } + return v; +} + +static object * +makemouse(hor, ver, clicks, button, mask) + int hor, ver, clicks, button, mask; +{ + object *v; + object *w; + if ((v = newtupleobject(4)) == NULL) + return NULL; + if ((w = makepoint(hor, ver)) == NULL || + settupleitem(v, 0, w) != 0 || + (w = newintobject((long)clicks)) == NULL || + settupleitem(v, 1, w) != 0 || + (w = newintobject((long)button)) == NULL || + settupleitem(v, 2, w) != 0 || + (w = newintobject((long)mask)) == NULL || + settupleitem(v, 3, w) != 0) { + DECREF(v); + return NULL; + } + return v; +} + +static object * +makemenu(mp, item) + object *mp; + int item; +{ + object *v; + object *w; + if ((v = newtupleobject(2)) == NULL) + return NULL; + INCREF(mp); + if (settupleitem(v, 0, mp) != 0 || + (w = newintobject((long)item)) == NULL || + settupleitem(v, 1, w) != 0) { + DECREF(v); + return NULL; + } + return v; +} + + +/* Drawing objects */ + +typedef struct { + OB_HEAD + windowobject *d_ref; +} drawingobject; + +static drawingobject *Drawing; /* Set to current drawing object, or NULL */ + +/* Drawing methods */ + +static void +drawing_dealloc(dp) + drawingobject *dp; +{ + wenddrawing(dp->d_ref->w_win); + Drawing = NULL; + DECREF(dp->d_ref); + free((char *)dp); +} + +static object * +drawing_generic(dp, args, func) + drawingobject *dp; + object *args; + void (*func) FPROTO((int, int, int, int)); +{ + int a[4]; + if (!getrectarg(args, a)) + return NULL; + (*func)(a[0], a[1], a[2], a[3]); + INCREF(None); + return None; +} + +static object * +drawing_line(dp, args) + drawingobject *dp; + object *args; +{ + drawing_generic(dp, args, wdrawline); +} + +static object * +drawing_xorline(dp, args) + drawingobject *dp; + object *args; +{ + drawing_generic(dp, args, wxorline); +} + +static object * +drawing_circle(dp, args) + drawingobject *dp; + object *args; +{ + int a[3]; + if (!getpointintarg(args, a)) + return NULL; + wdrawcircle(a[0], a[1], a[2]); + INCREF(None); + return None; +} + +static object * +drawing_elarc(dp, args) + drawingobject *dp; + object *args; +{ + int a[6]; + if (!get3pointarg(args, a)) + return NULL; + wdrawelarc(a[0], a[1], a[2], a[3], a[4], a[5]); + INCREF(None); + return None; +} + +static object * +drawing_box(dp, args) + drawingobject *dp; + object *args; +{ + drawing_generic(dp, args, wdrawbox); +} + +static object * +drawing_erase(dp, args) + drawingobject *dp; + object *args; +{ + drawing_generic(dp, args, werase); +} + +static object * +drawing_paint(dp, args) + drawingobject *dp; + object *args; +{ + drawing_generic(dp, args, wpaint); +} + +static object * +drawing_invert(dp, args) + drawingobject *dp; + object *args; +{ + drawing_generic(dp, args, winvert); +} + +static object * +drawing_cliprect(dp, args) + drawingobject *dp; + object *args; +{ + drawing_generic(dp, args, wcliprect); +} + +static object * +drawing_noclip(dp, args) + drawingobject *dp; + object *args; +{ + if (!getnoarg(args)) + return NULL; + wnoclip(); + INCREF(None); + return None; +} + +static object * +drawing_shade(dp, args) + drawingobject *dp; + object *args; +{ + int a[5]; + if (!getrectintarg(args, a)) + return NULL; + wshade(a[0], a[1], a[2], a[3], a[4]); + INCREF(None); + return None; +} + +static object * +drawing_text(dp, args) + drawingobject *dp; + object *args; +{ + int a[2]; + object *s; + if (!getpointstrarg(args, a, &s)) + return NULL; + wdrawtext(a[0], a[1], getstringvalue(s), (int)getstringsize(s)); + INCREF(None); + return None; +} + +/* The following four are also used as stdwin functions */ + +static object * +drawing_lineheight(dp, args) + drawingobject *dp; + object *args; +{ + if (!getnoarg(args)) + return NULL; + return newintobject((long)wlineheight()); +} + +static object * +drawing_baseline(dp, args) + drawingobject *dp; + object *args; +{ + if (!getnoarg(args)) + return NULL; + return newintobject((long)wbaseline()); +} + +static object * +drawing_textwidth(dp, args) + drawingobject *dp; + object *args; +{ + object *s; + if (!getstrarg(args, &s)) + return NULL; + return newintobject( + (long)wtextwidth(getstringvalue(s), (int)getstringsize(s))); +} + +static object * +drawing_textbreak(dp, args) + drawingobject *dp; + object *args; +{ + object *s; + int a; + if (!getstrintarg(args, &s, &a)) + return NULL; + return newintobject( + (long)wtextbreak(getstringvalue(s), (int)getstringsize(s), a)); +} + +static struct methodlist drawing_methods[] = { + {"box", drawing_box}, + {"circle", drawing_circle}, + {"cliprect", drawing_cliprect}, + {"elarc", drawing_elarc}, + {"erase", drawing_erase}, + {"invert", drawing_invert}, + {"line", drawing_line}, + {"noclip", drawing_noclip}, + {"paint", drawing_paint}, + {"shade", drawing_shade}, + {"text", drawing_text}, + {"xorline", drawing_xorline}, + + /* Text measuring methods: */ + {"baseline", drawing_baseline}, + {"lineheight", drawing_lineheight}, + {"textbreak", drawing_textbreak}, + {"textwidth", drawing_textwidth}, + {NULL, NULL} /* sentinel */ +}; + +static object * +drawing_getattr(wp, name) + drawingobject *wp; + char *name; +{ + return findmethod(drawing_methods, (object *)wp, name); +} + +static typeobject Drawingtype = { + OB_HEAD_INIT(&Typetype) + 0, /*ob_size*/ + "drawing", /*tp_name*/ + sizeof(drawingobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + drawing_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + drawing_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; + + +/* Text(edit) objects */ + +typedef struct { + OB_HEAD + TEXTEDIT *t_text; + windowobject *t_ref; + object *t_attr; /* Attributes dictionary */ +} textobject; + +extern typeobject Texttype; /* Really static, forward */ + +static textobject * +newtextobject(wp, left, top, right, bottom) + windowobject *wp; + int left, top, right, bottom; +{ + textobject *tp; + tp = NEWOBJ(textobject, &Texttype); + if (tp == NULL) + return NULL; + tp->t_attr = NULL; + INCREF(wp); + tp->t_ref = wp; + tp->t_text = tecreate(wp->w_win, left, top, right, bottom); + if (tp->t_text == NULL) { + DECREF(tp); + return (textobject *) err_nomem(); + } + return tp; +} + +/* Text(edit) methods */ + +static void +text_dealloc(tp) + textobject *tp; +{ + if (tp->t_text != NULL) + tefree(tp->t_text); + if (tp->t_attr != NULL) + DECREF(tp->t_attr); + DECREF(tp->t_ref); + DEL(tp); +} + +static object * +text_arrow(self, args) + textobject *self; + object *args; +{ + int code; + if (!getintarg(args, &code)) + return NULL; + tearrow(self->t_text, code); + INCREF(None); + return None; +} + +static object * +text_draw(self, args) + textobject *self; + object *args; +{ + register TEXTEDIT *tp = self->t_text; + int a[4]; + int left, top, right, bottom; + if (!getrectarg(args, a)) + return NULL; + if (Drawing != NULL) { + err_setstr(RuntimeError, "not drawing"); + return NULL; + } + /* Clip to text area and ignore if area is empty */ + left = tegetleft(tp); + top = tegettop(tp); + right = tegetright(tp); + bottom = tegetbottom(tp); + if (a[0] < left) a[0] = left; + if (a[1] < top) a[1] = top; + if (a[2] > right) a[2] = right; + if (a[3] > bottom) a[3] = bottom; + if (a[0] < a[2] && a[1] < a[3]) { + /* Hide/show focus around draw call; these are undocumented, + but required here to get the highlighting correct. + The call to werase is also required for this reason. + Finally, this forces us to require (above) that we are NOT + already drawing. */ + tehidefocus(tp); + wbegindrawing(self->t_ref->w_win); + werase(a[0], a[1], a[2], a[3]); + tedrawnew(tp, a[0], a[1], a[2], a[3]); + wenddrawing(self->t_ref->w_win); + teshowfocus(tp); + } + INCREF(None); + return None; +} + +static object * +text_event(self, args) + textobject *self; + object *args; +{ + register TEXTEDIT *tp = self->t_text; + EVENT e; + if (!geteventarg(args, &e)) + return NULL; + if (e.type == WE_MOUSE_DOWN) { + /* Cheat at the margins */ + int width, height; + wgetdocsize(e.window, &width, &height); + if (e.u.where.h < 0 && tegetleft(tp) == 0) + e.u.where.h = 0; + else if (e.u.where.h > width && tegetright(tp) == width) + e.u.where.h = width; + if (e.u.where.v < 0 && tegettop(tp) == 0) + e.u.where.v = 0; + else if (e.u.where.v > height && tegetright(tp) == height) + e.u.where.v = height; + } + return newintobject((long) teevent(tp, &e)); +} + +static object * +text_getfocus(self, args) + textobject *self; + object *args; +{ + if (!getnoarg(args)) + return NULL; + return makepoint(tegetfoc1(self->t_text), tegetfoc2(self->t_text)); +} + +static object * +text_getfocustext(self, args) + textobject *self; + object *args; +{ + int f1, f2; + char *text; + if (!getnoarg(args)) + return NULL; + f1 = tegetfoc1(self->t_text); + f2 = tegetfoc2(self->t_text); + text = tegettext(self->t_text); + return newsizedstringobject(text + f1, f2-f1); +} + +static object * +text_getrect(self, args) + textobject *self; + object *args; +{ + if (!getnoarg(args)) + return NULL; + return makerect(tegetleft(self->t_text), + tegettop(self->t_text), + tegetright(self->t_text), + tegetbottom(self->t_text)); +} + +static object * +text_gettext(self, args) + textobject *self; + object *args; +{ + if (!getnoarg(args)) + return NULL; + return newsizedstringobject(tegettext(self->t_text), + tegetlen(self->t_text)); +} + +static object * +text_move(self, args) + textobject *self; + object *args; +{ + int a[4]; + if (!getrectarg(args, a)) + return NULL; + temovenew(self->t_text, a[0], a[1], a[2], a[3]); + INCREF(None); + return None; +} + +static object * +text_setfocus(self, args) + textobject *self; + object *args; +{ + int a[2]; + if (!getpointarg(args, a)) + return NULL; + tesetfocus(self->t_text, a[0], a[1]); + INCREF(None); + return None; +} + +static object * +text_replace(self, args) + textobject *self; + object *args; +{ + object *text; + if (!getstrarg(args, &text)) + return NULL; + tereplace(self->t_text, getstringvalue(text)); + INCREF(None); + return None; +} + +static struct methodlist text_methods[] = { + "arrow", text_arrow, + "draw", text_draw, + "event", text_event, + "getfocus", text_getfocus, + "getfocustext", text_getfocustext, + "getrect", text_getrect, + "gettext", text_gettext, + "move", text_move, + "replace", text_replace, + "setfocus", text_setfocus, + {NULL, NULL} /* sentinel */ +}; + +static object * +text_getattr(tp, name) + textobject *tp; + char *name; +{ + if (tp->t_attr != NULL) { + object *v = dictlookup(tp->t_attr, name); + if (v != NULL) { + INCREF(v); + return v; + } + } + return findmethod(text_methods, (object *)tp, name); +} + +static int +text_setattr(tp, name, v) + textobject *tp; + char *name; + object *v; +{ + if (tp->t_attr == NULL) { + tp->t_attr = newdictobject(); + if (tp->t_attr == NULL) + return -1; + } + if (v == NULL) + return dictremove(tp->t_attr, name); + else + return dictinsert(tp->t_attr, name, v); +} + +static typeobject Texttype = { + OB_HEAD_INIT(&Typetype) + 0, /*ob_size*/ + "textedit", /*tp_name*/ + sizeof(textobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + text_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + text_getattr, /*tp_getattr*/ + text_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; + + +/* Menu objects */ + +#define IDOFFSET 10 /* Menu IDs we use start here */ +#define MAXNMENU 20 /* Max #menus we allow */ +static menuobject *menulist[MAXNMENU]; + +static menuobject * +newmenuobject(title) + object *title; +{ + int id; + MENU *menu; + menuobject *mp; + for (id = 0; id < MAXNMENU; id++) { + if (menulist[id] == NULL) + break; + } + if (id >= MAXNMENU) + return (menuobject *) err_nomem(); + menu = wmenucreate(id + IDOFFSET, getstringvalue(title)); + if (menu == NULL) + return (menuobject *) err_nomem(); + mp = NEWOBJ(menuobject, &Menutype); + if (mp != NULL) { + mp->m_menu = menu; + mp->m_id = id + IDOFFSET; + mp->m_attr = NULL; + menulist[id] = mp; + } + else + wmenudelete(menu); + return mp; +} + +/* Menu methods */ + +static void +menu_dealloc(mp) + menuobject *mp; +{ + + int id = mp->m_id - IDOFFSET; + if (id >= 0 && id < MAXNMENU && menulist[id] == mp) { + menulist[id] = NULL; + } + wmenudelete(mp->m_menu); + if (mp->m_attr != NULL) + DECREF(mp->m_attr); + DEL(mp); +} + +static object * +menu_additem(self, args) + menuobject *self; + object *args; +{ + object *text; + int shortcut; + if (is_tupleobject(args)) { + object *v; + if (!getstrstrarg(args, &text, &v)) + return NULL; + if (getstringsize(v) != 1) { + err_badarg(); + return NULL; + } + shortcut = *getstringvalue(v) & 0xff; + } + else { + if (!getstrarg(args, &text)) + return NULL; + shortcut = -1; + } + wmenuadditem(self->m_menu, getstringvalue(text), shortcut); + INCREF(None); + return None; +} + +static object * +menu_setitem(self, args) + menuobject *self; + object *args; +{ + int index; + object *text; + if (!getintstrarg(args, &index, &text)) + return NULL; + wmenusetitem(self->m_menu, index, getstringvalue(text)); + INCREF(None); + return None; +} + +static object * +menu_enable(self, args) + menuobject *self; + object *args; +{ + int index; + int flag; + if (!getintintarg(args, &index, &flag)) + return NULL; + wmenuenable(self->m_menu, index, flag); + INCREF(None); + return None; +} + +static object * +menu_check(self, args) + menuobject *self; + object *args; +{ + int index; + int flag; + if (!getintintarg(args, &index, &flag)) + return NULL; + wmenucheck(self->m_menu, index, flag); + INCREF(None); + return None; +} + +static struct methodlist menu_methods[] = { + "additem", menu_additem, + "setitem", menu_setitem, + "enable", menu_enable, + "check", menu_check, + {NULL, NULL} /* sentinel */ +}; + +static object * +menu_getattr(mp, name) + menuobject *mp; + char *name; +{ + if (mp->m_attr != NULL) { + object *v = dictlookup(mp->m_attr, name); + if (v != NULL) { + INCREF(v); + return v; + } + } + return findmethod(menu_methods, (object *)mp, name); +} + +static int +menu_setattr(mp, name, v) + menuobject *mp; + char *name; + object *v; +{ + if (mp->m_attr == NULL) { + mp->m_attr = newdictobject(); + if (mp->m_attr == NULL) + return -1; + } + if (v == NULL) + return dictremove(mp->m_attr, name); + else + return dictinsert(mp->m_attr, name, v); +} + +static typeobject Menutype = { + OB_HEAD_INIT(&Typetype) + 0, /*ob_size*/ + "menu", /*tp_name*/ + sizeof(menuobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + menu_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + menu_getattr, /*tp_getattr*/ + menu_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; + + +/* Windows */ + +#define MAXNWIN 50 +static windowobject *windowlist[MAXNWIN]; + +/* Window methods */ + +static void +window_dealloc(wp) + windowobject *wp; +{ + if (wp->w_win != NULL) { + int tag = wgettag(wp->w_win); + if (tag >= 0 && tag < MAXNWIN) + windowlist[tag] = NULL; + else + fprintf(stderr, "XXX help! tag %d in window_dealloc\n", + tag); + wclose(wp->w_win); + } + DECREF(wp->w_title); + if (wp->w_attr != NULL) + DECREF(wp->w_attr); + free((char *)wp); +} + +static void +window_print(wp, fp, flags) + windowobject *wp; + FILE *fp; + int flags; +{ + fprintf(fp, "<window titled '%s'>", getstringvalue(wp->w_title)); +} + +static object * +window_begindrawing(wp, args) + windowobject *wp; + object *args; +{ + drawingobject *dp; + if (!getnoarg(args)) + return NULL; + if (Drawing != NULL) { + err_setstr(RuntimeError, "already drawing"); + return NULL; + } + dp = NEWOBJ(drawingobject, &Drawingtype); + if (dp == NULL) + return NULL; + Drawing = dp; + INCREF(wp); + dp->d_ref = wp; + wbegindrawing(wp->w_win); + return (object *)dp; +} + +static object * +window_change(wp, args) + windowobject *wp; + object *args; +{ + int a[4]; + if (!getrectarg(args, a)) + return NULL; + wchange(wp->w_win, a[0], a[1], a[2], a[3]); + INCREF(None); + return None; +} + +static object * +window_gettitle(wp, args) + windowobject *wp; + object *args; +{ + if (!getnoarg(args)) + return NULL; + INCREF(wp->w_title); + return wp->w_title; +} + +static object * +window_getwinsize(wp, args) + windowobject *wp; + object *args; +{ + int width, height; + if (!getnoarg(args)) + return NULL; + wgetwinsize(wp->w_win, &width, &height); + return makepoint(width, height); +} + +static object * +window_getdocsize(wp, args) + windowobject *wp; + object *args; +{ + int width, height; + if (!getnoarg(args)) + return NULL; + wgetdocsize(wp->w_win, &width, &height); + return makepoint(width, height); +} + +static object * +window_getorigin(wp, args) + windowobject *wp; + object *args; +{ + int width, height; + if (!getnoarg(args)) + return NULL; + wgetorigin(wp->w_win, &width, &height); + return makepoint(width, height); +} + +static object * +window_scroll(wp, args) + windowobject *wp; + object *args; +{ + int a[6]; + if (!getrectpointarg(args, a)) + return NULL; + wscroll(wp->w_win, a[0], a[1], a[2], a[3], a[4], a[5]); + INCREF(None); + return None; +} + +static object * +window_setdocsize(wp, args) + windowobject *wp; + object *args; +{ + int a[2]; + if (!getpointarg(args, a)) + return NULL; + wsetdocsize(wp->w_win, a[0], a[1]); + INCREF(None); + return None; +} + +static object * +window_setorigin(wp, args) + windowobject *wp; + object *args; +{ + int a[2]; + if (!getpointarg(args, a)) + return NULL; + wsetorigin(wp->w_win, a[0], a[1]); + INCREF(None); + return None; +} + +static object * +window_settitle(wp, args) + windowobject *wp; + object *args; +{ + object *title; + if (!getstrarg(args, &title)) + return NULL; + DECREF(wp->w_title); + INCREF(title); + wp->w_title = title; + wsettitle(wp->w_win, getstringvalue(title)); + INCREF(None); + return None; +} + +static object * +window_show(wp, args) + windowobject *wp; + object *args; +{ + int a[4]; + if (!getrectarg(args, a)) + return NULL; + wshow(wp->w_win, a[0], a[1], a[2], a[3]); + INCREF(None); + return None; +} + +static object * +window_settimer(wp, args) + windowobject *wp; + object *args; +{ + int a; + if (!getintarg(args, &a)) + return NULL; + wsettimer(wp->w_win, a); + INCREF(None); + return None; +} + +static object * +window_menucreate(self, args) + windowobject *self; + object *args; +{ + menuobject *mp; + object *title; + if (!getstrarg(args, &title)) + return NULL; + wmenusetdeflocal(1); + mp = newmenuobject(title); + if (mp == NULL) + return NULL; + wmenuattach(self->w_win, mp->m_menu); + return (object *)mp; +} + +static object * +window_textcreate(self, args) + windowobject *self; + object *args; +{ + textobject *tp; + int a[4]; + if (!getrectarg(args, a)) + return NULL; + return (object *) + newtextobject(self, a[0], a[1], a[2], a[3]); +} + +static object * +window_setselection(self, args) + windowobject *self; + object *args; +{ + int sel; + object *str; + int ok; + if (!getintstrarg(args, &sel, &str)) + return NULL; + ok = wsetselection(self->w_win, sel, + getstringvalue(str), (int)getstringsize(str)); + return newintobject(ok); +} + +static object * +window_setwincursor(self, args) + windowobject *self; + object *args; +{ + object *str; + CURSOR *c; + if (!getstrarg(args, &str)) + return NULL; + c = wfetchcursor(getstringvalue(str)); + if (c == NULL) { + err_setstr(RuntimeError, "no such cursor"); + return NULL; + } + wsetwincursor(self->w_win, c); + INCREF(None); + return None; +} + +static struct methodlist window_methods[] = { + {"begindrawing",window_begindrawing}, + {"change", window_change}, + {"getdocsize", window_getdocsize}, + {"getorigin", window_getorigin}, + {"gettitle", window_gettitle}, + {"getwinsize", window_getwinsize}, + {"menucreate", window_menucreate}, + {"scroll", window_scroll}, + {"setwincursor",window_setwincursor}, + {"setdocsize", window_setdocsize}, + {"setorigin", window_setorigin}, + {"setselection",window_setselection}, + {"settimer", window_settimer}, + {"settitle", window_settitle}, + {"show", window_show}, + {"textcreate", window_textcreate}, + {NULL, NULL} /* sentinel */ +}; + +static object * +window_getattr(wp, name) + windowobject *wp; + char *name; +{ + if (wp->w_attr != NULL) { + object *v = dictlookup(wp->w_attr, name); + if (v != NULL) { + INCREF(v); + return v; + } + } + return findmethod(window_methods, (object *)wp, name); +} + +static int +window_setattr(wp, name, v) + windowobject *wp; + char *name; + object *v; +{ + if (wp->w_attr == NULL) { + wp->w_attr = newdictobject(); + if (wp->w_attr == NULL) + return -1; + } + if (v == NULL) + return dictremove(wp->w_attr, name); + else + return dictinsert(wp->w_attr, name, v); +} + +static typeobject Windowtype = { + OB_HEAD_INIT(&Typetype) + 0, /*ob_size*/ + "window", /*tp_name*/ + sizeof(windowobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + window_dealloc, /*tp_dealloc*/ + window_print, /*tp_print*/ + window_getattr, /*tp_getattr*/ + window_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; + +/* Stdwin methods */ + +static object * +stdwin_open(sw, args) + object *sw; + object *args; +{ + int tag; + object *title; + windowobject *wp; + if (!getstrarg(args, &title)) + return NULL; + for (tag = 0; tag < MAXNWIN; tag++) { + if (windowlist[tag] == NULL) + break; + } + if (tag >= MAXNWIN) + return err_nomem(); + wp = NEWOBJ(windowobject, &Windowtype); + if (wp == NULL) + return NULL; + INCREF(title); + wp->w_title = title; + wp->w_win = wopen(getstringvalue(title), (void (*)()) NULL); + wp->w_attr = NULL; + if (wp->w_win == NULL) { + DECREF(wp); + return NULL; + } + windowlist[tag] = wp; + wsettag(wp->w_win, tag); + return (object *)wp; +} + +static object * +stdwin_get_poll_event(poll, args) + int poll; + object *args; +{ + EVENT e; + object *v, *w; + if (!getnoarg(args)) + return NULL; + if (Drawing != NULL) { + err_setstr(RuntimeError, "cannot getevent() while drawing"); + return NULL; + } +/* again: */ + if (poll) { + if (!wpollevent(&e)) { + INCREF(None); + return None; + } + } + else + wgetevent(&e); + if (e.type == WE_COMMAND && e.u.command == WC_CANCEL) { + /* Turn keyboard interrupts into exceptions */ + err_set(KeyboardInterrupt); + return NULL; + } +/* + if (e.window == NULL && (e.type == WE_COMMAND || e.type == WE_CHAR)) + goto again; +*/ + if (e.type == WE_COMMAND && e.u.command == WC_CLOSE) { + /* Turn WC_CLOSE commands into WE_CLOSE events */ + e.type = WE_CLOSE; + } + v = newtupleobject(3); + if (v == NULL) + return NULL; + if ((w = newintobject((long)e.type)) == NULL) { + DECREF(v); + return NULL; + } + settupleitem(v, 0, w); + if (e.window == NULL) + w = None; + else { + int tag = wgettag(e.window); + if (tag < 0 || tag >= MAXNWIN || windowlist[tag] == NULL) + w = None; + else + w = (object *)windowlist[tag]; +#ifdef sgi + /* XXX Trap for unexplained weird bug */ + if ((long)w == (long)0x80000001) { + err_setstr(SystemError, + "bad pointer in stdwin.getevent()"); + return NULL; + } +#endif + } + INCREF(w); + settupleitem(v, 1, w); + switch (e.type) { + case WE_CHAR: + { + char c[1]; + c[0] = e.u.character; + w = newsizedstringobject(c, 1); + } + break; + case WE_COMMAND: + w = newintobject((long)e.u.command); + break; + case WE_DRAW: + w = makerect(e.u.area.left, e.u.area.top, + e.u.area.right, e.u.area.bottom); + break; + case WE_MOUSE_DOWN: + case WE_MOUSE_MOVE: + case WE_MOUSE_UP: + w = makemouse(e.u.where.h, e.u.where.v, + e.u.where.clicks, + e.u.where.button, + e.u.where.mask); + break; + case WE_MENU: + if (e.u.m.id >= IDOFFSET && e.u.m.id < IDOFFSET+MAXNMENU && + menulist[e.u.m.id - IDOFFSET] != NULL) + w = (object *)menulist[e.u.m.id - IDOFFSET]; + else + w = None; + w = makemenu(w, e.u.m.item); + break; + case WE_LOST_SEL: + w = newintobject((long)e.u.sel); + break; + default: + w = None; + INCREF(w); + break; + } + if (w == NULL) { + DECREF(v); + return NULL; + } + settupleitem(v, 2, w); + return v; +} + +static object * +stdwin_getevent(sw, args) + object *sw; + object *args; +{ + return stdwin_get_poll_event(0, args); +} + +static object * +stdwin_pollevent(sw, args) + object *sw; + object *args; +{ + return stdwin_get_poll_event(1, args); +} + +static object * +stdwin_setdefwinpos(sw, args) + object *sw; + object *args; +{ + int a[2]; + if (!getpointarg(args, a)) + return NULL; + wsetdefwinpos(a[0], a[1]); + INCREF(None); + return None; +} + +static object * +stdwin_setdefwinsize(sw, args) + object *sw; + object *args; +{ + int a[2]; + if (!getpointarg(args, a)) + return NULL; + wsetdefwinsize(a[0], a[1]); + INCREF(None); + return None; +} + +static object * +stdwin_getdefwinpos(wp, args) + windowobject *wp; + object *args; +{ + int h, v; + if (!getnoarg(args)) + return NULL; + wgetdefwinpos(&h, &v); + return makepoint(h, v); +} + +static object * +stdwin_getdefwinsize(wp, args) + windowobject *wp; + object *args; +{ + int width, height; + if (!getnoarg(args)) + return NULL; + wgetdefwinsize(&width, &height); + return makepoint(width, height); +} + +static object * +stdwin_menucreate(self, args) + object *self; + object *args; +{ + object *title; + if (!getstrarg(args, &title)) + return NULL; + wmenusetdeflocal(0); + return (object *)newmenuobject(title); +} + +static object * +stdwin_askfile(self, args) + object *self; + object *args; +{ + object *prompt, *dflt; + int new, ret; + char buf[256]; + if (!getstrstrintarg(args, &prompt, &dflt, &new)) + return NULL; + strncpy(buf, getstringvalue(dflt), sizeof buf); + buf[sizeof buf - 1] = '\0'; + ret = waskfile(getstringvalue(prompt), buf, sizeof buf, new); + if (!ret) { + err_set(KeyboardInterrupt); + return NULL; + } + return newstringobject(buf); +} + +static object * +stdwin_askync(self, args) + object *self; + object *args; +{ + object *prompt; + int new, ret; + if (!getstrintarg(args, &prompt, &new)) + return NULL; + ret = waskync(getstringvalue(prompt), new); + if (ret < 0) { + err_set(KeyboardInterrupt); + return NULL; + } + return newintobject((long)ret); +} + +static object * +stdwin_askstr(self, args) + object *self; + object *args; +{ + object *prompt, *dflt; + int ret; + char buf[256]; + if (!getstrstrarg(args, &prompt, &dflt)) + return NULL; + strncpy(buf, getstringvalue(dflt), sizeof buf); + buf[sizeof buf - 1] = '\0'; + ret = waskstr(getstringvalue(prompt), buf, sizeof buf); + if (!ret) { + err_set(KeyboardInterrupt); + return NULL; + } + return newstringobject(buf); +} + +static object * +stdwin_message(self, args) + object *self; + object *args; +{ + object *msg; + if (!getstrarg(args, &msg)) + return NULL; + wmessage(getstringvalue(msg)); + INCREF(None); + return None; +} + +static object * +stdwin_fleep(self, args) + object *self; + object *args; +{ + if (!getnoarg(args)) + return NULL; + wfleep(); + INCREF(None); + return None; +} + +static object * +stdwin_setcutbuffer(self, args) + object *self; + object *args; +{ + int i; + object *str; + if (!getintstrarg(args, &i, &str)) + return NULL; + wsetcutbuffer(i, getstringvalue(str), getstringsize(str)); + INCREF(None); + return None; +} + +static object * +stdwin_getcutbuffer(self, args) + object *self; + object *args; +{ + int i; + char *str; + int len; + if (!getintarg(args, &i)) + return NULL; + str = wgetcutbuffer(i, &len); + if (str == NULL) { + str = ""; + len = 0; + } + return newsizedstringobject(str, len); +} + +static object * +stdwin_rotatecutbuffers(self, args) + object *self; + object *args; +{ + int i; + if (!getintarg(args, &i)) + return NULL; + wrotatecutbuffers(i); + INCREF(None); + return None; +} + +static object * +stdwin_getselection(self, args) + object *self; + object *args; +{ + int sel; + char *data; + int len; + if (!getintarg(args, &sel)) + return NULL; + data = wgetselection(sel, &len); + if (data == NULL) { + data = ""; + len = 0; + } + return newsizedstringobject(data, len); +} + +static object * +stdwin_resetselection(self, args) + object *self; + object *args; +{ + int sel; + if (!getintarg(args, &sel)) + return NULL; + wresetselection(sel); + INCREF(None); + return None; +} + +static struct methodlist stdwin_methods[] = { + {"askfile", stdwin_askfile}, + {"askstr", stdwin_askstr}, + {"askync", stdwin_askync}, + {"fleep", stdwin_fleep}, + {"getselection", stdwin_getselection}, + {"getcutbuffer", stdwin_getcutbuffer}, + {"getdefwinpos", stdwin_getdefwinpos}, + {"getdefwinsize", stdwin_getdefwinsize}, + {"getevent", stdwin_getevent}, + {"menucreate", stdwin_menucreate}, + {"message", stdwin_message}, + {"open", stdwin_open}, + {"pollevent", stdwin_pollevent}, + {"resetselection", stdwin_resetselection}, + {"rotatecutbuffers", stdwin_rotatecutbuffers}, + {"setcutbuffer", stdwin_setcutbuffer}, + {"setdefwinpos", stdwin_setdefwinpos}, + {"setdefwinsize", stdwin_setdefwinsize}, + + /* Text measuring methods borrow code from drawing objects: */ + {"baseline", drawing_baseline}, + {"lineheight", drawing_lineheight}, + {"textbreak", drawing_textbreak}, + {"textwidth", drawing_textwidth}, + {NULL, NULL} /* sentinel */ +}; + +void +initstdwin() +{ + static int inited; + if (!inited) { + winit(); + inited = 1; + } + initmodule("stdwin", stdwin_methods); +} diff --git a/src/stdwinobject.h b/src/stdwinobject.h new file mode 100644 index 0000000..a6d20b8 --- /dev/null +++ b/src/stdwinobject.h @@ -0,0 +1,31 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Stdwin object interface */ + +extern typeobject Stdwintype; + +#define is_stdwinobject(op) ((op)->ob_type == &Stdwintype) + +extern object *newstdwinobject PROTO((void)); diff --git a/src/strdup.c b/src/strdup.c new file mode 100644 index 0000000..e39796d --- /dev/null +++ b/src/strdup.c @@ -0,0 +1,39 @@ +/*********************************************************** +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. + +******************************************************************/ + +#include "PROTO.h" +#include "malloc.h" +#include "string.h" + +char * +strdup(str) + const char *str; +{ + if (str != NULL) { + register char *copy = NEW(char, strlen(str) + 1); + if (copy != NULL) + return strcpy(copy, str); + } + return NULL; +} diff --git a/src/strerror.c b/src/strerror.c new file mode 100644 index 0000000..b2d9da9 --- /dev/null +++ b/src/strerror.c @@ -0,0 +1,47 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* PD implementation of strerror() for systems that don't have it. + Author: Guido van Rossum, CWI Amsterdam, Oct. 1990, <[email protected]>. */ + +#include <stdio.h> + +extern int sys_nerr; +extern char *sys_errlist[]; + +char * +strerror(err) + int err; +{ + static char buf[20]; + if (err >= 0 && err < sys_nerr) + return sys_errlist[err]; + sprintf(buf, "Unknown errno %d", err); + return buf; +} + +#ifdef THINK_C +int sys_nerr = 0; +char *sys_errlist[1] = 0; +#endif diff --git a/src/stringobject.c b/src/stringobject.c new file mode 100644 index 0000000..d27243f --- /dev/null +++ b/src/stringobject.c @@ -0,0 +1,347 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* String object implementation */ + +#include "allobjects.h" + +object * +newsizedstringobject(str, size) + char *str; + int size; +{ + register stringobject *op = (stringobject *) + malloc(sizeof(stringobject) + size * sizeof(char)); + if (op == NULL) + return err_nomem(); + NEWREF(op); + op->ob_type = &Stringtype; + op->ob_size = size; + if (str != NULL) + memcpy(op->ob_sval, str, size); + op->ob_sval[size] = '\0'; + return (object *) op; +} + +object * +newstringobject(str) + char *str; +{ + register unsigned int size = strlen(str); + register stringobject *op = (stringobject *) + malloc(sizeof(stringobject) + size * sizeof(char)); + if (op == NULL) + return err_nomem(); + NEWREF(op); + op->ob_type = &Stringtype; + op->ob_size = size; + strcpy(op->ob_sval, str); + return (object *) op; +} + +unsigned int +getstringsize(op) + register object *op; +{ + if (!is_stringobject(op)) { + err_badcall(); + return -1; + } + return ((stringobject *)op) -> ob_size; +} + +/*const*/ char * +getstringvalue(op) + register object *op; +{ + if (!is_stringobject(op)) { + err_badcall(); + return NULL; + } + return ((stringobject *)op) -> ob_sval; +} + +/* Methods */ + +static void +stringprint(op, fp, flags) + stringobject *op; + FILE *fp; + int flags; +{ + int i; + char c; + if (flags & PRINT_RAW) { + fwrite(op->ob_sval, 1, (int) op->ob_size, fp); + return; + } + fprintf(fp, "'"); + for (i = 0; i < op->ob_size; i++) { + c = op->ob_sval[i]; + if (c == '\'' || c == '\\') + fprintf(fp, "\\%c", c); + else if (c < ' ' || c >= 0177) + fprintf(fp, "\\%03o", c&0377); + else + putc(c, fp); + } + fprintf(fp, "'"); +} + +static object * +stringrepr(op) + register stringobject *op; +{ + /* XXX overflow? */ + int newsize = 2 + 4 * op->ob_size * sizeof(char); + object *v = newsizedstringobject((char *)NULL, newsize); + if (v == NULL) { + return err_nomem(); + } + else { + register int i; + register char c; + register char *p; + NEWREF(v); + v->ob_type = &Stringtype; + ((stringobject *)v)->ob_size = newsize; + p = ((stringobject *)v)->ob_sval; + *p++ = '\''; + for (i = 0; i < op->ob_size; i++) { + c = op->ob_sval[i]; + if (c == '\'' || c == '\\') + *p++ = '\\', *p++ = c; + else if (c < ' ' || c >= 0177) { + sprintf(p, "\\%03o", c&0377); + while (*p != '\0') + p++; + + } + else + *p++ = c; + } + *p++ = '\''; + *p = '\0'; + resizestring(&v, (int) (p - ((stringobject *)v)->ob_sval)); + return v; + } +} + +static int +stringlength(a) + stringobject *a; +{ + return a->ob_size; +} + +static object * +stringconcat(a, bb) + register stringobject *a; + register object *bb; +{ + register unsigned int size; + register stringobject *op; + if (!is_stringobject(bb)) { + err_badarg(); + return NULL; + } +#define b ((stringobject *)bb) + /* Optimize cases with empty left or right operand */ + if (a->ob_size == 0) { + INCREF(bb); + return bb; + } + if (b->ob_size == 0) { + INCREF(a); + return (object *)a; + } + size = a->ob_size + b->ob_size; + op = (stringobject *) + malloc(sizeof(stringobject) + size * sizeof(char)); + if (op == NULL) + return err_nomem(); + NEWREF(op); + op->ob_type = &Stringtype; + op->ob_size = size; + memcpy(op->ob_sval, a->ob_sval, (int) a->ob_size); + memcpy(op->ob_sval + a->ob_size, b->ob_sval, (int) b->ob_size); + op->ob_sval[size] = '\0'; + return (object *) op; +#undef b +} + +static object * +stringrepeat(a, n) + register stringobject *a; + register int n; +{ + register int i; + register unsigned int size; + register stringobject *op; + if (n < 0) + n = 0; + size = a->ob_size * n; + if (size == a->ob_size) { + INCREF(a); + return (object *)a; + } + op = (stringobject *) + malloc(sizeof(stringobject) + size * sizeof(char)); + if (op == NULL) + return err_nomem(); + NEWREF(op); + op->ob_type = &Stringtype; + op->ob_size = size; + for (i = 0; i < size; i += a->ob_size) + memcpy(op->ob_sval+i, a->ob_sval, (int) a->ob_size); + op->ob_sval[size] = '\0'; + return (object *) op; +} + +/* String slice a[i:j] consists of characters a[i] ... a[j-1] */ + +static object * +stringslice(a, i, j) + register stringobject *a; + register int i, j; /* May be negative! */ +{ + if (i < 0) + i = 0; + if (j < 0) + j = 0; /* Avoid signed/unsigned bug in next line */ + if (j > a->ob_size) + j = a->ob_size; + if (i == 0 && j == a->ob_size) { /* It's the same as a */ + INCREF(a); + return (object *)a; + } + if (j < i) + j = i; + return newsizedstringobject(a->ob_sval + i, (int) (j-i)); +} + +static object * +stringitem(a, i) + stringobject *a; + register int i; +{ + if (i < 0 || i >= a->ob_size) { + err_setstr(IndexError, "string index out of range"); + return NULL; + } + return stringslice(a, i, i+1); +} + +static int +stringcompare(a, b) + stringobject *a, *b; +{ + int len_a = a->ob_size, len_b = b->ob_size; + int min_len = (len_a < len_b) ? len_a : len_b; + int cmp = memcmp(a->ob_sval, b->ob_sval, min_len); + if (cmp != 0) + return cmp; + return (len_a < len_b) ? -1 : (len_a > len_b) ? 1 : 0; +} + +static sequence_methods string_as_sequence = { + stringlength, /*tp_length*/ + stringconcat, /*tp_concat*/ + stringrepeat, /*tp_repeat*/ + stringitem, /*tp_item*/ + stringslice, /*tp_slice*/ + 0, /*tp_ass_item*/ + 0, /*tp_ass_slice*/ +}; + +typeobject Stringtype = { + OB_HEAD_INIT(&Typetype) + 0, + "string", + sizeof(stringobject), + sizeof(char), + free, /*tp_dealloc*/ + stringprint, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + stringcompare, /*tp_compare*/ + stringrepr, /*tp_repr*/ + 0, /*tp_as_number*/ + &string_as_sequence, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; + +void +joinstring(pv, w) + register object **pv; + register object *w; +{ + register object *v; + if (*pv == NULL || w == NULL || !is_stringobject(*pv)) + return; + v = stringconcat((stringobject *) *pv, w); + DECREF(*pv); + *pv = v; +} + +/* The following function breaks the notion that strings are immutable: + it changes the size of a string. We get away with this only if there + is only one module referencing the object. You can also think of it + as creating a new string object and destroying the old one, only + more efficiently. In any case, don't use this if the string may + already be known to some other part of the code... */ + +int +resizestring(pv, newsize) + object **pv; + int newsize; +{ + register object *v; + register stringobject *sv; + v = *pv; + if (!is_stringobject(v) || v->ob_refcnt != 1) { + *pv = 0; + DECREF(v); + err_badcall(); + return -1; + } + /* XXX UNREF/NEWREF interface should be more symmetrical */ +#ifdef REF_DEBUG + --ref_total; +#endif + UNREF(v); + *pv = (object *) + realloc((char *)v, + sizeof(stringobject) + newsize * sizeof(char)); + if (*pv == NULL) { + DEL(v); + err_nomem(); + return -1; + } + NEWREF(*pv); + sv = (stringobject *) *pv; + sv->ob_size = newsize; + sv->ob_sval[newsize] = '\0'; + return 0; +} diff --git a/src/stringobject.h b/src/stringobject.h new file mode 100644 index 0000000..17e0367 --- /dev/null +++ b/src/stringobject.h @@ -0,0 +1,63 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* String object interface */ + +/* +123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 + +Type stringobject represents a character string. An extra zero byte is +reserved at the end to ensure it is zero-terminated, but a size is +present so strings with null bytes in them can be represented. This +is an immutable object type. + +There are functions to create new string objects, to test +an object for string-ness, and to get the +string value. The latter function returns a null pointer +if the object is not of the proper type. +There is a variant that takes an explicit size as well as a +variant that assumes a zero-terminated string. Note that none of the +functions should be applied to nil objects. +*/ + +/* NB The type is revealed here only because it is used in dictobject.c */ + +typedef struct { + OB_VARHEAD + char ob_sval[1]; +} stringobject; + +extern typeobject Stringtype; + +#define is_stringobject(op) ((op)->ob_type == &Stringtype) + +extern object *newsizedstringobject PROTO((char *, int)); +extern object *newstringobject PROTO((char *)); +extern unsigned int getstringsize PROTO((object *)); +extern char *getstringvalue PROTO((object *)); +extern void joinstring PROTO((object **, object *)); +extern int resizestring PROTO((object **, int)); + +/* Macro, trading safety for speed */ +#define GETSTRINGVALUE(op) ((op)->ob_sval) diff --git a/src/strtol.c b/src/strtol.c new file mode 100644 index 0000000..cdf9b92 --- /dev/null +++ b/src/strtol.c @@ -0,0 +1,122 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* +** strtol +** This is a general purpose routine for converting +** an ascii string to an integer in an arbitrary base. +** Leading white space is ignored, if 'base' is zero +** it looks for a leading 0, 0x or 0X to tell which +** base. If these are absent it defaults to 10. +** Base must be between 0 and 36. +** If 'ptr' is non-NULL it will contain a pointer to +** the end of the scan. +** Errors due to bad pointers will probably result in +** exceptions - we don't check for them. +*/ + +#include "ctype.h" + +long +strtol(str, ptr, base) +register char * str; +char ** ptr; +int base; +{ + register long result; /* return value of the function */ + register int c; /* current input character */ + int minus; /* true if a leading minus was found */ + + result = 0; + minus = 0; + +/* catch silly bases */ + if (base < 0 || base > 36) + { + if (ptr) + *ptr = str; + return result; + } + +/* skip leading white space */ + while (*str && isspace(*str)) + str++; + +/* check for optional leading minus sign */ + if (*str == '-') + { + minus = 1; + str++; + } + +/* check for leading 0 or 0x for auto-base or base 16 */ + switch (base) + { + case 0: /* look for leading 0, 0x or 0X */ + if (*str == '0') + { + str++; + if (*str == 'x' || *str == 'X') + { + str++; + base = 16; + } + else + base = 8; + } + else + base = 10; + break; + + case 16: /* skip leading 0x or 0X */ + if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')) + str += 2; + break; + } + +/* do the conversion */ + while (c = *str) + { + if (isdigit(c) && c - '0' < base) + c -= '0'; + else + { + if (isupper(c)) + c = tolower(c); + if (c >= 'a' && c <= 'z') + c -= 'a' - 10; + else /* non-"digit" character */ + break; + if (c >= base) /* non-"digit" character */ + break; + } + result = result * base + c; + str++; + } + +/* set pointer to point to the last character scanned */ + if (ptr) + *ptr = str; + return minus ? -result : result; +} diff --git a/src/structmember.c b/src/structmember.c new file mode 100644 index 0000000..c87a3c7 --- /dev/null +++ b/src/structmember.c @@ -0,0 +1,158 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Map C struct members to Python object attributes */ + +#include "allobjects.h" + +#include "structmember.h" + +object * +getmember(addr, mlist, name) + char *addr; + struct memberlist *mlist; + char *name; +{ + struct memberlist *l; + + for (l = mlist; l->name != NULL; l++) { + if (strcmp(l->name, name) == 0) { + object *v; + addr += l->offset; + switch (l->type) { + case T_SHORT: + v = newintobject((long) *(short*)addr); + break; + case T_INT: + v = newintobject((long) *(int*)addr); + break; + case T_LONG: + v = newintobject(*(long*)addr); + break; + case T_FLOAT: + v = newfloatobject((double)*(float*)addr); + break; + case T_DOUBLE: + v = newfloatobject(*(double*)addr); + break; + case T_STRING: + if (*(char**)addr == NULL) { + INCREF(None); + v = None; + } + else + v = newstringobject(*(char**)addr); + break; + case T_OBJECT: + v = *(object **)addr; + if (v == NULL) + v = None; + INCREF(v); + break; + default: + err_setstr(SystemError, "bad memberlist type"); + v = NULL; + } + return v; + } + } + + err_setstr(NameError, name); + return NULL; +} + +int +setmember(addr, mlist, name, v) + char *addr; + struct memberlist *mlist; + char *name; + object *v; +{ + struct memberlist *l; + + for (l = mlist; l->name != NULL; l++) { + if (strcmp(l->name, name) == 0) { + if (l->readonly || l->type == T_STRING) { + err_setstr(RuntimeError, "readonly attribute"); + return -1; + } + addr += l->offset; + switch (l->type) { + case T_SHORT: + if (!is_intobject(v)) { + err_badarg(); + return -1; + } + *(short*)addr = getintvalue(v); + break; + case T_INT: + if (!is_intobject(v)) { + err_badarg(); + return -1; + } + *(int*)addr = getintvalue(v); + break; + case T_LONG: + if (!is_intobject(v)) { + err_badarg(); + return -1; + } + *(long*)addr = getintvalue(v); + break; + case T_FLOAT: + if (is_intobject(v)) + *(float*)addr = getintvalue(v); + else if (is_floatobject(v)) + *(float*)addr = getfloatvalue(v); + else { + err_badarg(); + return -1; + } + break; + case T_DOUBLE: + if (is_intobject(v)) + *(double*)addr = getintvalue(v); + else if (is_floatobject(v)) + *(double*)addr = getfloatvalue(v); + else { + err_badarg(); + return -1; + } + break; + case T_OBJECT: + XDECREF(*(object **)addr); + XINCREF(v); + *(object **)addr = v; + break; + default: + err_setstr(SystemError, "bad memberlist type"); + return -1; + } + return 0; + } + } + + err_setstr(NameError, name); + return -1; +} diff --git a/src/structmember.h b/src/structmember.h new file mode 100644 index 0000000..93d2a2e --- /dev/null +++ b/src/structmember.h @@ -0,0 +1,64 @@ +/*********************************************************** +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 to map C struct members to Python object attributes */ + +/* The offsetof() macro calculates the offset of a structure member + in its structure. Unfortunately this cannot be written down + portably, hence it is provided by a Standard C header file. + For pre-Standard C compilers, here is a version that usually works + (but watch out!): */ + +#ifndef offsetof +#define offsetof(type, member) ( (int) & ((type*)0) -> member ) +#endif + +/* An array of memberlist structures defines the name, type and offset + of selected members of a C structure. These can be read by + getmember() and set by setmember() (except if their READONLY flag + is set). The array must be terminated with an entry whose name + pointer is NULL. */ + +struct memberlist { + char *name; + int type; + int offset; + int readonly; +}; + +/* Types */ +#define T_SHORT 0 +#define T_INT 1 +#define T_LONG 2 +#define T_FLOAT 3 +#define T_DOUBLE 4 +#define T_STRING 5 +#define T_OBJECT 6 + +/* Readonly flag */ +#define READONLY 1 +#define RO READONLY /* Shorthand */ + +object *getmember PROTO((char *, struct memberlist *, char *)); +int setmember PROTO((char *, struct memberlist *, char *, object *)); diff --git a/src/stubcode.h b/src/stubcode.h new file mode 100644 index 0000000..6e76c23 --- /dev/null +++ b/src/stubcode.h @@ -0,0 +1,28 @@ +/*********************************************************** +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 CAP 0 +#define STUBC 1 +#define NAME 2 diff --git a/src/sysmodule.c b/src/sysmodule.c new file mode 100644 index 0000000..6b3b576 --- /dev/null +++ b/src/sysmodule.c @@ -0,0 +1,214 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* System module */ + +/* +Various bits of information used by the interpreter are collected in +module 'sys'. +Function member: +- exit(sts): call (C, POSIX) exit(sts) +Data members: +- stdin, stdout, stderr: standard file objects +- modules: the table of modules (dictionary) +- path: module search path (list of strings) +- argv: script arguments (list of strings) +- ps1, ps2: optional primary and secondary prompts (strings) +*/ + +#include "allobjects.h" + +#include "sysmodule.h" +#include "import.h" +#include "modsupport.h" + +/* Define delimiter used in $PYTHONPATH */ + +#ifdef THINK_C +#define DELIM ' ' +#endif + +#ifndef DELIM +#define DELIM ':' +#endif + +static object *sysdict; + +object * +sysget(name) + char *name; +{ + return dictlookup(sysdict, name); +} + +FILE * +sysgetfile(name, def) + char *name; + FILE *def; +{ + FILE *fp = NULL; + object *v = sysget(name); + if (v != NULL) + fp = getfilefile(v); + if (fp == NULL) + fp = def; + return fp; +} + +int +sysset(name, v) + char *name; + object *v; +{ + if (v == NULL) + return dictremove(sysdict, name); + else + return dictinsert(sysdict, name, v); +} + +static object * +sys_exit(self, args) + object *self; + object *args; +{ + int sts; + if (!getintarg(args, &sts)) + return NULL; + goaway(sts); + exit(sts); /* Just in case */ + /* NOTREACHED */ +} + +static struct methodlist sys_methods[] = { + {"exit", sys_exit}, + {NULL, NULL} /* sentinel */ +}; + +static object *sysin, *sysout, *syserr; + +void +initsys() +{ + object *m = initmodule("sys", sys_methods); + sysdict = getmoduledict(m); + INCREF(sysdict); + /* NB keep an extra ref to the std files to avoid closing them + when the user deletes them */ + /* XXX File objects should have a "don't close" flag instead */ + sysin = newopenfileobject(stdin, "<stdin>", "r"); + sysout = newopenfileobject(stdout, "<stdout>", "w"); + syserr = newopenfileobject(stderr, "<stderr>", "w"); + if (err_occurred()) + fatal("can't create sys.std* file objects"); + dictinsert(sysdict, "stdin", sysin); + dictinsert(sysdict, "stdout", sysout); + dictinsert(sysdict, "stderr", syserr); + dictinsert(sysdict, "modules", get_modules()); + if (err_occurred()) + fatal("can't insert sys.* objects in sys dict"); +} + +static object * +makepathobject(path, delim) + char *path; + int delim; +{ + int i, n; + char *p; + object *v, *w; + + n = 1; + p = path; + while ((p = strchr(p, delim)) != NULL) { + n++; + p++; + } + v = newlistobject(n); + if (v == NULL) + return NULL; + for (i = 0; ; i++) { + p = strchr(path, delim); + if (p == NULL) + p = strchr(path, '\0'); /* End of string */ + w = newsizedstringobject(path, (int) (p - path)); + if (w == NULL) { + DECREF(v); + return NULL; + } + setlistitem(v, i, w); + if (*p == '\0') + break; + path = p+1; + } + return v; +} + +void +setpythonpath(path) + char *path; +{ + object *v; + if ((v = makepathobject(path, DELIM)) == NULL) + fatal("can't create sys.path"); + if (sysset("path", v) != 0) + fatal("can't assign sys.path"); + DECREF(v); +} + +static object * +makeargvobject(argc, argv) + int argc; + char **argv; +{ + object *av; + if (argc < 0 || argv == NULL) + argc = 0; + av = newlistobject(argc); + if (av != NULL) { + int i; + for (i = 0; i < argc; i++) { + object *v = newstringobject(argv[i]); + if (v == NULL) { + DECREF(av); + av = NULL; + break; + } + setlistitem(av, i, v); + } + } + return av; +} + +void +setpythonargv(argc, argv) + int argc; + char **argv; +{ + object *av = makeargvobject(argc, argv); + if (av == NULL) + fatal("no mem for sys.argv"); + if (sysset("argv", av) != 0) + fatal("can't assign sys.argv"); + DECREF(av); +} diff --git a/src/sysmodule.h b/src/sysmodule.h new file mode 100644 index 0000000..eed1944 --- /dev/null +++ b/src/sysmodule.h @@ -0,0 +1,30 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* System module interface */ + +object *sysget PROTO((char *)); +int sysset PROTO((char *, object *)); +FILE *sysgetfile PROTO((char *, FILE *)); +void initsys PROTO((void)); diff --git a/src/timemodule.c b/src/timemodule.c new file mode 100644 index 0000000..dcaedbd --- /dev/null +++ b/src/timemodule.c @@ -0,0 +1,229 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Time module */ + +#include "allobjects.h" + +#include "modsupport.h" + +#include "sigtype.h" + +#include <signal.h> +#include <setjmp.h> + +#ifdef __STDC__ +#include <time.h> +#else /* !__STDC__ */ +typedef unsigned long time_t; +extern time_t time(); +#endif /* !__STDC__ */ + + +/* Time methods */ + +static object * +time_time(self, args) + object *self; + object *args; +{ + long secs; + if (!getnoarg(args)) + return NULL; + secs = time((time_t *)NULL); + return newintobject(secs); +} + +static jmp_buf sleep_intr; + +static void +sleep_catcher(sig) + int sig; +{ + longjmp(sleep_intr, 1); +} + +static object * +time_sleep(self, args) + object *self; + object *args; +{ + int secs; + SIGTYPE (*sigsave)(); + if (!getintarg(args, &secs)) + return NULL; + if (setjmp(sleep_intr)) { + signal(SIGINT, sigsave); + err_set(KeyboardInterrupt); + return NULL; + } + sigsave = signal(SIGINT, SIG_IGN); + if (sigsave != (SIGTYPE (*)()) SIG_IGN) + signal(SIGINT, sleep_catcher); + sleep(secs); + signal(SIGINT, sigsave); + INCREF(None); + return None; +} + +#ifdef THINK_C +#define DO_MILLI +#endif /* THINK_C */ + +#ifdef AMOEBA +#define DO_MILLI +extern long sys_milli(); +#define millitimer sys_milli +#endif /* AMOEBA */ + +#ifdef BSD_TIME +#define DO_MILLI +#endif /* BSD_TIME */ + +#ifdef DO_MILLI + +static object * +time_millisleep(self, args) + object *self; + object *args; +{ + long msecs; + SIGTYPE (*sigsave)(); + if (!getlongarg(args, &msecs)) + return NULL; + if (setjmp(sleep_intr)) { + signal(SIGINT, sigsave); + err_set(KeyboardInterrupt); + return NULL; + } + sigsave = signal(SIGINT, SIG_IGN); + if (sigsave != (SIGTYPE (*)()) SIG_IGN) + signal(SIGINT, sleep_catcher); + millisleep(msecs); + signal(SIGINT, sigsave); + INCREF(None); + return None; +} + +static object * +time_millitimer(self, args) + object *self; + object *args; +{ + long msecs; + extern long millitimer(); + if (!getnoarg(args)) + return NULL; + msecs = millitimer(); + return newintobject(msecs); +} + +#endif /* DO_MILLI */ + + +static struct methodlist time_methods[] = { +#ifdef DO_MILLI + {"millisleep", time_millisleep}, + {"millitimer", time_millitimer}, +#endif /* DO_MILLI */ + {"sleep", time_sleep}, + {"time", time_time}, + {NULL, NULL} /* sentinel */ +}; + + +void +inittime() +{ + initmodule("time", time_methods); +} + + +#ifdef THINK_C + +#define MacTicks (* (long *)0x16A) + +static +sleep(msecs) + int msecs; +{ + register long deadline; + + deadline = MacTicks + msecs * 60; + while (MacTicks < deadline) { + if (intrcheck()) + sleep_catcher(SIGINT); + } +} + +static +millisleep(msecs) + long msecs; +{ + register long deadline; + + deadline = MacTicks + msecs * 3 / 50; /* msecs * 60 / 1000 */ + while (MacTicks < deadline) { + if (intrcheck()) + sleep_catcher(SIGINT); + } +} + +static long +millitimer() +{ + return MacTicks * 50 / 3; /* MacTicks * 1000 / 60 */ +} + +#endif /* THINK_C */ + + +#ifdef BSD_TIME + +#include <sys/types.h> +#include <sys/time.h> + +static long +millitimer() +{ + struct timeval t; + struct timezone tz; + if (gettimeofday(&t, &tz) != 0) + return -1; + return t.tv_sec*1000 + t.tv_usec/1000; + +} + +static +millisleep(msecs) + long msecs; +{ + struct timeval t; + t.tv_sec = msecs/1000; + t.tv_usec = (msecs%1000)*1000; + (void) select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t); +} + +#endif /* BSD_TIME */ + diff --git a/src/token.h b/src/token.h new file mode 100644 index 0000000..79f0ed0 --- /dev/null +++ b/src/token.h @@ -0,0 +1,69 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Token types */ + +#define ENDMARKER 0 +#define NAME 1 +#define NUMBER 2 +#define STRING 3 +#define NEWLINE 4 +#define INDENT 5 +#define DEDENT 6 +#define LPAR 7 +#define RPAR 8 +#define LSQB 9 +#define RSQB 10 +#define COLON 11 +#define COMMA 12 +#define SEMI 13 +#define PLUS 14 +#define MINUS 15 +#define STAR 16 +#define SLASH 17 +#define VBAR 18 +#define AMPER 19 +#define LESS 20 +#define GREATER 21 +#define EQUAL 22 +#define DOT 23 +#define PERCENT 24 +#define BACKQUOTE 25 +#define LBRACE 26 +#define RBRACE 27 +#define OP 28 +#define ERRORTOKEN 29 +#define N_TOKENS 30 + +/* Special definitions for cooperation with parser */ + +#define NT_OFFSET 256 + +#define ISTERMINAL(x) ((x) < NT_OFFSET) +#define ISNONTERMINAL(x) ((x) >= NT_OFFSET) +#define ISEOF(x) ((x) == ENDMARKER) + + +extern char *tok_name[]; /* Token names */ +extern int tok_1char PROTO((int)); diff --git a/src/tokenizer.c b/src/tokenizer.c new file mode 100644 index 0000000..231123f --- /dev/null +++ b/src/tokenizer.c @@ -0,0 +1,523 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Tokenizer implementation */ + +/* XXX This is rather old, should be restructured perhaps */ +/* XXX Need a better interface to report errors than writing to stderr */ +/* XXX Should use editor resource to fetch true tab size on Macintosh */ + +#include "pgenheaders.h" + +#include <ctype.h> +#include "string.h" + +#include "fgetsintr.h" +#include "tokenizer.h" +#include "errcode.h" + +#ifdef THINK_C +#define TABSIZE 4 +#endif + +#ifndef TABSIZE +#define TABSIZE 8 +#endif + +/* Forward */ +static struct tok_state *tok_new PROTO((void)); +static int tok_nextc PROTO((struct tok_state *tok)); +static void tok_backup PROTO((struct tok_state *tok, int c)); + +/* Token names */ + +char *tok_name[] = { + "ENDMARKER", + "NAME", + "NUMBER", + "STRING", + "NEWLINE", + "INDENT", + "DEDENT", + "LPAR", + "RPAR", + "LSQB", + "RSQB", + "COLON", + "COMMA", + "SEMI", + "PLUS", + "MINUS", + "STAR", + "SLASH", + "VBAR", + "AMPER", + "LESS", + "GREATER", + "EQUAL", + "DOT", + "PERCENT", + "BACKQUOTE", + "LBRACE", + "RBRACE", + "OP", + "<ERRORTOKEN>", + "<N_TOKENS>" +}; + + +/* Create and initialize a new tok_state structure */ + +static struct tok_state * +tok_new() +{ + struct tok_state *tok = NEW(struct tok_state, 1); + if (tok == NULL) + return NULL; + tok->buf = tok->cur = tok->end = tok->inp = NULL; + tok->done = E_OK; + tok->fp = NULL; + tok->tabsize = TABSIZE; + tok->indent = 0; + tok->indstack[0] = 0; + tok->atbol = 1; + tok->pendin = 0; + tok->prompt = tok->nextprompt = NULL; + tok->lineno = 0; + return tok; +} + + +/* Set up tokenizer for string */ + +struct tok_state * +tok_setups(str) + char *str; +{ + struct tok_state *tok = tok_new(); + if (tok == NULL) + return NULL; + tok->buf = tok->cur = str; + tok->end = tok->inp = strchr(str, '\0'); + return tok; +} + + +/* Set up tokenizer for string */ + +struct tok_state * +tok_setupf(fp, ps1, ps2) + FILE *fp; + char *ps1, *ps2; +{ + struct tok_state *tok = tok_new(); + if (tok == NULL) + return NULL; + if ((tok->buf = NEW(char, BUFSIZ)) == NULL) { + DEL(tok); + return NULL; + } + tok->cur = tok->inp = tok->buf; + tok->end = tok->buf + BUFSIZ; + tok->fp = fp; + tok->prompt = ps1; + tok->nextprompt = ps2; + return tok; +} + + +/* Free a tok_state structure */ + +void +tok_free(tok) + struct tok_state *tok; +{ + /* XXX really need a separate flag to say 'my buffer' */ + if (tok->fp != NULL && tok->buf != NULL) + DEL(tok->buf); + DEL(tok); +} + + +/* Get next char, updating state; error code goes into tok->done */ + +static int +tok_nextc(tok) + register struct tok_state *tok; +{ + if (tok->done != E_OK) + return EOF; + + for (;;) { + if (tok->cur < tok->inp) + return *tok->cur++; + if (tok->fp == NULL) { + tok->done = E_EOF; + return EOF; + } + if (tok->inp > tok->buf && tok->inp[-1] == '\n') + tok->inp = tok->buf; + if (tok->inp == tok->end) { + int n = tok->end - tok->buf; + char *new = tok->buf; + RESIZE(new, char, n+n); + if (new == NULL) { + fprintf(stderr, "tokenizer out of mem\n"); + tok->done = E_NOMEM; + return EOF; + } + tok->buf = new; + tok->inp = tok->buf + n; + tok->end = tok->inp + n; + } +#ifdef USE_READLINE + if (tok->prompt != NULL) { + extern char *readline PROTO((char *prompt)); + static int been_here; + if (!been_here) { + /* Force rebind of TAB to insert-tab */ + extern int rl_insert(); + rl_bind_key('\t', rl_insert); + been_here++; + } + if (tok->buf != NULL) + free(tok->buf); + tok->buf = readline(tok->prompt); + (void) intrcheck(); /* Clear pending interrupt */ + if (tok->nextprompt != NULL) + tok->prompt = tok->nextprompt; + /* XXX different semantics w/o readline()! */ + if (tok->buf == NULL) { + tok->done = E_EOF; + } + else { + unsigned int n = strlen(tok->buf); + if (n > 0) + add_history(tok->buf); + /* Append the '\n' that readline() + doesn't give us, for the tokenizer... */ + tok->buf = realloc(tok->buf, n+2); + if (tok->buf == NULL) + tok->done = E_NOMEM; + else { + tok->end = tok->buf + n; + *tok->end++ = '\n'; + *tok->end = '\0'; + tok->inp = tok->end; + tok->cur = tok->buf; + } + } + } + else +#endif + { + tok->cur = tok->inp; + if (tok->prompt != NULL && tok->inp == tok->buf) { + fprintf(stderr, "%s", tok->prompt); + tok->prompt = tok->nextprompt; + } + tok->done = fgets_intr(tok->inp, + (int)(tok->end - tok->inp), tok->fp); + } + if (tok->done != E_OK) { + if (tok->prompt != NULL) + fprintf(stderr, "\n"); + return EOF; + } + tok->inp = strchr(tok->inp, '\0'); + } +} + + +/* Back-up one character */ + +static void +tok_backup(tok, c) + register struct tok_state *tok; + register int c; +{ + if (c != EOF) { + if (--tok->cur < tok->buf) { + fprintf(stderr, "tok_backup: begin of buffer\n"); + abort(); + } + if (*tok->cur != c) + *tok->cur = c; + } +} + + +/* Return the token corresponding to a single character */ + +int +tok_1char(c) + int c; +{ + switch (c) { + case '(': return LPAR; + case ')': return RPAR; + case '[': return LSQB; + case ']': return RSQB; + case ':': return COLON; + case ',': return COMMA; + case ';': return SEMI; + case '+': return PLUS; + case '-': return MINUS; + case '*': return STAR; + case '/': return SLASH; + case '|': return VBAR; + case '&': return AMPER; + case '<': return LESS; + case '>': return GREATER; + case '=': return EQUAL; + case '.': return DOT; + case '%': return PERCENT; + case '`': return BACKQUOTE; + case '{': return LBRACE; + case '}': return RBRACE; + default: return OP; + } +} + + +/* Get next token, after space stripping etc. */ + +int +tok_get(tok, p_start, p_end) + register struct tok_state *tok; /* In/out: tokenizer state */ + char **p_start, **p_end; /* Out: point to start/end of token */ +{ + register int c; + + /* Get indentation level */ + if (tok->atbol) { + register int col = 0; + tok->atbol = 0; + tok->lineno++; + for (;;) { + c = tok_nextc(tok); + if (c == ' ') + col++; + else if (c == '\t') + col = (col/tok->tabsize + 1) * tok->tabsize; + else + break; + } + tok_backup(tok, c); + if (col == tok->indstack[tok->indent]) { + /* No change */ + } + else if (col > tok->indstack[tok->indent]) { + /* Indent -- always one */ + if (tok->indent+1 >= MAXINDENT) { + fprintf(stderr, "excessive indent\n"); + tok->done = E_TOKEN; + return ERRORTOKEN; + } + tok->pendin++; + tok->indstack[++tok->indent] = col; + } + else /* col < tok->indstack[tok->indent] */ { + /* Dedent -- any number, must be consistent */ + while (tok->indent > 0 && + col < tok->indstack[tok->indent]) { + tok->indent--; + tok->pendin--; + } + if (col != tok->indstack[tok->indent]) { + fprintf(stderr, "inconsistent dedent\n"); + tok->done = E_TOKEN; + return ERRORTOKEN; + } + } + } + + *p_start = *p_end = tok->cur; + + /* Return pending indents/dedents */ + if (tok->pendin != 0) { + if (tok->pendin < 0) { + tok->pendin++; + return DEDENT; + } + else { + tok->pendin--; + return INDENT; + } + } + + again: + /* Skip spaces */ + do { + c = tok_nextc(tok); + } while (c == ' ' || c == '\t'); + + /* Set start of current token */ + *p_start = tok->cur - 1; + + /* Skip comment */ + if (c == '#') { + /* Hack to allow overriding the tabsize in the file. + This is also recognized by vi, when it occurs near the + beginning or end of the file. (Will vi never die...?) */ + int x; + /* XXX The case to (unsigned char *) is needed by THINK C 3.0 */ + if (sscanf(/*(unsigned char *)*/tok->cur, + " vi:set tabsize=%d:", &x) == 1 && + x >= 1 && x <= 40) { + fprintf(stderr, "# vi:set tabsize=%d:\n", x); + tok->tabsize = x; + } + do { + c = tok_nextc(tok); + } while (c != EOF && c != '\n'); + } + + /* Check for EOF and errors now */ + if (c == EOF) + return tok->done == E_EOF ? ENDMARKER : ERRORTOKEN; + + /* Identifier (most frequent token!) */ + if (isalpha(c) || c == '_') { + do { + c = tok_nextc(tok); + } while (isalnum(c) || c == '_'); + tok_backup(tok, c); + *p_end = tok->cur; + return NAME; + } + + /* Newline */ + if (c == '\n') { + tok->atbol = 1; + *p_end = tok->cur - 1; /* Leave '\n' out of the string */ + return NEWLINE; + } + + /* Number */ + if (isdigit(c)) { + if (c == '0') { + /* Hex or octal */ + c = tok_nextc(tok); + if (c == '.') + goto fraction; + if (c == 'x' || c == 'X') { + /* Hex */ + do { + c = tok_nextc(tok); + } while (isxdigit(c)); + } + else { + /* Octal; c is first char of it */ + /* There's no 'isoctdigit' macro, sigh */ + while ('0' <= c && c < '8') { + c = tok_nextc(tok); + } + } + } + else { + /* Decimal */ + do { + c = tok_nextc(tok); + } while (isdigit(c)); + /* Accept floating point numbers. + XXX This accepts incomplete things like 12e or 1e+; + worry about that at run-time. + XXX Doesn't accept numbers starting with a dot */ + if (c == '.') { + fraction: + /* Fraction */ + do { + c = tok_nextc(tok); + } while (isdigit(c)); + } + if (c == 'e' || c == 'E') { + /* Exponent part */ + c = tok_nextc(tok); + if (c == '+' || c == '-') + c = tok_nextc(tok); + while (isdigit(c)) { + c = tok_nextc(tok); + } + } + } + tok_backup(tok, c); + *p_end = tok->cur; + return NUMBER; + } + + /* String */ + if (c == '\'') { + for (;;) { + c = tok_nextc(tok); + if (c == '\n' || c == EOF) { + tok->done = E_TOKEN; + return ERRORTOKEN; + } + if (c == '\\') { + c = tok_nextc(tok); + *p_end = tok->cur; + if (c == '\n' || c == EOF) { + tok->done = E_TOKEN; + return ERRORTOKEN; + } + continue; + } + if (c == '\'') + break; + } + *p_end = tok->cur; + return STRING; + } + + /* Line continuation */ + if (c == '\\') { + c = tok_nextc(tok); + if (c != '\n') { + tok->done = E_TOKEN; + return ERRORTOKEN; + } + tok->lineno++; + goto again; /* Read next line */ + } + + /* Punctuation character */ + *p_end = tok->cur; + return tok_1char(c); +} + + +#ifdef DEBUG + +void +tok_dump(type, start, end) + int type; + char *start, *end; +{ + printf("%s", tok_name[type]); + if (type == NAME || type == NUMBER || type == STRING || type == OP) + printf("(%.*s)", (int)(end - start), start); +} + +#endif diff --git a/src/tokenizer.h b/src/tokenizer.h new file mode 100644 index 0000000..aec5ef3 --- /dev/null +++ b/src/tokenizer.h @@ -0,0 +1,53 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Tokenizer interface */ + +#include "token.h" /* For token types */ + +#define MAXINDENT 100 /* Max indentation level */ + +/* Tokenizer state */ +struct tok_state { + /* Input state; buf <= cur <= inp <= end */ + /* NB an entire token must fit in the buffer */ + char *buf; /* Input buffer */ + char *cur; /* Next character in buffer */ + char *inp; /* End of data in buffer */ + char *end; /* End of input buffer */ + int done; /* 0 normally, 1 at EOF, -1 after error */ + FILE *fp; /* Rest of input; NULL if tokenizing a string */ + int tabsize; /* Tab spacing */ + int indent; /* Current indentation index */ + int indstack[MAXINDENT]; /* Stack of indents */ + int atbol; /* Nonzero if at begin of new line */ + int pendin; /* Pending indents (if > 0) or dedents (if < 0) */ + char *prompt, *nextprompt; /* For interactive prompting */ + int lineno; /* Current line number */ +}; + +extern struct tok_state *tok_setups PROTO((char *)); +extern struct tok_state *tok_setupf PROTO((FILE *, char *ps1, char *ps2)); +extern void tok_free PROTO((struct tok_state *)); +extern int tok_get PROTO((struct tok_state *, char **, char **)); diff --git a/src/traceback.c b/src/traceback.c new file mode 100644 index 0000000..7d40ca5 --- /dev/null +++ b/src/traceback.c @@ -0,0 +1,217 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Traceback implementation */ + +#include "allobjects.h" + +#include "compile.h" +#include "frameobject.h" +#include "traceback.h" +#include "structmember.h" + +typedef struct _tracebackobject { + OB_HEAD + struct _tracebackobject *tb_next; + frameobject *tb_frame; + int tb_lasti; + int tb_lineno; +} tracebackobject; + +#define OFF(x) offsetof(tracebackobject, x) + +static struct memberlist tb_memberlist[] = { + {"tb_next", T_OBJECT, OFF(tb_next)}, + {"tb_frame", T_OBJECT, OFF(tb_frame)}, + {"tb_lasti", T_INT, OFF(tb_lasti)}, + {"tb_lineno", T_INT, OFF(tb_lineno)}, + {NULL} /* Sentinel */ +}; + +static object * +tb_getattr(tb, name) + tracebackobject *tb; + char *name; +{ + return getmember((char *)tb, tb_memberlist, name); +} + +static void +tb_dealloc(tb) + tracebackobject *tb; +{ + XDECREF(tb->tb_next); + XDECREF(tb->tb_frame); + DEL(tb); +} + +static typeobject Tracebacktype = { + OB_HEAD_INIT(&Typetype) + 0, + "traceback", + sizeof(tracebackobject), + 0, + tb_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + tb_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; + +#define is_tracebackobject(v) ((v)->ob_type == &Tracebacktype) + +static tracebackobject * +newtracebackobject(next, frame, lasti, lineno) + tracebackobject *next; + frameobject *frame; + int lasti, lineno; +{ + tracebackobject *tb; + if ((next != NULL && !is_tracebackobject(next)) || + frame == NULL || !is_frameobject(frame)) { + err_badcall(); + return NULL; + } + tb = NEWOBJ(tracebackobject, &Tracebacktype); + if (tb != NULL) { + XINCREF(next); + tb->tb_next = next; + XINCREF(frame); + tb->tb_frame = frame; + tb->tb_lasti = lasti; + tb->tb_lineno = lineno; + } + return tb; +} + +static tracebackobject *tb_current = NULL; + +int +tb_here(frame, lasti, lineno) + frameobject *frame; + int lasti; + int lineno; +{ + tracebackobject *tb; + tb = newtracebackobject(tb_current, frame, lasti, lineno); + if (tb == NULL) + return -1; + XDECREF(tb_current); + tb_current = tb; + return 0; +} + +object * +tb_fetch() +{ + object *v; + v = (object *)tb_current; + tb_current = NULL; + return v; +} + +int +tb_store(v) + object *v; +{ + if (v != NULL && !is_tracebackobject(v)) { + err_badcall(); + return -1; + } + XDECREF(tb_current); + XINCREF(v); + tb_current = (tracebackobject *)v; + return 0; +} + +static void +tb_displayline(fp, filename, lineno) + FILE *fp; + char *filename; + int lineno; +{ + FILE *xfp; + char buf[1000]; + int i; + if (filename[0] == '<' && filename[strlen(filename)-1] == '>') + return; + xfp = fopen(filename, "r"); + if (xfp == NULL) { + fprintf(fp, " (cannot open \"%s\")\n", filename); + return; + } + for (i = 0; i < lineno; i++) { + if (fgets(buf, sizeof buf, xfp) == NULL) + break; + } + if (i == lineno) { + char *p = buf; + while (*p == ' ' || *p == '\t') + p++; + fprintf(fp, " %s", p); + if (strchr(p, '\n') == NULL) + fprintf(fp, "\n"); + } + fclose(xfp); +} + +static void +tb_printinternal(tb, fp) + tracebackobject *tb; + FILE *fp; +{ + while (tb != NULL) { + if (intrcheck()) { + fprintf(fp, "[interrupted]\n"); + break; + } + fprintf(fp, " File \""); + printobject(tb->tb_frame->f_code->co_filename, fp, PRINT_RAW); + fprintf(fp, "\", line %d\n", tb->tb_lineno); + tb_displayline(fp, + getstringvalue(tb->tb_frame->f_code->co_filename), + tb->tb_lineno); + tb = tb->tb_next; + } +} + +int +tb_print(v, fp) + object *v; + FILE *fp; +{ + if (v == NULL) + return 0; + if (!is_tracebackobject(v)) { + err_badcall(); + return -1; + } + sysset("last_traceback", v); + tb_printinternal((tracebackobject *)v, fp); + return 0; +} diff --git a/src/traceback.h b/src/traceback.h new file mode 100644 index 0000000..2127a33 --- /dev/null +++ b/src/traceback.h @@ -0,0 +1,30 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Traceback interface */ + +int tb_here PROTO((struct _frame *, int, int)); +object *tb_fetch PROTO((void)); +int tb_store PROTO((object *)); +int tb_print PROTO((object *, FILE *)); diff --git a/src/tupleobject.c b/src/tupleobject.c new file mode 100644 index 0000000..5ea1e11 --- /dev/null +++ b/src/tupleobject.c @@ -0,0 +1,287 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Tuple object implementation */ + +#include "allobjects.h" + +object * +newtupleobject(size) + register int size; +{ + register int i; + register tupleobject *op; + if (size < 0) { + err_badcall(); + return NULL; + } + op = (tupleobject *) + malloc(sizeof(tupleobject) + size * sizeof(object *)); + if (op == NULL) + return err_nomem(); + NEWREF(op); + op->ob_type = &Tupletype; + op->ob_size = size; + for (i = 0; i < size; i++) + op->ob_item[i] = NULL; + return (object *) op; +} + +int +gettuplesize(op) + register object *op; +{ + if (!is_tupleobject(op)) { + err_badcall(); + return -1; + } + else + return ((tupleobject *)op)->ob_size; +} + +object * +gettupleitem(op, i) + register object *op; + register int i; +{ + if (!is_tupleobject(op)) { + err_badcall(); + return NULL; + } + if (i < 0 || i >= ((tupleobject *)op) -> ob_size) { + err_setstr(IndexError, "tuple index out of range"); + return NULL; + } + return ((tupleobject *)op) -> ob_item[i]; +} + +int +settupleitem(op, i, newitem) + register object *op; + register int i; + register object *newitem; +{ + register object *olditem; + if (!is_tupleobject(op)) { + if (newitem != NULL) + DECREF(newitem); + err_badcall(); + return -1; + } + if (i < 0 || i >= ((tupleobject *)op) -> ob_size) { + if (newitem != NULL) + DECREF(newitem); + err_setstr(IndexError, "tuple assignment index out of range"); + return -1; + } + olditem = ((tupleobject *)op) -> ob_item[i]; + ((tupleobject *)op) -> ob_item[i] = newitem; + if (olditem != NULL) + DECREF(olditem); + return 0; +} + +/* Methods */ + +static void +tupledealloc(op) + register tupleobject *op; +{ + register int i; + for (i = 0; i < op->ob_size; i++) { + if (op->ob_item[i] != NULL) + DECREF(op->ob_item[i]); + } + free((ANY *)op); +} + +static void +tupleprint(op, fp, flags) + tupleobject *op; + FILE *fp; + int flags; +{ + int i; + fprintf(fp, "("); + for (i = 0; i < op->ob_size && !StopPrint; i++) { + if (i > 0) { + fprintf(fp, ", "); + } + printobject(op->ob_item[i], fp, flags); + } + if (op->ob_size == 1) + fprintf(fp, ","); + fprintf(fp, ")"); +} + +object * +tuplerepr(v) + tupleobject *v; +{ + object *s, *t, *comma; + int i; + s = newstringobject("("); + comma = newstringobject(", "); + for (i = 0; i < v->ob_size && s != NULL; i++) { + if (i > 0) + joinstring(&s, comma); + t = reprobject(v->ob_item[i]); + joinstring(&s, t); + if (t != NULL) + DECREF(t); + } + DECREF(comma); + if (v->ob_size == 1) { + t = newstringobject(","); + joinstring(&s, t); + DECREF(t); + } + t = newstringobject(")"); + joinstring(&s, t); + DECREF(t); + return s; +} + +static int +tuplecompare(v, w) + register tupleobject *v, *w; +{ + register int len = + (v->ob_size < w->ob_size) ? v->ob_size : w->ob_size; + register int i; + for (i = 0; i < len; i++) { + int cmp = cmpobject(v->ob_item[i], w->ob_item[i]); + if (cmp != 0) + return cmp; + } + return v->ob_size - w->ob_size; +} + +static int +tuplelength(a) + tupleobject *a; +{ + return a->ob_size; +} + +static object * +tupleitem(a, i) + register tupleobject *a; + register int i; +{ + if (i < 0 || i >= a->ob_size) { + err_setstr(IndexError, "tuple index out of range"); + return NULL; + } + INCREF(a->ob_item[i]); + return a->ob_item[i]; +} + +static object * +tupleslice(a, ilow, ihigh) + register tupleobject *a; + register int ilow, ihigh; +{ + register tupleobject *np; + register int i; + if (ilow < 0) + ilow = 0; + if (ihigh > a->ob_size) + ihigh = a->ob_size; + if (ihigh < ilow) + ihigh = ilow; + if (ilow == 0 && ihigh == a->ob_size) { + /* XXX can only do this if tuples are immutable! */ + INCREF(a); + return (object *)a; + } + np = (tupleobject *)newtupleobject(ihigh - ilow); + if (np == NULL) + return NULL; + for (i = ilow; i < ihigh; i++) { + object *v = a->ob_item[i]; + INCREF(v); + np->ob_item[i - ilow] = v; + } + return (object *)np; +} + +static object * +tupleconcat(a, bb) + register tupleobject *a; + register object *bb; +{ + register int size; + register int i; + tupleobject *np; + if (!is_tupleobject(bb)) { + err_badarg(); + return NULL; + } +#define b ((tupleobject *)bb) + size = a->ob_size + b->ob_size; + np = (tupleobject *) newtupleobject(size); + if (np == NULL) { + return err_nomem(); + } + for (i = 0; i < a->ob_size; i++) { + object *v = a->ob_item[i]; + INCREF(v); + np->ob_item[i] = v; + } + for (i = 0; i < b->ob_size; i++) { + object *v = b->ob_item[i]; + INCREF(v); + np->ob_item[i + a->ob_size] = v; + } + return (object *)np; +#undef b +} + +static sequence_methods tuple_as_sequence = { + tuplelength, /*sq_length*/ + tupleconcat, /*sq_concat*/ + 0, /*sq_repeat*/ + tupleitem, /*sq_item*/ + tupleslice, /*sq_slice*/ + 0, /*sq_ass_item*/ + 0, /*sq_ass_slice*/ +}; + +typeobject Tupletype = { + OB_HEAD_INIT(&Typetype) + 0, + "tuple", + sizeof(tupleobject) - sizeof(object *), + sizeof(object *), + tupledealloc, /*tp_dealloc*/ + tupleprint, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + tuplecompare, /*tp_compare*/ + tuplerepr, /*tp_repr*/ + 0, /*tp_as_number*/ + &tuple_as_sequence, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; diff --git a/src/tupleobject.h b/src/tupleobject.h new file mode 100644 index 0000000..293da22 --- /dev/null +++ b/src/tupleobject.h @@ -0,0 +1,56 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Tuple object interface */ + +/* +123456789-123456789-123456789-123456789-123456789-123456789-123456789-12 + +Another generally useful object type is an tuple of object pointers. +This is a mutable type: the tuple items can be changed (but not their +number). Out-of-range indices or non-tuple objects are ignored. + +*** WARNING *** settupleitem does not increment the new item's reference +count, but does decrement the reference count of the item it replaces, +if not nil. It does *decrement* the reference count if it is *not* +inserted in the tuple. Similarly, gettupleitem does not increment the +returned item's reference count. +*/ + +typedef struct { + OB_VARHEAD + object *ob_item[1]; +} tupleobject; + +extern typeobject Tupletype; + +#define is_tupleobject(op) ((op)->ob_type == &Tupletype) + +extern object *newtupleobject PROTO((int size)); +extern int gettuplesize PROTO((object *)); +extern object *gettupleitem PROTO((object *, int)); +extern int settupleitem PROTO((object *, int, object *)); + +/* Macro, trading safety for speed */ +#define GETTUPLEITEM(op, i) ((op)->ob_item[i]) diff --git a/src/typeobject.c b/src/typeobject.c new file mode 100644 index 0000000..39ed7c7 --- /dev/null +++ b/src/typeobject.c @@ -0,0 +1,61 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Type object implementation */ + +#include "allobjects.h" + +/* Type object implementation */ + +static void +type_print(v, fp, flags) + typeobject *v; + FILE *fp; + int flags; +{ + fprintf(fp, "<type '%s'>", v->tp_name); +} + +static object * +type_repr(v) + typeobject *v; +{ + char buf[100]; + sprintf(buf, "<type '%.80s'>", v->tp_name); + return newstringobject(buf); +} + +typeobject Typetype = { + OB_HEAD_INIT(&Typetype) + 0, /* Number of items for varobject */ + "type", /* Name of this type */ + sizeof(typeobject), /* Basic object size */ + 0, /* Item size for varobject */ + 0, /*tp_dealloc*/ + type_print, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + type_repr, /*tp_repr*/ +}; diff --git a/src/xxobject.c b/src/xxobject.c new file mode 100644 index 0000000..52be44b --- /dev/null +++ b/src/xxobject.c @@ -0,0 +1,131 @@ +/*********************************************************** +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. + +******************************************************************/ + +/* Use this file as a template to start implementing a new object type. + If your objects will be called foobar, start by copying this file to + foobarobject.c, changing all occurrences of xx to foobar and all + occurrences of Xx by Foobar. You will probably want to delete all + references to 'x_attr' and add your own types of attributes + instead. Maybe you want to name your local variables other than + 'xp'. If your object type is needed in other files, you'll have to + create a file "foobarobject.h"; see intobject.h for an example. */ + + +/* Xx objects */ + +#include "allobjects.h" + +typedef struct { + OB_HEAD + object *x_attr; /* Attributes dictionary */ +} xxobject; + +extern typeobject Xxtype; /* Really static, forward */ + +#define is_xxobject(v) ((v)->ob_type == &Xxtype) + +static xxobject * +newxxobject(arg) + object *arg; +{ + xxobject *xp; + xp = NEWOBJ(xxobject, &Xxtype); + if (xp == NULL) + return NULL; + xp->x_attr = NULL; + return xp; +} + +/* Xx methods */ + +static void +xx_dealloc(xp) + xxobject *xp; +{ + XDECREF(xp->x_attr); + DEL(xp); +} + +static object * +xx_demo(self, args) + xxobject *self; + object *args; +{ + if (!getnoarg(args)) + return NULL; + INCREF(None); + return None; +} + +static struct methodlist xx_methods[] = { + "demo", xx_demo, + {NULL, NULL} /* sentinel */ +}; + +static object * +xx_getattr(xp, name) + xxobject *xp; + char *name; +{ + if (xp->x_attr != NULL) { + object *v = dictlookup(xp->x_attr, name); + if (v != NULL) { + INCREF(v); + return v; + } + } + return findmethod(xx_methods, (object *)xp, name); +} + +static int +xx_setattr(xp, name, v) + xxobject *xp; + char *name; + object *v; +{ + if (xp->x_attr == NULL) { + xp->x_attr = newdictobject(); + if (xp->x_attr == NULL) + return -1; + } + if (v == NULL) + return dictremove(xp->x_attr, name); + else + return dictinsert(xp->x_attr, name, v); +} + +static typeobject Xxtype = { + OB_HEAD_INIT(&Typetype) + 0, /*ob_size*/ + "xx", /*tp_name*/ + sizeof(xxobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + xx_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + xx_getattr, /*tp_getattr*/ + xx_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; |
