Remove some of the old demos. (Put a few somewhere else.)

This commit is contained in:
Georg Brandl 2010-12-30 17:22:33 +00:00
parent d1fc34d563
commit 4cf83f4d12
69 changed files with 47 additions and 7628 deletions

View File

@ -1,10 +0,0 @@
CGI Examples
------------
Here are some example CGI programs.
cgi0.sh -- A shell script to test your server is configured for CGI
cgi1.py -- A Python script to test your server is configured for CGI
cgi2.py -- A Python script showing how to parse a form
cgi3.py -- A Python script for driving an arbitrary CGI application
wiki.py -- Sample CGI application: a minimal Wiki implementation

View File

@ -1,8 +0,0 @@
#! /bin/sh
# If you can't get this to work, your web server isn't set up right
echo Content-type: text/plain
echo
echo Hello world
echo This is cgi0.sh

View File

@ -1,14 +0,0 @@
#!/usr/bin/env python3
"""CGI test 1 - check server setup."""
# Until you get this to work, your web server isn't set up right or
# your Python isn't set up right.
# If cgi0.sh works but cgi1.py doesn't, check the #! line and the file
# permissions. The docs for the cgi.py module have debugging tips.
print("Content-type: text/html")
print()
print("<h1>Hello world</h1>")
print("<p>This is cgi1.py")

View File

@ -1,22 +0,0 @@
#!/usr/bin/env python3
"""CGI test 2 - basic use of cgi module."""
import cgitb; cgitb.enable()
import cgi
def main():
form = cgi.FieldStorage()
print("Content-type: text/html")
print()
if not form:
print("<h1>No Form Keys</h1>")
else:
print("<h1>Form Keys</h1>")
for key in form.keys():
value = form[key].value
print("<p>", cgi.escape(key), ":", cgi.escape(value))
if __name__ == "__main__":
main()

View File

@ -1,10 +0,0 @@
#!/usr/bin/env python3
"""CGI test 3 (persistent data)."""
import cgitb; cgitb.enable()
from wiki import main
if __name__ == "__main__":
main()

View File

@ -1,123 +0,0 @@
"""Wiki main program. Imported and run by cgi3.py."""
import os, re, cgi, sys, tempfile
escape = cgi.escape
def main():
form = cgi.FieldStorage()
print("Content-type: text/html")
print()
cmd = form.getvalue("cmd", "view")
page = form.getvalue("page", "FrontPage")
wiki = WikiPage(page)
method = getattr(wiki, 'cmd_' + cmd, None) or wiki.cmd_view
method(form)
class WikiPage:
homedir = tempfile.gettempdir()
scripturl = os.path.basename(sys.argv[0])
def __init__(self, name):
if not self.iswikiword(name):
raise ValueError("page name is not a wiki word")
self.name = name
self.load()
def cmd_view(self, form):
print("<h1>", escape(self.splitwikiword(self.name)), "</h1>")
print("<p>")
for line in self.data.splitlines():
line = line.rstrip()
if not line:
print("<p>")
else:
print(self.formatline(line))
print("<hr>")
print("<p>", self.mklink("edit", self.name, "Edit this page") + ";")
print(self.mklink("view", "FrontPage", "go to front page") + ".")
def formatline(self, line):
words = []
for word in re.split('(\W+)', line):
if self.iswikiword(word):
if os.path.isfile(self.mkfile(word)):
word = self.mklink("view", word, word)
else:
word = self.mklink("new", word, word + "*")
else:
word = escape(word)
words.append(word)
return "".join(words)
def cmd_edit(self, form, label="Change"):
print("<h1>", label, self.name, "</h1>")
print('<form method="POST" action="%s">' % self.scripturl)
s = '<textarea cols="70" rows="20" name="text">%s</textarea>'
print(s % self.data)
print('<input type="hidden" name="cmd" value="create">')
print('<input type="hidden" name="page" value="%s">' % self.name)
print('<br>')
print('<input type="submit" value="%s Page">' % label)
print("</form>")
def cmd_create(self, form):
self.data = form.getvalue("text", "").strip()
error = self.store()
if error:
print("<h1>I'm sorry. That didn't work</h1>")
print("<p>An error occurred while attempting to write the file:")
print("<p>", escape(error))
else:
# Use a redirect directive, to avoid "reload page" problems
print("<head>")
s = '<meta http-equiv="refresh" content="1; URL=%s">'
print(s % (self.scripturl + "?cmd=view&page=" + self.name))
print("<head>")
print("<h1>OK</h1>")
print("<p>If nothing happens, please click here:", end=' ')
print(self.mklink("view", self.name, self.name))
def cmd_new(self, form):
self.cmd_edit(form, label="Create")
def iswikiword(self, word):
return re.match("[A-Z][a-z]+([A-Z][a-z]*)+", word)
def splitwikiword(self, word):
chars = []
for c in word:
if chars and c.isupper():
chars.append(' ')
chars.append(c)
return "".join(chars)
def mkfile(self, name=None):
if name is None:
name = self.name
return os.path.join(self.homedir, name + ".txt")
def mklink(self, cmd, page, text):
link = self.scripturl + "?cmd=" + cmd + "&page=" + page
return '<a href="%s">%s</a>' % (link, text)
def load(self):
try:
f = open(self.mkfile())
data = f.read().strip()
f.close()
except IOError:
data = ""
self.data = data
def store(self):
data = self.data
try:
f = open(self.mkfile(), "w")
f.write(data)
if data and not data.endswith('\n'):
f.write('\n')
f.close()
return ""
except IOError as err:
return "IOError: %s" % str(err)

View File

@ -1,60 +0,0 @@
Subject: Re: What language would you use?
From: Tom Christiansen <tchrist@mox.perl.com>
Date: 6 Nov 1994 15:14:51 GMT
Newsgroups: comp.lang.python,comp.lang.tcl,comp.lang.scheme,comp.lang.misc,comp.lang.perl
Message-Id: <39irtb$3t4@csnews.cs.Colorado.EDU>
References: <39b7ha$j9v@zeno.nscf.org> <39hhjp$lgn@csnews.cs.Colorado.EDU> <39hvsu$dus@mathserv.mps.ohio-state.edu>
[...]
If you're really into benchmarks, I'd love it if someone were to code up
the following problems in tcl, python, and scheme (and whatever else you'd
like). Separate versions (one optimized for speed, one for beauty :-) are
ok. Post your code so we can time it on our own systems.
0) Factorial Test (numerics and function calls)
(we did this already)
1) Regular Expressions Test
Read a file of (extended per egrep) regular expressions (one per line),
and apply those to all files whose names are listed on the command line.
Basically, an 'egrep -f' simulator. Test it with 20 "vt100" patterns
against a five /etc/termcap files. Tests using more elaborate patters
would also be interesting. Your code should not break if given hundreds
of regular expressions or binary files to scan.
2) Sorting Test
Sort an input file that consists of lines like this
var1=23 other=14 ditto=23 fred=2
such that each output line is sorted WRT to the number. Order
of output lines does not change. Resolve collisions using the
variable name. e.g.
fred=2 other=14 ditto=23 var1=23
Lines may be up to several kilobytes in length and contain
zillions of variables.
3) System Test
Given a list of directories, report any bogus symbolic links contained
anywhere in those subtrees. A bogus symbolic link is one that cannot
be resolved because it points to a nonexistent or otherwise
unresolvable file. Do *not* use an external find executable.
Directories may be very very deep. Print a warning immediately if the
system you're running on doesn't support symbolic links.
I'll post perl solutions if people post the others.
--tom
--
Tom Christiansen Perl Consultant, Gamer, Hiker tchrist@mox.perl.com
"But Billy! A *small* allowance prepares you for a lifetime of small
salaries and for your Social Security payments." --Family Circus

View File

@ -1,4 +0,0 @@
^def
^class
^import
^from

View File

@ -1,47 +0,0 @@
#! /usr/bin/env python3
# 1) Regular Expressions Test
#
# Read a file of (extended per egrep) regular expressions (one per line),
# and apply those to all files whose names are listed on the command line.
# Basically, an 'egrep -f' simulator. Test it with 20 "vt100" patterns
# against a five /etc/termcap files. Tests using more elaborate patters
# would also be interesting. Your code should not break if given hundreds
# of regular expressions or binary files to scan.
# This implementation:
# - combines all patterns into a single one using ( ... | ... | ... )
# - reads patterns from stdin, scans files given as command line arguments
# - produces output in the format <file>:<lineno>:<line>
# - is only about 2.5 times as slow as egrep (though I couldn't run
# Tom's test -- this system, a vanilla SGI, only has /etc/terminfo)
import string
import sys
import re
def main():
pats = list(map(chomp, sys.stdin.readlines()))
bigpat = '(' + '|'.join(pats) + ')'
prog = re.compile(bigpat)
for file in sys.argv[1:]:
try:
fp = open(file, 'r')
except IOError as msg:
print("%s: %s" % (file, msg))
continue
lineno = 0
while 1:
line = fp.readline()
if not line:
break
lineno = lineno + 1
if prog.search(line):
print("%s:%s:%s" % (file, lineno, line), end=' ')
def chomp(s):
return s.rstrip('\n')
if __name__ == '__main__':
main()

View File

@ -1,45 +0,0 @@
#! /usr/bin/env python3
# 2) Sorting Test
#
# Sort an input file that consists of lines like this
#
# var1=23 other=14 ditto=23 fred=2
#
# such that each output line is sorted WRT to the number. Order
# of output lines does not change. Resolve collisions using the
# variable name. e.g.
#
# fred=2 other=14 ditto=23 var1=23
#
# Lines may be up to several kilobytes in length and contain
# zillions of variables.
# This implementation:
# - Reads stdin, writes stdout
# - Uses any amount of whitespace to separate fields
# - Allows signed numbers
# - Treats illegally formatted fields as field=0
# - Outputs the sorted fields with exactly one space between them
# - Handles blank input lines correctly
import re
import sys
def main():
prog = re.compile('^(.*)=([-+]?[0-9]+)')
def makekey(item, prog=prog):
match = prog.match(item)
if match:
var, num = match.groups()
return int(num), var
else:
# Bad input -- pretend it's a var with value 0
return 0, item
for line in sys.stdin:
items = sorted(makekey(item) for item in line.split())
for num, var in items:
print("%s=%s" % (var, num), end=' ')
print()
main()

View File

@ -1,74 +0,0 @@
#! /usr/bin/env python3
# 3) System Test
#
# Given a list of directories, report any bogus symbolic links contained
# anywhere in those subtrees. A bogus symbolic link is one that cannot
# be resolved because it points to a nonexistent or otherwise
# unresolvable file. Do *not* use an external find executable.
# Directories may be very very deep. Print a warning immediately if the
# system you're running on doesn't support symbolic links.
# This implementation:
# - takes one optional argument, using the current directory as default
# - uses chdir to increase performance
# - sorts the names per directory
# - prints output lines of the form "path1 -> path2" as it goes
# - prints error messages about directories it can't list or chdir into
import os
import sys
from stat import *
def main():
try:
# Note: can't test for presence of lstat -- it's always there
dummy = os.readlink
except AttributeError:
print("This system doesn't have symbolic links")
sys.exit(0)
if sys.argv[1:]:
prefix = sys.argv[1]
else:
prefix = ''
if prefix:
os.chdir(prefix)
if prefix[-1:] != '/': prefix = prefix + '/'
reportboguslinks(prefix)
else:
reportboguslinks('')
def reportboguslinks(prefix):
try:
names = os.listdir('.')
except os.error as msg:
print("%s%s: can't list: %s" % (prefix, '.', msg))
return
names.sort()
for name in names:
if name == os.curdir or name == os.pardir:
continue
try:
mode = os.lstat(name)[ST_MODE]
except os.error:
print("%s%s: can't stat: %s" % (prefix, name, msg))
continue
if S_ISLNK(mode):
try:
os.stat(name)
except os.error:
print("%s%s -> %s" % \
(prefix, name, os.readlink(name)))
elif S_ISDIR(mode):
try:
os.chdir(name)
except os.error as msg:
print("%s%s: can't chdir: %s" % \
(prefix, name, msg))
continue
try:
reportboguslinks(prefix + name + '/')
finally:
os.chdir('..')
main()

View File

@ -1,273 +0,0 @@
#!/usr/bin/env python3
#
# $Id$
#
# (n)curses exerciser in Python, an interactive test for the curses
# module. Currently, only the panel demos are ported.
import curses
from curses import panel
def wGetchar(win = None):
if win is None: win = stdscr
return win.getch()
def Getchar():
wGetchar()
#
# Panels tester
#
def wait_a_while():
if nap_msec == 1:
Getchar()
else:
curses.napms(nap_msec)
def saywhat(text):
stdscr.move(curses.LINES - 1, 0)
stdscr.clrtoeol()
stdscr.addstr(text)
def mkpanel(color, rows, cols, tly, tlx):
win = curses.newwin(rows, cols, tly, tlx)
pan = panel.new_panel(win)
if curses.has_colors():
if color == curses.COLOR_BLUE:
fg = curses.COLOR_WHITE
else:
fg = curses.COLOR_BLACK
bg = color
curses.init_pair(color, fg, bg)
win.bkgdset(ord(' '), curses.color_pair(color))
else:
win.bkgdset(ord(' '), curses.A_BOLD)
return pan
def pflush():
panel.update_panels()
curses.doupdate()
def fill_panel(pan):
win = pan.window()
num = pan.userptr()[1]
win.move(1, 1)
win.addstr("-pan%c-" % num)
win.clrtoeol()
win.box()
maxy, maxx = win.getmaxyx()
for y in range(2, maxy - 1):
for x in range(1, maxx - 1):
win.move(y, x)
win.addch(num)
def demo_panels(win):
global stdscr, nap_msec, mod
stdscr = win
nap_msec = 1
mod = ["test", "TEST", "(**)", "*()*", "<-->", "LAST"]
stdscr.refresh()
for y in range(0, curses.LINES - 1):
for x in range(0, curses.COLS):
stdscr.addstr("%d" % ((y + x) % 10))
for y in range(0, 1):
p1 = mkpanel(curses.COLOR_RED,
curses.LINES // 2 - 2,
curses.COLS // 8 + 1,
0,
0)
p1.set_userptr("p1")
p2 = mkpanel(curses.COLOR_GREEN,
curses.LINES // 2 + 1,
curses.COLS // 7,
curses.LINES // 4,
curses.COLS // 10)
p2.set_userptr("p2")
p3 = mkpanel(curses.COLOR_YELLOW,
curses.LINES // 4,
curses.COLS // 10,
curses.LINES // 2,
curses.COLS // 9)
p3.set_userptr("p3")
p4 = mkpanel(curses.COLOR_BLUE,
curses.LINES // 2 - 2,
curses.COLS // 8,
curses.LINES // 2 - 2,
curses.COLS // 3)
p4.set_userptr("p4")
p5 = mkpanel(curses.COLOR_MAGENTA,
curses.LINES // 2 - 2,
curses.COLS // 8,
curses.LINES // 2,
curses.COLS // 2 - 2)
p5.set_userptr("p5")
fill_panel(p1)
fill_panel(p2)
fill_panel(p3)
fill_panel(p4)
fill_panel(p5)
p4.hide()
p5.hide()
pflush()
saywhat("press any key to continue")
wait_a_while()
saywhat("h3 s1 s2 s4 s5;press any key to continue")
p1.move(0, 0)
p3.hide()
p1.show()
p2.show()
p4.show()
p5.show()
pflush()
wait_a_while()
saywhat("s1; press any key to continue")
p1.show()
pflush()
wait_a_while()
saywhat("s2; press any key to continue")
p2.show()
pflush()
wait_a_while()
saywhat("m2; press any key to continue")
p2.move(curses.LINES // 3 + 1, curses.COLS // 8)
pflush()
wait_a_while()
saywhat("s3; press any key to continue")
p3.show()
pflush()
wait_a_while()
saywhat("m3; press any key to continue")
p3.move(curses.LINES // 4 + 1, curses.COLS // 15)
pflush()
wait_a_while()
saywhat("b3; press any key to continue")
p3.bottom()
pflush()
wait_a_while()
saywhat("s4; press any key to continue")
p4.show()
pflush()
wait_a_while()
saywhat("s5; press any key to continue")
p5.show()
pflush()
wait_a_while()
saywhat("t3; press any key to continue")
p3.top()
pflush()
wait_a_while()
saywhat("t1; press any key to continue")
p1.show()
pflush()
wait_a_while()
saywhat("t2; press any key to continue")
p2.show()
pflush()
wait_a_while()
saywhat("t3; press any key to continue")
p3.show()
pflush()
wait_a_while()
saywhat("t4; press any key to continue")
p4.show()
pflush()
wait_a_while()
for itmp in range(0, 6):
w4 = p4.window()
w5 = p5.window()
saywhat("m4; press any key to continue")
w4.move(curses.LINES // 8, 1)
w4.addstr(mod[itmp])
p4.move(curses.LINES // 6, itmp * curses.COLS // 8)
w5.move(curses.LINES // 6, 1)
w5.addstr(mod[itmp])
pflush()
wait_a_while()
saywhat("m5; press any key to continue")
w4.move(curses.LINES // 6, 1)
w4.addstr(mod[itmp])
p5.move(curses.LINES // 3 - 1, itmp * 10 + 6)
w5.move(curses.LINES // 8, 1)
w5.addstr(mod[itmp])
pflush()
wait_a_while()
saywhat("m4; press any key to continue")
p4.move(curses.LINES // 6, (itmp + 1) * curses.COLS // 8)
pflush()
wait_a_while()
saywhat("t5; press any key to continue")
p5.top()
pflush()
wait_a_while()
saywhat("t2; press any key to continue")
p2.top()
pflush()
wait_a_while()
saywhat("t1; press any key to continue")
p1.top()
pflush()
wait_a_while()
saywhat("d2; press any key to continue")
del p2
pflush()
wait_a_while()
saywhat("h3; press any key to continue")
p3.hide()
pflush()
wait_a_while()
saywhat("d1; press any key to continue")
del p1
pflush()
wait_a_while()
saywhat("d4; press any key to continue")
del p4
pflush()
wait_a_while()
saywhat("d5; press any key to continue")
del p5
pflush()
wait_a_while()
if nap_msec == 1:
break
nap_msec = 100
#
# one fine day there'll be the menu at this place
#
curses.wrapper(demo_panels)

View File

@ -1,94 +0,0 @@
#!/usr/bin/env python3
#
# $Id$
#
# somebody should probably check the randrange()s...
import curses
from random import randrange
def next_j(j):
if j == 0:
j = 4
else:
j -= 1
if curses.has_colors():
z = randrange(0, 3)
color = curses.color_pair(z)
if z:
color = color | curses.A_BOLD
stdscr.attrset(color)
return j
def main(win):
# we know that the first argument from curses.wrapper() is stdscr.
# Initialize it globally for convenience.
global stdscr
stdscr = win
if curses.has_colors():
bg = curses.COLOR_BLACK
curses.init_pair(1, curses.COLOR_BLUE, bg)
curses.init_pair(2, curses.COLOR_CYAN, bg)
curses.nl()
curses.noecho()
# XXX curs_set() always returns ERR
# curses.curs_set(0)
stdscr.timeout(0)
c = curses.COLS - 4
r = curses.LINES - 4
xpos = [0] * c
ypos = [0] * r
for j in range(4, -1, -1):
xpos[j] = randrange(0, c) + 2
ypos[j] = randrange(0, r) + 2
j = 0
while True:
x = randrange(0, c) + 2
y = randrange(0, r) + 2
stdscr.addch(y, x, ord('.'))
stdscr.addch(ypos[j], xpos[j], ord('o'))
j = next_j(j)
stdscr.addch(ypos[j], xpos[j], ord('O'))
j = next_j(j)
stdscr.addch( ypos[j] - 1, xpos[j], ord('-'))
stdscr.addstr(ypos[j], xpos[j] - 1, "|.|")
stdscr.addch( ypos[j] + 1, xpos[j], ord('-'))
j = next_j(j)
stdscr.addch( ypos[j] - 2, xpos[j], ord('-'))
stdscr.addstr(ypos[j] - 1, xpos[j] - 1, "/ \\")
stdscr.addstr(ypos[j], xpos[j] - 2, "| O |")
stdscr.addstr(ypos[j] + 1, xpos[j] - 1, "\\ /")
stdscr.addch( ypos[j] + 2, xpos[j], ord('-'))
j = next_j(j)
stdscr.addch( ypos[j] - 2, xpos[j], ord(' '))
stdscr.addstr(ypos[j] - 1, xpos[j] - 1, " ")
stdscr.addstr(ypos[j], xpos[j] - 2, " ")
stdscr.addstr(ypos[j] + 1, xpos[j] - 1, " ")
stdscr.addch( ypos[j] + 2, xpos[j], ord(' '))
xpos[j] = x
ypos[j] = y
ch = stdscr.getch()
if ch == ord('q') or ch == ord('Q'):
return
elif ch == ord('s'):
stdscr.nodelay(0)
elif ch == ord(' '):
stdscr.nodelay(1)
curses.napms(50)
curses.wrapper(main)

View File

@ -1,147 +0,0 @@
#!/usr/bin/env python3
#
# $Id$
#
# From tclock.c, Copyright Howard Jones <ha.jones@ic.ac.uk>, September 1994.
from math import *
import curses, time
ASPECT = 2.2
def sign(_x):
if _x < 0: return -1
return 1
def A2XY(angle, radius):
return (int(round(ASPECT * radius * sin(angle))),
int(round(radius * cos(angle))))
def plot(x, y, col):
stdscr.addch(y, x, col)
# draw a diagonal line using Bresenham's algorithm
def dline(pair, from_x, from_y, x2, y2, ch):
if curses.has_colors():
stdscr.attrset(curses.color_pair(pair))
dx = x2 - from_x
dy = y2 - from_y
ax = abs(dx * 2)
ay = abs(dy * 2)
sx = sign(dx)
sy = sign(dy)
x = from_x
y = from_y
if ax > ay:
d = ay - ax // 2
while True:
plot(x, y, ch)
if x == x2:
return
if d >= 0:
y += sy
d -= ax
x += sx
d += ay
else:
d = ax - ay // 2
while True:
plot(x, y, ch)
if y == y2:
return
if d >= 0:
x += sx
d -= ay
y += sy
d += ax
def main(win):
global stdscr
stdscr = win
lastbeep = -1
my_bg = curses.COLOR_BLACK
stdscr.nodelay(1)
stdscr.timeout(0)
# curses.curs_set(0)
if curses.has_colors():
curses.init_pair(1, curses.COLOR_RED, my_bg)
curses.init_pair(2, curses.COLOR_MAGENTA, my_bg)
curses.init_pair(3, curses.COLOR_GREEN, my_bg)
cx = (curses.COLS - 1) // 2
cy = curses.LINES // 2
ch = min( cy-1, int(cx // ASPECT) - 1)
mradius = (3 * ch) // 4
hradius = ch // 2
sradius = 5 * ch // 6
for i in range(0, 12):
sangle = (i + 1) * 2.0 * pi / 12.0
sdx, sdy = A2XY(sangle, sradius)
stdscr.addstr(cy - sdy, cx + sdx, "%d" % (i + 1))
stdscr.addstr(0, 0,
"ASCII Clock by Howard Jones <ha.jones@ic.ac.uk>, 1994")
sradius = max(sradius-4, 8)
while True:
curses.napms(1000)
tim = time.time()
t = time.localtime(tim)
hours = t[3] + t[4] / 60.0
if hours > 12.0:
hours -= 12.0
mangle = t[4] * 2 * pi / 60.0
mdx, mdy = A2XY(mangle, mradius)
hangle = hours * 2 * pi / 12.0
hdx, hdy = A2XY(hangle, hradius)
sangle = t[5] * 2 * pi / 60.0
sdx, sdy = A2XY(sangle, sradius)
dline(3, cx, cy, cx + mdx, cy - mdy, ord('#'))
stdscr.attrset(curses.A_REVERSE)
dline(2, cx, cy, cx + hdx, cy - hdy, ord('.'))
stdscr.attroff(curses.A_REVERSE)
if curses.has_colors():
stdscr.attrset(curses.color_pair(1))
plot(cx + sdx, cy - sdy, ord('O'))
if curses.has_colors():
stdscr.attrset(curses.color_pair(0))
stdscr.addstr(curses.LINES - 2, 0, time.ctime(tim))
stdscr.refresh()
if (t[5] % 5) == 0 and t[5] != lastbeep:
lastbeep = t[5]
curses.beep()
ch = stdscr.getch()
if ch == ord('q'):
return 0
plot(cx + sdx, cy - sdy, ord(' '))
dline(0, cx, cy, cx + hdx, cy - hdy, ord(' '))
dline(0, cx, cy, cx + mdx, cy - mdy, ord(' '))
curses.wrapper(main)

View File

@ -1,906 +0,0 @@
# asciixmas
# December 1989 Larry Bartz Indianapolis, IN
#
# $Id$
#
# I'm dreaming of an ascii character-based monochrome Christmas,
# Just like the ones I used to know!
# Via a full duplex communications channel,
# At 9600 bits per second,
# Even though it's kinda slow.
#
# I'm dreaming of an ascii character-based monochrome Christmas,
# With ev'ry C program I write!
# May your screen be merry and bright!
# And may all your Christmases be amber or green,
# (for reduced eyestrain and improved visibility)!
#
#
# Notes on the Python version:
# I used a couple of `try...except curses.error' to get around some functions
# returning ERR. The errors come from using wrapping functions to fill
# windows to the last character cell. The C version doesn't have this problem,
# it simply ignores any return values.
#
import curses
import sys
FROMWHO = "Thomas Gellekum <tg@FreeBSD.org>"
def set_color(win, color):
if curses.has_colors():
n = color + 1
curses.init_pair(n, color, my_bg)
win.attroff(curses.A_COLOR)
win.attron(curses.color_pair(n))
def unset_color(win):
if curses.has_colors():
win.attrset(curses.color_pair(0))
def look_out(msecs):
curses.napms(msecs)
if stdscr.getch() != -1:
curses.beep()
sys.exit(0)
def boxit():
for y in range(0, 20):
stdscr.addch(y, 7, ord('|'))
for x in range(8, 80):
stdscr.addch(19, x, ord('_'))
for x in range(0, 80):
stdscr.addch(22, x, ord('_'))
return
def seas():
stdscr.addch(4, 1, ord('S'))
stdscr.addch(6, 1, ord('E'))
stdscr.addch(8, 1, ord('A'))
stdscr.addch(10, 1, ord('S'))
stdscr.addch(12, 1, ord('O'))
stdscr.addch(14, 1, ord('N'))
stdscr.addch(16, 1, ord("'"))
stdscr.addch(18, 1, ord('S'))
return
def greet():
stdscr.addch(3, 5, ord('G'))
stdscr.addch(5, 5, ord('R'))
stdscr.addch(7, 5, ord('E'))
stdscr.addch(9, 5, ord('E'))
stdscr.addch(11, 5, ord('T'))
stdscr.addch(13, 5, ord('I'))
stdscr.addch(15, 5, ord('N'))
stdscr.addch(17, 5, ord('G'))
stdscr.addch(19, 5, ord('S'))
return
def fromwho():
stdscr.addstr(21, 13, FROMWHO)
return
def tree():
set_color(treescrn, curses.COLOR_GREEN)
treescrn.addch(1, 11, ord('/'))
treescrn.addch(2, 11, ord('/'))
treescrn.addch(3, 10, ord('/'))
treescrn.addch(4, 9, ord('/'))
treescrn.addch(5, 9, ord('/'))
treescrn.addch(6, 8, ord('/'))
treescrn.addch(7, 7, ord('/'))
treescrn.addch(8, 6, ord('/'))
treescrn.addch(9, 6, ord('/'))
treescrn.addch(10, 5, ord('/'))
treescrn.addch(11, 3, ord('/'))
treescrn.addch(12, 2, ord('/'))
treescrn.addch(1, 13, ord('\\'))
treescrn.addch(2, 13, ord('\\'))
treescrn.addch(3, 14, ord('\\'))
treescrn.addch(4, 15, ord('\\'))
treescrn.addch(5, 15, ord('\\'))
treescrn.addch(6, 16, ord('\\'))
treescrn.addch(7, 17, ord('\\'))
treescrn.addch(8, 18, ord('\\'))
treescrn.addch(9, 18, ord('\\'))
treescrn.addch(10, 19, ord('\\'))
treescrn.addch(11, 21, ord('\\'))
treescrn.addch(12, 22, ord('\\'))
treescrn.addch(4, 10, ord('_'))
treescrn.addch(4, 14, ord('_'))
treescrn.addch(8, 7, ord('_'))
treescrn.addch(8, 17, ord('_'))
treescrn.addstr(13, 0, "//////////// \\\\\\\\\\\\\\\\\\\\\\\\")
treescrn.addstr(14, 11, "| |")
treescrn.addstr(15, 11, "|_|")
unset_color(treescrn)
treescrn.refresh()
w_del_msg.refresh()
return
def balls():
treescrn.overlay(treescrn2)
set_color(treescrn2, curses.COLOR_BLUE)
treescrn2.addch(3, 9, ord('@'))
treescrn2.addch(3, 15, ord('@'))
treescrn2.addch(4, 8, ord('@'))
treescrn2.addch(4, 16, ord('@'))
treescrn2.addch(5, 7, ord('@'))
treescrn2.addch(5, 17, ord('@'))
treescrn2.addch(7, 6, ord('@'))
treescrn2.addch(7, 18, ord('@'))
treescrn2.addch(8, 5, ord('@'))
treescrn2.addch(8, 19, ord('@'))
treescrn2.addch(10, 4, ord('@'))
treescrn2.addch(10, 20, ord('@'))
treescrn2.addch(11, 2, ord('@'))
treescrn2.addch(11, 22, ord('@'))
treescrn2.addch(12, 1, ord('@'))
treescrn2.addch(12, 23, ord('@'))
unset_color(treescrn2)
treescrn2.refresh()
w_del_msg.refresh()
return
def star():
treescrn2.attrset(curses.A_BOLD | curses.A_BLINK)
set_color(treescrn2, curses.COLOR_YELLOW)
treescrn2.addch(0, 12, ord('*'))
treescrn2.standend()
unset_color(treescrn2)
treescrn2.refresh()
w_del_msg.refresh()
return
def strng1():
treescrn2.attrset(curses.A_BOLD | curses.A_BLINK)
set_color(treescrn2, curses.COLOR_WHITE)
treescrn2.addch(3, 13, ord('\''))
treescrn2.addch(3, 12, ord(':'))
treescrn2.addch(3, 11, ord('.'))
treescrn2.attroff(curses.A_BOLD | curses.A_BLINK)
unset_color(treescrn2)
treescrn2.refresh()
w_del_msg.refresh()
return
def strng2():
treescrn2.attrset(curses.A_BOLD | curses.A_BLINK)
set_color(treescrn2, curses.COLOR_WHITE)
treescrn2.addch(5, 14, ord('\''))
treescrn2.addch(5, 13, ord(':'))
treescrn2.addch(5, 12, ord('.'))
treescrn2.addch(5, 11, ord(','))
treescrn2.addch(6, 10, ord('\''))
treescrn2.addch(6, 9, ord(':'))
treescrn2.attroff(curses.A_BOLD | curses.A_BLINK)
unset_color(treescrn2)
treescrn2.refresh()
w_del_msg.refresh()
return
def strng3():
treescrn2.attrset(curses.A_BOLD | curses.A_BLINK)
set_color(treescrn2, curses.COLOR_WHITE)
treescrn2.addch(7, 16, ord('\''))
treescrn2.addch(7, 15, ord(':'))
treescrn2.addch(7, 14, ord('.'))
treescrn2.addch(7, 13, ord(','))
treescrn2.addch(8, 12, ord('\''))
treescrn2.addch(8, 11, ord(':'))
treescrn2.addch(8, 10, ord('.'))
treescrn2.addch(8, 9, ord(','))
treescrn2.attroff(curses.A_BOLD | curses.A_BLINK)
unset_color(treescrn2)
treescrn2.refresh()
w_del_msg.refresh()
return
def strng4():
treescrn2.attrset(curses.A_BOLD | curses.A_BLINK)
set_color(treescrn2, curses.COLOR_WHITE)
treescrn2.addch(9, 17, ord('\''))
treescrn2.addch(9, 16, ord(':'))
treescrn2.addch(9, 15, ord('.'))
treescrn2.addch(9, 14, ord(','))
treescrn2.addch(10, 13, ord('\''))
treescrn2.addch(10, 12, ord(':'))
treescrn2.addch(10, 11, ord('.'))
treescrn2.addch(10, 10, ord(','))
treescrn2.addch(11, 9, ord('\''))
treescrn2.addch(11, 8, ord(':'))
treescrn2.addch(11, 7, ord('.'))
treescrn2.addch(11, 6, ord(','))
treescrn2.addch(12, 5, ord('\''))
treescrn2.attroff(curses.A_BOLD | curses.A_BLINK)
unset_color(treescrn2)
treescrn2.refresh()
w_del_msg.refresh()
return
def strng5():
treescrn2.attrset(curses.A_BOLD | curses.A_BLINK)
set_color(treescrn2, curses.COLOR_WHITE)
treescrn2.addch(11, 19, ord('\''))
treescrn2.addch(11, 18, ord(':'))
treescrn2.addch(11, 17, ord('.'))
treescrn2.addch(11, 16, ord(','))
treescrn2.addch(12, 15, ord('\''))
treescrn2.addch(12, 14, ord(':'))
treescrn2.addch(12, 13, ord('.'))
treescrn2.addch(12, 12, ord(','))
treescrn2.attroff(curses.A_BOLD | curses.A_BLINK)
unset_color(treescrn2)
# save a fully lit tree
treescrn2.overlay(treescrn)
treescrn2.refresh()
w_del_msg.refresh()
return
def blinkit():
treescrn8.touchwin()
for cycle in range(5):
if cycle == 0:
treescrn3.overlay(treescrn8)
treescrn8.refresh()
w_del_msg.refresh()
break
elif cycle == 1:
treescrn4.overlay(treescrn8)
treescrn8.refresh()
w_del_msg.refresh()
break
elif cycle == 2:
treescrn5.overlay(treescrn8)
treescrn8.refresh()
w_del_msg.refresh()
break
elif cycle == 3:
treescrn6.overlay(treescrn8)
treescrn8.refresh()
w_del_msg.refresh()
break
elif cycle == 4:
treescrn7.overlay(treescrn8)
treescrn8.refresh()
w_del_msg.refresh()
break
treescrn8.touchwin()
# ALL ON
treescrn.overlay(treescrn8)
treescrn8.refresh()
w_del_msg.refresh()
return
def deer_step(win, y, x):
win.mvwin(y, x)
win.refresh()
w_del_msg.refresh()
look_out(5)
def reindeer():
y_pos = 0
for x_pos in range(70, 62, -1):
if x_pos < 66: y_pos = 1
for looper in range(0, 4):
dotdeer0.addch(y_pos, x_pos, ord('.'))
dotdeer0.refresh()
w_del_msg.refresh()
dotdeer0.erase()
dotdeer0.refresh()
w_del_msg.refresh()
look_out(50)
y_pos = 2
for x_pos in range(x_pos - 1, 50, -1):
for looper in range(0, 4):
if x_pos < 56:
y_pos = 3
try:
stardeer0.addch(y_pos, x_pos, ord('*'))
except curses.error:
pass
stardeer0.refresh()
w_del_msg.refresh()
stardeer0.erase()
stardeer0.refresh()
w_del_msg.refresh()
else:
dotdeer0.addch(y_pos, x_pos, ord('*'))
dotdeer0.refresh()
w_del_msg.refresh()
dotdeer0.erase()
dotdeer0.refresh()
w_del_msg.refresh()
x_pos = 58
for y_pos in range(2, 5):
lildeer0.touchwin()
lildeer0.refresh()
w_del_msg.refresh()
for looper in range(0, 4):
deer_step(lildeer3, y_pos, x_pos)
deer_step(lildeer2, y_pos, x_pos)
deer_step(lildeer1, y_pos, x_pos)
deer_step(lildeer2, y_pos, x_pos)
deer_step(lildeer3, y_pos, x_pos)
lildeer0.touchwin()
lildeer0.refresh()
w_del_msg.refresh()
x_pos -= 2
x_pos = 35
for y_pos in range(5, 10):
middeer0.touchwin()
middeer0.refresh()
w_del_msg.refresh()
for looper in range(2):
deer_step(middeer3, y_pos, x_pos)
deer_step(middeer2, y_pos, x_pos)
deer_step(middeer1, y_pos, x_pos)
deer_step(middeer2, y_pos, x_pos)
deer_step(middeer3, y_pos, x_pos)
middeer0.touchwin()
middeer0.refresh()
w_del_msg.refresh()
x_pos -= 3
look_out(300)
y_pos = 1
for x_pos in range(8, 16):
deer_step(bigdeer4, y_pos, x_pos)
deer_step(bigdeer3, y_pos, x_pos)
deer_step(bigdeer2, y_pos, x_pos)
deer_step(bigdeer1, y_pos, x_pos)
deer_step(bigdeer2, y_pos, x_pos)
deer_step(bigdeer3, y_pos, x_pos)
deer_step(bigdeer4, y_pos, x_pos)
deer_step(bigdeer0, y_pos, x_pos)
x_pos -= 1
for looper in range(0, 6):
deer_step(lookdeer4, y_pos, x_pos)
deer_step(lookdeer3, y_pos, x_pos)
deer_step(lookdeer2, y_pos, x_pos)
deer_step(lookdeer1, y_pos, x_pos)
deer_step(lookdeer2, y_pos, x_pos)
deer_step(lookdeer3, y_pos, x_pos)
deer_step(lookdeer4, y_pos, x_pos)
deer_step(lookdeer0, y_pos, x_pos)
for y_pos in range(y_pos, 10):
for looper in range(0, 2):
deer_step(bigdeer4, y_pos, x_pos)
deer_step(bigdeer3, y_pos, x_pos)
deer_step(bigdeer2, y_pos, x_pos)
deer_step(bigdeer1, y_pos, x_pos)
deer_step(bigdeer2, y_pos, x_pos)
deer_step(bigdeer3, y_pos, x_pos)
deer_step(bigdeer4, y_pos, x_pos)
deer_step(bigdeer0, y_pos, x_pos)
y_pos -= 1
deer_step(lookdeer3, y_pos, x_pos)
return
def main(win):
global stdscr
stdscr = win
global my_bg, y_pos, x_pos
global treescrn, treescrn2, treescrn3, treescrn4
global treescrn5, treescrn6, treescrn7, treescrn8
global dotdeer0, stardeer0
global lildeer0, lildeer1, lildeer2, lildeer3
global middeer0, middeer1, middeer2, middeer3
global bigdeer0, bigdeer1, bigdeer2, bigdeer3, bigdeer4
global lookdeer0, lookdeer1, lookdeer2, lookdeer3, lookdeer4
global w_holiday, w_del_msg
my_bg = curses.COLOR_BLACK
# curses.curs_set(0)
treescrn = curses.newwin(16, 27, 3, 53)
treescrn2 = curses.newwin(16, 27, 3, 53)
treescrn3 = curses.newwin(16, 27, 3, 53)
treescrn4 = curses.newwin(16, 27, 3, 53)
treescrn5 = curses.newwin(16, 27, 3, 53)
treescrn6 = curses.newwin(16, 27, 3, 53)
treescrn7 = curses.newwin(16, 27, 3, 53)
treescrn8 = curses.newwin(16, 27, 3, 53)
dotdeer0 = curses.newwin(3, 71, 0, 8)
stardeer0 = curses.newwin(4, 56, 0, 8)
lildeer0 = curses.newwin(7, 53, 0, 8)
lildeer1 = curses.newwin(2, 4, 0, 0)
lildeer2 = curses.newwin(2, 4, 0, 0)
lildeer3 = curses.newwin(2, 4, 0, 0)
middeer0 = curses.newwin(15, 42, 0, 8)
middeer1 = curses.newwin(3, 7, 0, 0)
middeer2 = curses.newwin(3, 7, 0, 0)
middeer3 = curses.newwin(3, 7, 0, 0)
bigdeer0 = curses.newwin(10, 23, 0, 0)
bigdeer1 = curses.newwin(10, 23, 0, 0)
bigdeer2 = curses.newwin(10, 23, 0, 0)
bigdeer3 = curses.newwin(10, 23, 0, 0)
bigdeer4 = curses.newwin(10, 23, 0, 0)
lookdeer0 = curses.newwin(10, 25, 0, 0)
lookdeer1 = curses.newwin(10, 25, 0, 0)
lookdeer2 = curses.newwin(10, 25, 0, 0)
lookdeer3 = curses.newwin(10, 25, 0, 0)
lookdeer4 = curses.newwin(10, 25, 0, 0)
w_holiday = curses.newwin(1, 27, 3, 27)
w_del_msg = curses.newwin(1, 20, 23, 60)
try:
w_del_msg.addstr(0, 0, "Hit any key to quit")
except curses.error:
pass
try:
w_holiday.addstr(0, 0, "H A P P Y H O L I D A Y S")
except curses.error:
pass
# set up the windows for our various reindeer
lildeer1.addch(0, 0, ord('V'))
lildeer1.addch(1, 0, ord('@'))
lildeer1.addch(1, 1, ord('<'))
lildeer1.addch(1, 2, ord('>'))
try:
lildeer1.addch(1, 3, ord('~'))
except curses.error:
pass
lildeer2.addch(0, 0, ord('V'))
lildeer2.addch(1, 0, ord('@'))
lildeer2.addch(1, 1, ord('|'))
lildeer2.addch(1, 2, ord('|'))
try:
lildeer2.addch(1, 3, ord('~'))
except curses.error:
pass
lildeer3.addch(0, 0, ord('V'))
lildeer3.addch(1, 0, ord('@'))
lildeer3.addch(1, 1, ord('>'))
lildeer3.addch(1, 2, ord('<'))
try:
lildeer2.addch(1, 3, ord('~')) # XXX
except curses.error:
pass
middeer1.addch(0, 2, ord('y'))
middeer1.addch(0, 3, ord('y'))
middeer1.addch(1, 2, ord('0'))
middeer1.addch(1, 3, ord('('))
middeer1.addch(1, 4, ord('='))
middeer1.addch(1, 5, ord(')'))
middeer1.addch(1, 6, ord('~'))
middeer1.addch(2, 3, ord('\\'))
middeer1.addch(2, 5, ord('/'))
middeer2.addch(0, 2, ord('y'))
middeer2.addch(0, 3, ord('y'))
middeer2.addch(1, 2, ord('0'))
middeer2.addch(1, 3, ord('('))
middeer2.addch(1, 4, ord('='))
middeer2.addch(1, 5, ord(')'))
middeer2.addch(1, 6, ord('~'))
middeer2.addch(2, 3, ord('|'))
middeer2.addch(2, 5, ord('|'))
middeer3.addch(0, 2, ord('y'))
middeer3.addch(0, 3, ord('y'))
middeer3.addch(1, 2, ord('0'))
middeer3.addch(1, 3, ord('('))
middeer3.addch(1, 4, ord('='))
middeer3.addch(1, 5, ord(')'))
middeer3.addch(1, 6, ord('~'))
middeer3.addch(2, 3, ord('/'))
middeer3.addch(2, 5, ord('\\'))
bigdeer1.addch(0, 17, ord('\\'))
bigdeer1.addch(0, 18, ord('/'))
bigdeer1.addch(0, 19, ord('\\'))
bigdeer1.addch(0, 20, ord('/'))
bigdeer1.addch(1, 18, ord('\\'))
bigdeer1.addch(1, 20, ord('/'))
bigdeer1.addch(2, 19, ord('|'))
bigdeer1.addch(2, 20, ord('_'))
bigdeer1.addch(3, 18, ord('/'))
bigdeer1.addch(3, 19, ord('^'))
bigdeer1.addch(3, 20, ord('0'))
bigdeer1.addch(3, 21, ord('\\'))
bigdeer1.addch(4, 17, ord('/'))
bigdeer1.addch(4, 18, ord('/'))
bigdeer1.addch(4, 19, ord('\\'))
bigdeer1.addch(4, 22, ord('\\'))
bigdeer1.addstr(5, 7, "^~~~~~~~~// ~~U")
bigdeer1.addstr(6, 7, "( \\_____( /") # ))
bigdeer1.addstr(7, 8, "( ) /")
bigdeer1.addstr(8, 9, "\\\\ /")
bigdeer1.addstr(9, 11, "\\>/>")
bigdeer2.addch(0, 17, ord('\\'))
bigdeer2.addch(0, 18, ord('/'))
bigdeer2.addch(0, 19, ord('\\'))
bigdeer2.addch(0, 20, ord('/'))
bigdeer2.addch(1, 18, ord('\\'))
bigdeer2.addch(1, 20, ord('/'))
bigdeer2.addch(2, 19, ord('|'))
bigdeer2.addch(2, 20, ord('_'))
bigdeer2.addch(3, 18, ord('/'))
bigdeer2.addch(3, 19, ord('^'))
bigdeer2.addch(3, 20, ord('0'))
bigdeer2.addch(3, 21, ord('\\'))
bigdeer2.addch(4, 17, ord('/'))
bigdeer2.addch(4, 18, ord('/'))
bigdeer2.addch(4, 19, ord('\\'))
bigdeer2.addch(4, 22, ord('\\'))
bigdeer2.addstr(5, 7, "^~~~~~~~~// ~~U")
bigdeer2.addstr(6, 7, "(( )____( /") # ))
bigdeer2.addstr(7, 7, "( / |")
bigdeer2.addstr(8, 8, "\\/ |")
bigdeer2.addstr(9, 9, "|> |>")
bigdeer3.addch(0, 17, ord('\\'))
bigdeer3.addch(0, 18, ord('/'))
bigdeer3.addch(0, 19, ord('\\'))
bigdeer3.addch(0, 20, ord('/'))
bigdeer3.addch(1, 18, ord('\\'))
bigdeer3.addch(1, 20, ord('/'))
bigdeer3.addch(2, 19, ord('|'))
bigdeer3.addch(2, 20, ord('_'))
bigdeer3.addch(3, 18, ord('/'))
bigdeer3.addch(3, 19, ord('^'))
bigdeer3.addch(3, 20, ord('0'))
bigdeer3.addch(3, 21, ord('\\'))
bigdeer3.addch(4, 17, ord('/'))
bigdeer3.addch(4, 18, ord('/'))
bigdeer3.addch(4, 19, ord('\\'))
bigdeer3.addch(4, 22, ord('\\'))
bigdeer3.addstr(5, 7, "^~~~~~~~~// ~~U")
bigdeer3.addstr(6, 6, "( ()_____( /") # ))
bigdeer3.addstr(7, 6, "/ / /")
bigdeer3.addstr(8, 5, "|/ \\")
bigdeer3.addstr(9, 5, "/> \\>")
bigdeer4.addch(0, 17, ord('\\'))
bigdeer4.addch(0, 18, ord('/'))
bigdeer4.addch(0, 19, ord('\\'))
bigdeer4.addch(0, 20, ord('/'))
bigdeer4.addch(1, 18, ord('\\'))
bigdeer4.addch(1, 20, ord('/'))
bigdeer4.addch(2, 19, ord('|'))
bigdeer4.addch(2, 20, ord('_'))
bigdeer4.addch(3, 18, ord('/'))
bigdeer4.addch(3, 19, ord('^'))
bigdeer4.addch(3, 20, ord('0'))
bigdeer4.addch(3, 21, ord('\\'))
bigdeer4.addch(4, 17, ord('/'))
bigdeer4.addch(4, 18, ord('/'))
bigdeer4.addch(4, 19, ord('\\'))
bigdeer4.addch(4, 22, ord('\\'))
bigdeer4.addstr(5, 7, "^~~~~~~~~// ~~U")
bigdeer4.addstr(6, 6, "( )______( /") # )
bigdeer4.addstr(7, 5, "(/ \\") # )
bigdeer4.addstr(8, 0, "v___= ----^")
lookdeer1.addstr(0, 16, "\\/ \\/")
lookdeer1.addstr(1, 17, "\\Y/ \\Y/")
lookdeer1.addstr(2, 19, "\\=/")
lookdeer1.addstr(3, 17, "^\\o o/^")
lookdeer1.addstr(4, 17, "//( )")
lookdeer1.addstr(5, 7, "^~~~~~~~~// \\O/")
lookdeer1.addstr(6, 7, "( \\_____( /") # ))
lookdeer1.addstr(7, 8, "( ) /")
lookdeer1.addstr(8, 9, "\\\\ /")
lookdeer1.addstr(9, 11, "\\>/>")
lookdeer2.addstr(0, 16, "\\/ \\/")
lookdeer2.addstr(1, 17, "\\Y/ \\Y/")
lookdeer2.addstr(2, 19, "\\=/")
lookdeer2.addstr(3, 17, "^\\o o/^")
lookdeer2.addstr(4, 17, "//( )")
lookdeer2.addstr(5, 7, "^~~~~~~~~// \\O/")
lookdeer2.addstr(6, 7, "(( )____( /") # ))
lookdeer2.addstr(7, 7, "( / |")
lookdeer2.addstr(8, 8, "\\/ |")
lookdeer2.addstr(9, 9, "|> |>")
lookdeer3.addstr(0, 16, "\\/ \\/")
lookdeer3.addstr(1, 17, "\\Y/ \\Y/")
lookdeer3.addstr(2, 19, "\\=/")
lookdeer3.addstr(3, 17, "^\\o o/^")
lookdeer3.addstr(4, 17, "//( )")
lookdeer3.addstr(5, 7, "^~~~~~~~~// \\O/")
lookdeer3.addstr(6, 6, "( ()_____( /") # ))
lookdeer3.addstr(7, 6, "/ / /")
lookdeer3.addstr(8, 5, "|/ \\")
lookdeer3.addstr(9, 5, "/> \\>")
lookdeer4.addstr(0, 16, "\\/ \\/")
lookdeer4.addstr(1, 17, "\\Y/ \\Y/")
lookdeer4.addstr(2, 19, "\\=/")
lookdeer4.addstr(3, 17, "^\\o o/^")
lookdeer4.addstr(4, 17, "//( )")
lookdeer4.addstr(5, 7, "^~~~~~~~~// \\O/")
lookdeer4.addstr(6, 6, "( )______( /") # )
lookdeer4.addstr(7, 5, "(/ \\") # )
lookdeer4.addstr(8, 0, "v___= ----^")
###############################################
curses.cbreak()
stdscr.nodelay(1)
while 1:
stdscr.clear()
treescrn.erase()
w_del_msg.touchwin()
treescrn.touchwin()
treescrn2.erase()
treescrn2.touchwin()
treescrn8.erase()
treescrn8.touchwin()
stdscr.refresh()
look_out(150)
boxit()
stdscr.refresh()
look_out(150)
seas()
stdscr.refresh()
greet()
stdscr.refresh()
look_out(150)
fromwho()
stdscr.refresh()
look_out(150)
tree()
look_out(150)
balls()
look_out(150)
star()
look_out(150)
strng1()
strng2()
strng3()
strng4()
strng5()
# set up the windows for our blinking trees
#
# treescrn3
treescrn.overlay(treescrn3)
# balls
treescrn3.addch(4, 18, ord(' '))
treescrn3.addch(7, 6, ord(' '))
treescrn3.addch(8, 19, ord(' '))
treescrn3.addch(11, 22, ord(' '))
# star
treescrn3.addch(0, 12, ord('*'))
# strng1
treescrn3.addch(3, 11, ord(' '))
# strng2
treescrn3.addch(5, 13, ord(' '))
treescrn3.addch(6, 10, ord(' '))
# strng3
treescrn3.addch(7, 16, ord(' '))
treescrn3.addch(7, 14, ord(' '))
# strng4
treescrn3.addch(10, 13, ord(' '))
treescrn3.addch(10, 10, ord(' '))
treescrn3.addch(11, 8, ord(' '))
# strng5
treescrn3.addch(11, 18, ord(' '))
treescrn3.addch(12, 13, ord(' '))
# treescrn4
treescrn.overlay(treescrn4)
# balls
treescrn4.addch(3, 9, ord(' '))
treescrn4.addch(4, 16, ord(' '))
treescrn4.addch(7, 6, ord(' '))
treescrn4.addch(8, 19, ord(' '))
treescrn4.addch(11, 2, ord(' '))
treescrn4.addch(12, 23, ord(' '))
# star
treescrn4.standout()
treescrn4.addch(0, 12, ord('*'))
treescrn4.standend()
# strng1
treescrn4.addch(3, 13, ord(' '))
# strng2
# strng3
treescrn4.addch(7, 15, ord(' '))
treescrn4.addch(8, 11, ord(' '))
# strng4
treescrn4.addch(9, 16, ord(' '))
treescrn4.addch(10, 12, ord(' '))
treescrn4.addch(11, 8, ord(' '))
# strng5
treescrn4.addch(11, 18, ord(' '))
treescrn4.addch(12, 14, ord(' '))
# treescrn5
treescrn.overlay(treescrn5)
# balls
treescrn5.addch(3, 15, ord(' '))
treescrn5.addch(10, 20, ord(' '))
treescrn5.addch(12, 1, ord(' '))
# star
treescrn5.addch(0, 12, ord(' '))
# strng1
treescrn5.addch(3, 11, ord(' '))
# strng2
treescrn5.addch(5, 12, ord(' '))
# strng3
treescrn5.addch(7, 14, ord(' '))
treescrn5.addch(8, 10, ord(' '))
# strng4
treescrn5.addch(9, 15, ord(' '))
treescrn5.addch(10, 11, ord(' '))
treescrn5.addch(11, 7, ord(' '))
# strng5
treescrn5.addch(11, 17, ord(' '))
treescrn5.addch(12, 13, ord(' '))
# treescrn6
treescrn.overlay(treescrn6)
# balls
treescrn6.addch(6, 7, ord(' '))
treescrn6.addch(7, 18, ord(' '))
treescrn6.addch(10, 4, ord(' '))
treescrn6.addch(11, 23, ord(' '))
# star
treescrn6.standout()
treescrn6.addch(0, 12, ord('*'))
treescrn6.standend()
# strng1
# strng2
treescrn6.addch(5, 11, ord(' '))
# strng3
treescrn6.addch(7, 13, ord(' '))
treescrn6.addch(8, 9, ord(' '))
# strng4
treescrn6.addch(9, 14, ord(' '))
treescrn6.addch(10, 10, ord(' '))
treescrn6.addch(11, 6, ord(' '))
# strng5
treescrn6.addch(11, 16, ord(' '))
treescrn6.addch(12, 12, ord(' '))
# treescrn7
treescrn.overlay(treescrn7)
# balls
treescrn7.addch(3, 15, ord(' '))
treescrn7.addch(6, 7, ord(' '))
treescrn7.addch(7, 18, ord(' '))
treescrn7.addch(10, 4, ord(' '))
treescrn7.addch(11, 22, ord(' '))
# star
treescrn7.addch(0, 12, ord('*'))
# strng1
treescrn7.addch(3, 12, ord(' '))
# strng2
treescrn7.addch(5, 13, ord(' '))
treescrn7.addch(6, 9, ord(' '))
# strng3
treescrn7.addch(7, 15, ord(' '))
treescrn7.addch(8, 11, ord(' '))
# strng4
treescrn7.addch(9, 16, ord(' '))
treescrn7.addch(10, 12, ord(' '))
treescrn7.addch(11, 8, ord(' '))
# strng5
treescrn7.addch(11, 18, ord(' '))
treescrn7.addch(12, 14, ord(' '))
look_out(150)
reindeer()
w_holiday.touchwin()
w_holiday.refresh()
w_del_msg.refresh()
look_out(500)
for i in range(0, 20):
blinkit()
curses.wrapper(main)

View File

@ -1,10 +0,0 @@
This is the Python version of the MD5 test program from the MD5
Internet Draft (Rivest and Dusse, The MD5 Message-Digest Algorithm, 10
July 1991). The file "foo" contains the string "abc" with no trailing
newline.
When called without arguments, it acts as a filter. When called with
"-x", it executes a self-test, and the output should literally match
the output given in the RFC.
Code by Jan-Hein B\"uhrman after the original in C.

View File

@ -1 +0,0 @@
abc

View File

@ -1,122 +0,0 @@
from hashlib import md5
import string
from sys import argv
def MDPrint(str):
outstr = ''
for o in str:
outstr = (outstr
+ string.hexdigits[(o >> 4) & 0xF]
+ string.hexdigits[o & 0xF])
print(outstr, end=' ')
from time import time
def makestr(start, end):
result = ''
for i in range(start, end + 1):
result = result + chr(i)
return result
def MDTimeTrial():
TEST_BLOCK_SIZE = 1000
TEST_BLOCKS = 10000
TEST_BYTES = TEST_BLOCK_SIZE * TEST_BLOCKS
# initialize test data, need temporary string filler
filsiz = 1 << 8
filler = makestr(0, filsiz-1)
data = filler * (TEST_BLOCK_SIZE // filsiz)
data = data + filler[:(TEST_BLOCK_SIZE % filsiz)]
del filsiz, filler
# start timer
print('MD5 time trial. Processing', TEST_BYTES, 'characters...')
t1 = time()
mdContext = md5()
for i in range(TEST_BLOCKS):
mdContext.update(data)
str = mdContext.digest()
t2 = time()
MDPrint(str)
print('is digest of test input.')
print('Seconds to process test input:', t2 - t1)
print('Characters processed per second:', TEST_BYTES / (t2 - t1))
def MDString(str):
MDPrint(md5(str.encode("utf-8")).digest())
print('"' + str + '"')
def MDFile(filename):
f = open(filename, 'rb')
mdContext = md5()
while 1:
data = f.read(1024)
if not data:
break
mdContext.update(data)
MDPrint(mdContext.digest())
print(filename)
import sys
def MDFilter():
mdContext = md5()
while 1:
data = sys.stdin.read(16).encode()
if not data:
break
mdContext.update(data)
MDPrint(mdContext.digest())
print()
def MDTestSuite():
print('MD5 test suite results:')
MDString('')
MDString('a')
MDString('abc')
MDString('message digest')
MDString(makestr(ord('a'), ord('z')))
MDString(makestr(ord('A'), ord('Z'))
+ makestr(ord('a'), ord('z'))
+ makestr(ord('0'), ord('9')))
MDString((makestr(ord('1'), ord('9')) + '0') * 8)
# Contents of file foo are "abc"
MDFile('foo')
# I don't wanna use getopt(), since I want to use the same i/f...
def main():
if len(argv) == 1:
MDFilter()
for arg in argv[1:]:
if arg[:2] == '-s':
MDString(arg[2:])
elif arg == '-t':
MDTimeTrial()
elif arg == '-x':
MDTestSuite()
else:
MDFile(arg)
main()

View File

@ -1,6 +0,0 @@
Demo/parser
Doc/libparser.tex
Lib/AST.py
Lib/symbol.py
Lib/token.py
Modules/parsermodule.c

View File

@ -1,31 +0,0 @@
These files are from the large example of using the `parser' module. Refer
to the Python Library Reference for more information.
It also contains examples for the AST parser.
Files:
------
FILES -- list of files associated with the parser module.
README -- this file.
example.py -- module that uses the `parser' module to extract
information from the parse tree of Python source
code.
docstring.py -- sample source file containing only a module docstring.
simple.py -- sample source containing a "short form" definition.
source.py -- sample source code used to demonstrate ability to
handle nested constructs easily using the functions
and classes in example.py.
test_parser.py program to put the parser module through its paces.
unparse.py AST (2.5) based example to recreate source code
from an AST. This is incomplete; contributions
are welcome.
Enjoy!

View File

@ -1,2 +0,0 @@
"""Some documentation.
"""

View File

@ -1,190 +0,0 @@
"""Simple code to extract class & function docstrings from a module.
This code is used as an example in the library reference manual in the
section on using the parser module. Refer to the manual for a thorough
discussion of the operation of this code.
"""
import os
import parser
import symbol
import token
import types
from types import ListType, TupleType
def get_docs(fileName):
"""Retrieve information from the parse tree of a source file.
fileName
Name of the file to read Python source code from.
"""
source = open(fileName).read()
basename = os.path.basename(os.path.splitext(fileName)[0])
ast = parser.suite(source)
return ModuleInfo(ast.totuple(), basename)
class SuiteInfoBase:
_docstring = ''
_name = ''
def __init__(self, tree = None):
self._class_info = {}
self._function_info = {}
if tree:
self._extract_info(tree)
def _extract_info(self, tree):
# extract docstring
if len(tree) == 2:
found, vars = match(DOCSTRING_STMT_PATTERN[1], tree[1])
else:
found, vars = match(DOCSTRING_STMT_PATTERN, tree[3])
if found:
self._docstring = eval(vars['docstring'])
# discover inner definitions
for node in tree[1:]:
found, vars = match(COMPOUND_STMT_PATTERN, node)
if found:
cstmt = vars['compound']
if cstmt[0] == symbol.funcdef:
name = cstmt[2][1]
self._function_info[name] = FunctionInfo(cstmt)
elif cstmt[0] == symbol.classdef:
name = cstmt[2][1]
self._class_info[name] = ClassInfo(cstmt)
def get_docstring(self):
return self._docstring
def get_name(self):
return self._name
def get_class_names(self):
return list(self._class_info.keys())
def get_class_info(self, name):
return self._class_info[name]
def __getitem__(self, name):
try:
return self._class_info[name]
except KeyError:
return self._function_info[name]
class SuiteFuncInfo:
# Mixin class providing access to function names and info.
def get_function_names(self):
return list(self._function_info.keys())
def get_function_info(self, name):
return self._function_info[name]
class FunctionInfo(SuiteInfoBase, SuiteFuncInfo):
def __init__(self, tree = None):
self._name = tree[2][1]
SuiteInfoBase.__init__(self, tree and tree[-1] or None)
class ClassInfo(SuiteInfoBase):
def __init__(self, tree = None):
self._name = tree[2][1]
SuiteInfoBase.__init__(self, tree and tree[-1] or None)
def get_method_names(self):
return list(self._function_info.keys())
def get_method_info(self, name):
return self._function_info[name]
class ModuleInfo(SuiteInfoBase, SuiteFuncInfo):
def __init__(self, tree = None, name = "<string>"):
self._name = name
SuiteInfoBase.__init__(self, tree)
if tree:
found, vars = match(DOCSTRING_STMT_PATTERN, tree[1])
if found:
self._docstring = vars["docstring"]
def match(pattern, data, vars=None):
"""Match `data' to `pattern', with variable extraction.
pattern
Pattern to match against, possibly containing variables.
data
Data to be checked and against which variables are extracted.
vars
Dictionary of variables which have already been found. If not
provided, an empty dictionary is created.
The `pattern' value may contain variables of the form ['varname'] which
are allowed to match anything. The value that is matched is returned as
part of a dictionary which maps 'varname' to the matched value. 'varname'
is not required to be a string object, but using strings makes patterns
and the code which uses them more readable.
This function returns two values: a boolean indicating whether a match
was found and a dictionary mapping variable names to their associated
values.
"""
if vars is None:
vars = {}
if type(pattern) is ListType: # 'variables' are ['varname']
vars[pattern[0]] = data
return 1, vars
if type(pattern) is not TupleType:
return (pattern == data), vars
if len(data) != len(pattern):
return 0, vars
for pattern, data in map(None, pattern, data):
same, vars = match(pattern, data, vars)
if not same:
break
return same, vars
# This pattern identifies compound statements, allowing them to be readily
# differentiated from simple statements.
#
COMPOUND_STMT_PATTERN = (
symbol.stmt,
(symbol.compound_stmt, ['compound'])
)
# This pattern will match a 'stmt' node which *might* represent a docstring;
# docstrings require that the statement which provides the docstring be the
# first statement in the class or function, which this pattern does not check.
#
DOCSTRING_STMT_PATTERN = (
symbol.stmt,
(symbol.simple_stmt,
(symbol.small_stmt,
(symbol.expr_stmt,
(symbol.testlist,
(symbol.test,
(symbol.and_test,
(symbol.not_test,
(symbol.comparison,
(symbol.expr,
(symbol.xor_expr,
(symbol.and_expr,
(symbol.shift_expr,
(symbol.arith_expr,
(symbol.term,
(symbol.factor,
(symbol.power,
(symbol.atom,
(token.STRING, ['docstring'])
)))))))))))))))),
(token.NEWLINE, '')
))

View File

@ -1 +0,0 @@
def f(): "maybe a docstring"

View File

@ -1,27 +0,0 @@
"""Exmaple file to be parsed for the parsermodule example.
The classes and functions in this module exist only to exhibit the ability
of the handling information extraction from nested definitions using parse
trees. They shouldn't interest you otherwise!
"""
class Simple:
"This class does very little."
def method(self):
"This method does almost nothing."
return 1
class Nested:
"This is a nested class."
def nested_method(self):
"Method of Nested class."
def nested_function():
"Function in method of Nested class."
pass
return nested_function
def function():
"This function lives at the module level."
return 0

View File

@ -1,48 +0,0 @@
#! /usr/bin/env python3
# (Force the script to use the latest build.)
#
# test_parser.py
import parser, traceback
_numFailed = 0
def testChunk(t, fileName):
global _numFailed
print('----', fileName, end=' ')
try:
st = parser.suite(t)
tup = parser.st2tuple(st)
# this discards the first ST; a huge memory savings when running
# against a large source file like Tkinter.py.
st = None
new = parser.tuple2st(tup)
except parser.ParserError as err:
print()
print('parser module raised exception on input file', fileName + ':')
traceback.print_exc()
_numFailed = _numFailed + 1
else:
if tup != parser.st2tuple(new):
print()
print('parser module failed on input file', fileName)
_numFailed = _numFailed + 1
else:
print('o.k.')
def testFile(fileName):
t = open(fileName).read()
testChunk(t, fileName)
def test():
import sys
args = sys.argv[1:]
if not args:
import glob
args = glob.glob("*.py")
args.sort()
list(map(testFile, args))
sys.exit(_numFailed != 0)
if __name__ == '__main__':
test()

View File

@ -1,100 +0,0 @@
\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename parser.info
@settitle Python Parser Module Reference
@setchapternewpage odd
@footnotestyle end
@c %**end of header
@ifinfo
This file describes the interfaces
published by the optional @code{parser} module and gives examples of
how they may be used. It contains the same text as the chapter on the
@code{parser} module in the @cite{Python Library Reference}, but is
presented as a separate document.
Copyright 1995-1996 by Fred L. Drake, Jr., Reston, Virginia, USA, and
Virginia Polytechnic Institute and State University, Blacksburg,
Virginia, USA. Portions of the software copyright 1991-1995 by
Stichting Mathematisch Centrum, Amsterdam, The Netherlands. Copying is
permitted under the terms associated with the main Python distribution,
with the additional restriction that this additional notice be included
and maintained on all distributed copies.
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 Fred L. Drake, Jr. and
Virginia Polytechnic Institute and State University not be used in
advertising or publicity pertaining to distribution of the software
without specific, written prior permission.
FRED L. DRAKE, JR. AND VIRGINIA POLYTECHNIC INSTITUTE AND STATE
UNIVERSITY DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
EVENT SHALL FRED L. DRAKE, JR. OR VIRGINIA POLYTECHNIC INSTITUTE AND
STATE UNIVERSITY 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.
@end ifinfo
@titlepage
@title Python Parser Module Reference
@author Fred L. Drake, Jr.
@c The following two commands start the copyright page.
@page
@vskip 0pt plus 1filll
Copyright 1995-1996 by Fred L. Drake, Jr., Reston, Virginia, USA, and
Virginia Polytechnic Institute and State University, Blacksburg,
Virginia, USA. Portions of the software copyright 1991-1995 by
Stichting Mathematisch Centrum, Amsterdam, The Netherlands. Copying is
permitted under the terms associated with the main Python distribution,
with the additional restriction that this additional notice be included
and maintained on all distributed copies.
@center 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 Fred L. Drake, Jr. and
Virginia Polytechnic Institute and State University not be used in
advertising or publicity pertaining to distribution of the software
without specific, written prior permission.
FRED L. DRAKE, JR. AND VIRGINIA POLYTECHNIC INSTITUTE AND STATE
UNIVERSITY DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
EVENT SHALL FRED L. DRAKE, JR. OR VIRGINIA POLYTECHNIC INSTITUTE AND
STATE UNIVERSITY 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.
@end titlepage
@node Top, Overview, (dir), (dir)
@top The Python Parser Module
@ifinfo
This file describes the interfaces
published by the optional @code{parser} module and gives examples of
how they may be used. It contains the same text as the chapter on the
@code{parser} module in the @cite{Python Library Reference}, but is
presented as a separate document.
This version corresponds to Python version 1.4 (1 Sept. 1996).
@end ifinfo
@c placeholder for the master menu -- patched by texinfo-all-menus-update
@menu
@end menu

View File

@ -1,57 +0,0 @@
# Makefile for 'pysvr' application embedding Python.
# Tailored for Python 1.5a3 or later.
# Some details are specific for Solaris or CNRI.
# Also see ## comments for tailoring.
# Which C compiler
CC=gcc
##PURIFY=/usr/local/pure/purify
LINKCC=$(PURIFY) $(CC)
# Optimization preferences
OPT=-g
# Which Python version we're using
VER=2.2
# Expressions using the above definitions
PYVER=python$(VER)
# Use these defs when compiling against installed Python
##INST=/usr/local
##PYC=$(INST)/lib/$(PYVER)/config
##PYINCL=-I$(INST)/include/$(PYVER) -I$(PYC)
##PYLIBS=$(PYC)/lib$(PYVER).a
# Use these defs when compiling against built Python
PLAT=linux
PYINCL=-I../../Include -I../../$(PLAT)
PYLIBS=../../$(PLAT)/lib$(PYVER).a
# Libraries to link with -- very installation dependent
# (See LIBS= in Modules/Makefile in build tree)
RLLIBS=-lreadline -ltermcap
OTHERLIBS=-lnsl -lpthread -ldl -lm -ldb -lutil
# Compilation and link flags -- no need to change normally
CFLAGS=$(OPT)
CPPFLAGS=$(PYINCL)
LIBS=$(PYLIBS) $(RLLIBS) $(OTHERLIBS)
# Default port for the pysvr application
PORT=4000
# Default target
all: pysvr
# Target to build pysvr
pysvr: pysvr.o $(PYOBJS) $(PYLIBS)
$(LINKCC) pysvr.o $(LIBS) -o pysvr
# Target to build and run pysvr
run: pysvr
pysvr $(PORT)
# Target to clean up the directory
clean:
-rm -f pysvr *.o *~ core

View File

@ -1,9 +0,0 @@
This is an example of a multi-threaded C application embedding a
Python interpreter.
The particular application is a multi-threaded telnet-like server that
provides you with a Python prompt (instead of a shell prompt).
The file pysvr.py is a prototype in Python.
THIS APPLICATION IS NOT SECURE -- ONLY USE IT FOR TESTING!

View File

@ -1,370 +0,0 @@
/* A multi-threaded telnet-like server that gives a Python prompt.
Usage: pysvr [port]
For security reasons, it only accepts requests from the current host.
This can still be insecure, but restricts violations from people who
can log in on your machine. Use with caution!
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <getopt.h>
/* XXX Umpfh.
Python.h defines a typedef destructor, which conflicts with pthread.h.
So Python.h must be included after pthread.h. */
#include "Python.h"
extern int Py_VerboseFlag;
#ifndef PORT
#define PORT 4000
#endif
struct workorder {
int conn;
struct sockaddr_in addr;
};
/* Forward */
static void init_python(void);
static void usage(void);
static void oprogname(void);
static void main_thread(int);
static void create_thread(int, struct sockaddr_in *);
static void *service_thread(struct workorder *);
static void run_interpreter(FILE *, FILE *);
static int run_command(char *, PyObject *);
static void ps(void);
static char *progname = "pysvr";
static PyThreadState *gtstate;
main(int argc, char **argv)
{
int port = PORT;
int c;
if (argc > 0 && argv[0] != NULL && argv[0][0] != '\0')
progname = argv[0];
while ((c = getopt(argc, argv, "v")) != EOF) {
switch (c) {
case 'v':
Py_VerboseFlag++;
break;
default:
usage();
}
}
if (optind < argc) {
if (optind+1 < argc) {
oprogname();
fprintf(stderr, "too many arguments\n");
usage();
}
port = atoi(argv[optind]);
if (port <= 0) {
fprintf(stderr, "bad port (%s)\n", argv[optind]);
usage();
}
}
main_thread(port);
fprintf(stderr, "Bye.\n");
exit(0);
}
static char usage_line[] = "usage: %s [port]\n";
static void
usage(void)
{
fprintf(stderr, usage_line, progname);
exit(2);
}
static void
main_thread(int port)
{
int sock, conn, size, i;
struct sockaddr_in addr, clientaddr;
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock < 0) {
oprogname();
perror("can't create socket");
exit(1);
}
#ifdef SO_REUSEADDR
i = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &i, sizeof i);
#endif
memset((char *)&addr, '\0', sizeof addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = 0L;
if (bind(sock, (struct sockaddr *)&addr, sizeof addr) < 0) {
oprogname();
perror("can't bind socket to address");
exit(1);
}
if (listen(sock, 5) < 0) {
oprogname();
perror("can't listen on socket");
exit(1);
}
fprintf(stderr, "Listening on port %d...\n", port);
for (i = 0; ; i++) {
size = sizeof clientaddr;
memset((char *) &clientaddr, '\0', size);
conn = accept(sock, (struct sockaddr *) &clientaddr, &size);
if (conn < 0) {
oprogname();
perror("can't accept connection from socket");
exit(1);
}
size = sizeof addr;
memset((char *) &addr, '\0', size);
if (getsockname(conn, (struct sockaddr *)&addr, &size) < 0) {
oprogname();
perror("can't get socket name of connection");
exit(1);
}
if (clientaddr.sin_addr.s_addr != addr.sin_addr.s_addr) {
oprogname();
perror("connection from non-local host refused");
fprintf(stderr, "(addr=%lx, clientaddr=%lx)\n",
ntohl(addr.sin_addr.s_addr),
ntohl(clientaddr.sin_addr.s_addr));
close(conn);
continue;
}
if (i == 4) {
close(conn);
break;
}
create_thread(conn, &clientaddr);
}
close(sock);
if (gtstate) {
PyEval_AcquireThread(gtstate);
gtstate = NULL;
Py_Finalize();
/* And a second time, just because we can. */
Py_Finalize(); /* This should be harmless. */
}
exit(0);
}
static void
create_thread(int conn, struct sockaddr_in *addr)
{
struct workorder *work;
pthread_t tdata;
work = malloc(sizeof(struct workorder));
if (work == NULL) {
oprogname();
fprintf(stderr, "out of memory for thread.\n");
close(conn);
return;
}
work->conn = conn;
work->addr = *addr;
init_python();
if (pthread_create(&tdata, NULL, (void *)service_thread, work) < 0) {
oprogname();
perror("can't create new thread");
close(conn);
return;
}
if (pthread_detach(tdata) < 0) {
oprogname();
perror("can't detach from thread");
}
}
static PyThreadState *the_tstate;
static PyInterpreterState *the_interp;
static PyObject *the_builtins;
static void
init_python(void)
{
if (gtstate)
return;
Py_Initialize(); /* Initialize the interpreter */
PyEval_InitThreads(); /* Create (and acquire) the interpreter lock */
gtstate = PyEval_SaveThread(); /* Release the thread state */
}
static void *
service_thread(struct workorder *work)
{
FILE *input, *output;
fprintf(stderr, "Start thread for connection %d.\n", work->conn);
ps();
input = fdopen(work->conn, "r");
if (input == NULL) {
oprogname();
perror("can't create input stream");
goto done;
}
output = fdopen(work->conn, "w");
if (output == NULL) {
oprogname();
perror("can't create output stream");
fclose(input);
goto done;
}
setvbuf(input, NULL, _IONBF, 0);
setvbuf(output, NULL, _IONBF, 0);
run_interpreter(input, output);
fclose(input);
fclose(output);
done:
fprintf(stderr, "End thread for connection %d.\n", work->conn);
close(work->conn);
free(work);
}
static void
oprogname(void)
{
int save = errno;
fprintf(stderr, "%s: ", progname);
errno = save;
}
static void
run_interpreter(FILE *input, FILE *output)
{
PyThreadState *tstate;
PyObject *new_stdin, *new_stdout;
PyObject *mainmod, *globals;
char buffer[1000];
char *p, *q;
int n, end;
PyEval_AcquireLock();
tstate = Py_NewInterpreter();
if (tstate == NULL) {
fprintf(output, "Sorry -- can't create an interpreter\n");
return;
}
mainmod = PyImport_AddModule("__main__");
globals = PyModule_GetDict(mainmod);
Py_INCREF(globals);
new_stdin = PyFile_FromFile(input, "<socket-in>", "r", NULL);
new_stdout = PyFile_FromFile(output, "<socket-out>", "w", NULL);
PySys_SetObject("stdin", new_stdin);
PySys_SetObject("stdout", new_stdout);
PySys_SetObject("stderr", new_stdout);
for (n = 1; !PyErr_Occurred(); n++) {
Py_BEGIN_ALLOW_THREADS
fprintf(output, "%d> ", n);
p = fgets(buffer, sizeof buffer, input);
Py_END_ALLOW_THREADS
if (p == NULL)
break;
if (p[0] == '\377' && p[1] == '\354')
break;
q = strrchr(p, '\r');
if (q && q[1] == '\n' && q[2] == '\0') {
*q++ = '\n';
*q++ = '\0';
}
while (*p && isspace(*p))
p++;
if (p[0] == '#' || p[0] == '\0')
continue;
end = run_command(buffer, globals);
if (end < 0)
PyErr_Print();
if (end)
break;
}
Py_XDECREF(globals);
Py_XDECREF(new_stdin);
Py_XDECREF(new_stdout);
Py_EndInterpreter(tstate);
PyEval_ReleaseLock();
fprintf(output, "Goodbye!\n");
}
static int
run_command(char *buffer, PyObject *globals)
{
PyObject *m, *d, *v;
fprintf(stderr, "run_command: %s", buffer);
if (strchr(buffer, '\n') == NULL)
fprintf(stderr, "\n");
v = PyRun_String(buffer, Py_single_input, globals, globals);
if (v == NULL) {
if (PyErr_Occurred() == PyExc_SystemExit) {
PyErr_Clear();
return 1;
}
PyErr_Print();
return 0;
}
Py_DECREF(v);
return 0;
}
static void
ps(void)
{
char buffer[100];
PyOS_snprintf(buffer, sizeof(buffer),
"ps -l -p %d </dev/null | sed 1d\n", getpid());
system(buffer);
}

View File

@ -1,124 +0,0 @@
#! /usr/bin/env python3
"""A multi-threaded telnet-like server that gives a Python prompt.
This is really a prototype for the same thing in C.
Usage: pysvr.py [port]
For security reasons, it only accepts requests from the current host.
This can still be insecure, but restricts violations from people who
can log in on your machine. Use with caution!
"""
import sys, os, string, getopt, _thread, socket, traceback
PORT = 4000 # Default port
def main():
try:
opts, args = getopt.getopt(sys.argv[1:], "")
if len(args) > 1:
raise getopt.error("Too many arguments.")
except getopt.error as msg:
usage(msg)
for o, a in opts:
pass
if args:
try:
port = string.atoi(args[0])
except ValueError as msg:
usage(msg)
else:
port = PORT
main_thread(port)
def usage(msg=None):
sys.stdout = sys.stderr
if msg:
print(msg)
print("\n", __doc__, end=' ')
sys.exit(2)
def main_thread(port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("", port))
sock.listen(5)
print("Listening on port", port, "...")
while 1:
(conn, addr) = sock.accept()
if addr[0] != conn.getsockname()[0]:
conn.close()
print("Refusing connection from non-local host", addr[0], ".")
continue
_thread.start_new_thread(service_thread, (conn, addr))
del conn, addr
def service_thread(conn, addr):
(caddr, cport) = addr
print("Thread %s has connection from %s.\n" % (str(_thread.get_ident()),
caddr), end=' ')
stdin = conn.makefile("r")
stdout = conn.makefile("w", 0)
run_interpreter(stdin, stdout)
print("Thread %s is done.\n" % str(_thread.get_ident()), end=' ')
def run_interpreter(stdin, stdout):
globals = {}
try:
str(sys.ps1)
except:
sys.ps1 = ">>> "
source = ""
while 1:
stdout.write(sys.ps1)
line = stdin.readline()
if line[:2] == '\377\354':
line = ""
if not line and not source:
break
if line[-2:] == '\r\n':
line = line[:-2] + '\n'
source = source + line
try:
code = compile_command(source)
except SyntaxError as err:
source = ""
traceback.print_exception(SyntaxError, err, None, file=stdout)
continue
if not code:
continue
source = ""
try:
run_command(code, stdin, stdout, globals)
except SystemExit as how:
if how:
try:
how = str(how)
except:
how = ""
stdout.write("Exit %s\n" % how)
break
stdout.write("\nGoodbye.\n")
def run_command(code, stdin, stdout, globals):
save = sys.stdin, sys.stdout, sys.stderr
try:
sys.stdout = sys.stderr = stdout
sys.stdin = stdin
try:
exec(code, globals)
except SystemExit as how:
raise SystemExit(how).with_traceback(sys.exc_info()[2])
except:
type, value, tb = sys.exc_info()
if tb: tb = tb.tb_next
traceback.print_exception(type, value, tb)
del tb
finally:
sys.stdin, sys.stdout, sys.stderr = save
from code import compile_command
main()

View File

@ -1,10 +0,0 @@
File Name Archive # Description
-----------------------------------------------------------
MANIFEST 1 This shipping list
README 1
T.py 1
mountclient.py 1
nfsclient.py 1
rpc.py 1
test 1
xdr.py 1

View File

@ -1,31 +0,0 @@
This is a Python interface to Sun RPC, designed and implemented mostly
by reading the Internet RFCs about the subject.
*** NOTE: xdr.py has evolved into the standard module xdrlib.py ***
There are two library modules, xdr.py and rpc.py, and several example
clients: mountclient.py, nfsclient.py, and rnusersclient.py,
implementing the NFS Mount protocol, (part of) the NFS protocol, and
the "rnusers" protocol (used by rusers(1)), respectively. The latter
demonstrates the use of broadcast via the Port mapper's CALLIT
procedure.
There is also a way to create servers in Python.
To test the nfs client, run it from the shell with something like this:
python -c 'import nfsclient; nfsclient.test()' [hostname [filesystemname]]
When called without a filesystemname, it lists the filesystems at the
host; default host is the local machine.
Other clients are tested similarly.
For hostname, use e.g. wuarchive.wustl.edu or gatekeeper.dec.com (two
hosts that are known to export NFS filesystems with little restrictions).
There are now two different RPC compilers:
1) Wim Lewis rpcgen.py found on http://www.omnigroup.com/~wiml/soft/stale-index.html#python.
2) Peter Åstrands rpcgen.py, which is part of "pynfs" (http://www.cendio.se/~peter/pynfs/).

View File

@ -1,22 +0,0 @@
# Simple interface to report execution times of program fragments.
# Call TSTART() to reset the timer, TSTOP(...) to report times.
import sys, os, time
def TSTART():
global t0, t1
u, s, cu, cs = os.times()
t0 = u+cu, s+cs, time.time()
def TSTOP(*label):
global t0, t1
u, s, cu, cs = os.times()
t1 = u+cu, s+cs, time.time()
tt = []
for i in range(3):
tt.append(t1[i] - t0[i])
[u, s, r] = tt
msg = ''
for x in label: msg = msg + (x + ' ')
msg = msg + '%r user, %r sys, %r real\n' % (u, s, r)
sys.stderr.write(msg)

View File

@ -1,202 +0,0 @@
# Mount RPC client -- RFC 1094 (NFS), Appendix A
# This module demonstrates how to write your own RPC client in Python.
# When this example was written, there was no RPC compiler for
# Python. Without such a compiler, you must first create classes
# derived from Packer and Unpacker to handle the data types for the
# server you want to interface to. You then write the client class.
# If you want to support both the TCP and the UDP version of a
# protocol, use multiple inheritance as shown below.
import rpc
from rpc import Packer, Unpacker, TCPClient, UDPClient
# Program number and version for the mount protocol
MOUNTPROG = 100005
MOUNTVERS = 1
# Size of the 'fhandle' opaque structure
FHSIZE = 32
# Packer derived class for Mount protocol clients.
# The only thing we need to pack beyond basic types is an 'fhandle'
class MountPacker(Packer):
def pack_fhandle(self, fhandle):
self.pack_fopaque(FHSIZE, fhandle)
# Unpacker derived class for Mount protocol clients.
# The important types we need to unpack are fhandle, fhstatus,
# mountlist and exportlist; mountstruct, exportstruct and groups are
# used to unpack components of mountlist and exportlist and the
# corresponding functions are passed as function argument to the
# generic unpack_list function.
class MountUnpacker(Unpacker):
def unpack_fhandle(self):
return self.unpack_fopaque(FHSIZE)
def unpack_fhstatus(self):
status = self.unpack_uint()
if status == 0:
fh = self.unpack_fhandle()
else:
fh = None
return status, fh
def unpack_mountlist(self):
return self.unpack_list(self.unpack_mountstruct)
def unpack_mountstruct(self):
hostname = self.unpack_string()
directory = self.unpack_string()
return (hostname, directory)
def unpack_exportlist(self):
return self.unpack_list(self.unpack_exportstruct)
def unpack_exportstruct(self):
filesys = self.unpack_string()
groups = self.unpack_groups()
return (filesys, groups)
def unpack_groups(self):
return self.unpack_list(self.unpack_string)
# These are the procedures specific to the Mount client class.
# Think of this as a derived class of either TCPClient or UDPClient.
class PartialMountClient:
# This method is called by Client.__init__ to initialize
# self.packer and self.unpacker
def addpackers(self):
self.packer = MountPacker()
self.unpacker = MountUnpacker('')
# This method is called by Client.__init__ to bind the socket
# to a particular network interface and port. We use the
# default network interface, but if we're running as root,
# we want to bind to a reserved port
def bindsocket(self):
import os
try:
uid = os.getuid()
except AttributeError:
uid = 1
if uid == 0:
port = rpc.bindresvport(self.sock, '')
# 'port' is not used
else:
self.sock.bind(('', 0))
# This function is called to cough up a suitable
# authentication object for a call to procedure 'proc'.
def mkcred(self):
if self.cred is None:
self.cred = rpc.AUTH_UNIX, rpc.make_auth_unix_default()
return self.cred
# The methods Mnt, Dump etc. each implement one Remote
# Procedure Call. This is done by calling self.make_call()
# with as arguments:
#
# - the procedure number
# - the arguments (or None)
# - the "packer" function for the arguments (or None)
# - the "unpacker" function for the return value (or None)
#
# The packer and unpacker function, if not None, *must* be
# methods of self.packer and self.unpacker, respectively.
# A value of None means that there are no arguments or is no
# return value, respectively.
#
# The return value from make_call() is the return value from
# the remote procedure call, as unpacked by the "unpacker"
# function, or None if the unpacker function is None.
#
# (Even if you expect a result of None, you should still
# return the return value from make_call(), since this may be
# needed by a broadcasting version of the class.)
#
# If the call fails, make_call() raises an exception
# (this includes time-outs and invalid results).
#
# Note that (at least with the UDP protocol) there is no
# guarantee that a call is executed at most once. When you do
# get a reply, you know it has been executed at least once;
# when you don't get a reply, you know nothing.
def Mnt(self, directory):
return self.make_call(1, directory, \
self.packer.pack_string, \
self.unpacker.unpack_fhstatus)
def Dump(self):
return self.make_call(2, None, \
None, self.unpacker.unpack_mountlist)
def Umnt(self, directory):
return self.make_call(3, directory, \
self.packer.pack_string, None)
def Umntall(self):
return self.make_call(4, None, None, None)
def Export(self):
return self.make_call(5, None, \
None, self.unpacker.unpack_exportlist)
# We turn the partial Mount client into a full one for either protocol
# by use of multiple inheritance. (In general, when class C has base
# classes B1...Bn, if x is an instance of class C, methods of x are
# searched first in C, then in B1, then in B2, ..., finally in Bn.)
class TCPMountClient(PartialMountClient, TCPClient):
def __init__(self, host):
TCPClient.__init__(self, host, MOUNTPROG, MOUNTVERS)
class UDPMountClient(PartialMountClient, UDPClient):
def __init__(self, host):
UDPClient.__init__(self, host, MOUNTPROG, MOUNTVERS)
# A little test program for the Mount client. This takes a host as
# command line argument (default the local machine), prints its export
# list, and attempts to mount and unmount each exported files system.
# An optional first argument of -t or -u specifies the protocol to use
# (TCP or UDP), default is UDP.
def test():
import sys
if sys.argv[1:] and sys.argv[1] == '-t':
C = TCPMountClient
del sys.argv[1]
elif sys.argv[1:] and sys.argv[1] == '-u':
C = UDPMountClient
del sys.argv[1]
else:
C = UDPMountClient
if sys.argv[1:]: host = sys.argv[1]
else: host = ''
mcl = C(host)
list = mcl.Export()
for item in list:
print(item)
try:
mcl.Mnt(item[0])
except:
print('Sorry')
continue
mcl.Umnt(item[0])

View File

@ -1,201 +0,0 @@
# NFS RPC client -- RFC 1094
# XXX This is not yet complete.
# XXX Only GETATTR, SETTTR, LOOKUP and READDIR are supported.
# (See mountclient.py for some hints on how to write RPC clients in
# Python in general)
import rpc
from rpc import UDPClient, TCPClient
from mountclient import FHSIZE, MountPacker, MountUnpacker
NFS_PROGRAM = 100003
NFS_VERSION = 2
# enum stat
NFS_OK = 0
# (...many error values...)
# enum ftype
NFNON = 0
NFREG = 1
NFDIR = 2
NFBLK = 3
NFCHR = 4
NFLNK = 5
class NFSPacker(MountPacker):
def pack_sattrargs(self, sa):
file, attributes = sa
self.pack_fhandle(file)
self.pack_sattr(attributes)
def pack_sattr(self, sa):
mode, uid, gid, size, atime, mtime = sa
self.pack_uint(mode)
self.pack_uint(uid)
self.pack_uint(gid)
self.pack_uint(size)
self.pack_timeval(atime)
self.pack_timeval(mtime)
def pack_diropargs(self, da):
dir, name = da
self.pack_fhandle(dir)
self.pack_string(name)
def pack_readdirargs(self, ra):
dir, cookie, count = ra
self.pack_fhandle(dir)
self.pack_uint(cookie)
self.pack_uint(count)
def pack_timeval(self, tv):
secs, usecs = tv
self.pack_uint(secs)
self.pack_uint(usecs)
class NFSUnpacker(MountUnpacker):
def unpack_readdirres(self):
status = self.unpack_enum()
if status == NFS_OK:
entries = self.unpack_list(self.unpack_entry)
eof = self.unpack_bool()
rest = (entries, eof)
else:
rest = None
return (status, rest)
def unpack_entry(self):
fileid = self.unpack_uint()
name = self.unpack_string()
cookie = self.unpack_uint()
return (fileid, name, cookie)
def unpack_diropres(self):
status = self.unpack_enum()
if status == NFS_OK:
fh = self.unpack_fhandle()
fa = self.unpack_fattr()
rest = (fh, fa)
else:
rest = None
return (status, rest)
def unpack_attrstat(self):
status = self.unpack_enum()
if status == NFS_OK:
attributes = self.unpack_fattr()
else:
attributes = None
return status, attributes
def unpack_fattr(self):
type = self.unpack_enum()
mode = self.unpack_uint()
nlink = self.unpack_uint()
uid = self.unpack_uint()
gid = self.unpack_uint()
size = self.unpack_uint()
blocksize = self.unpack_uint()
rdev = self.unpack_uint()
blocks = self.unpack_uint()
fsid = self.unpack_uint()
fileid = self.unpack_uint()
atime = self.unpack_timeval()
mtime = self.unpack_timeval()
ctime = self.unpack_timeval()
return (type, mode, nlink, uid, gid, size, blocksize, \
rdev, blocks, fsid, fileid, atime, mtime, ctime)
def unpack_timeval(self):
secs = self.unpack_uint()
usecs = self.unpack_uint()
return (secs, usecs)
class NFSClient(UDPClient):
def __init__(self, host):
UDPClient.__init__(self, host, NFS_PROGRAM, NFS_VERSION)
def addpackers(self):
self.packer = NFSPacker()
self.unpacker = NFSUnpacker('')
def mkcred(self):
if self.cred is None:
self.cred = rpc.AUTH_UNIX, rpc.make_auth_unix_default()
return self.cred
def Getattr(self, fh):
return self.make_call(1, fh, \
self.packer.pack_fhandle, \
self.unpacker.unpack_attrstat)
def Setattr(self, sa):
return self.make_call(2, sa, \
self.packer.pack_sattrargs, \
self.unpacker.unpack_attrstat)
# Root() is obsolete
def Lookup(self, da):
return self.make_call(4, da, \
self.packer.pack_diropargs, \
self.unpacker.unpack_diropres)
# ...
def Readdir(self, ra):
return self.make_call(16, ra, \
self.packer.pack_readdirargs, \
self.unpacker.unpack_readdirres)
# Shorthand to get the entire contents of a directory
def Listdir(self, dir):
list = []
ra = (dir, 0, 2000)
while 1:
(status, rest) = self.Readdir(ra)
if status != NFS_OK:
break
entries, eof = rest
last_cookie = None
for fileid, name, cookie in entries:
list.append((fileid, name))
last_cookie = cookie
if eof or last_cookie is None:
break
ra = (ra[0], last_cookie, ra[2])
return list
def test():
import sys
if sys.argv[1:]: host = sys.argv[1]
else: host = ''
if sys.argv[2:]: filesys = sys.argv[2]
else: filesys = None
from mountclient import UDPMountClient, TCPMountClient
mcl = TCPMountClient(host)
if filesys is None:
list = mcl.Export()
for item in list:
print(item)
return
sf = mcl.Mnt(filesys)
print(sf)
fh = sf[1]
if fh:
ncl = NFSClient(host)
attrstat = ncl.Getattr(fh)
print(attrstat)
list = ncl.Listdir(fh)
for item in list: print(item)
mcl.Umnt(filesys)

View File

@ -1,98 +0,0 @@
# Remote nusers client interface
import rpc
from rpc import Packer, Unpacker, UDPClient, BroadcastUDPClient
class RnusersPacker(Packer):
def pack_utmp(self, ui):
ut_line, ut_name, ut_host, ut_time = utmp
self.pack_string(ut_line)
self.pack_string(ut_name)
self.pack_string(ut_host)
self.pack_int(ut_time)
def pack_utmpidle(self, ui):
ui_itmp, ui_idle = ui
self.pack_utmp(ui_utmp)
self.pack_uint(ui_idle)
def pack_utmpidlearr(self, list):
self.pack_array(list, self.pack_itmpidle)
class RnusersUnpacker(Unpacker):
def unpack_utmp(self):
ut_line = self.unpack_string()
ut_name = self.unpack_string()
ut_host = self.unpack_string()
ut_time = self.unpack_int()
return ut_line, ut_name, ut_host, ut_time
def unpack_utmpidle(self):
ui_utmp = self.unpack_utmp()
ui_idle = self.unpack_uint()
return ui_utmp, ui_idle
def unpack_utmpidlearr(self):
return self.unpack_array(self.unpack_utmpidle)
class PartialRnusersClient:
def addpackers(self):
self.packer = RnusersPacker()
self.unpacker = RnusersUnpacker('')
def Num(self):
return self.make_call(1, None, None, self.unpacker.unpack_int)
def Names(self):
return self.make_call(2, None, \
None, self.unpacker.unpack_utmpidlearr)
def Allnames(self):
return self.make_call(3, None, \
None, self.unpacker.unpack_utmpidlearr)
class RnusersClient(PartialRnusersClient, UDPClient):
def __init__(self, host):
UDPClient.__init__(self, host, 100002, 2)
class BroadcastRnusersClient(PartialRnusersClient, BroadcastUDPClient):
def __init__(self, bcastaddr):
BroadcastUDPClient.__init__(self, bcastaddr, 100002, 2)
def test():
import sys
if not sys.argv[1:]:
testbcast()
return
else:
host = sys.argv[1]
c = RnusersClient(host)
list = c.Names()
for (line, name, host, time), idle in list:
line = strip0(line)
name = strip0(name)
host = strip0(host)
print("%r %r %r %s %s" % (name, host, line, time, idle))
def testbcast():
c = BroadcastRnusersClient('<broadcast>')
def listit(list, fromaddr):
host, port = fromaddr
print(host + '\t:', end=' ')
for (line, name, host, time), idle in list:
print(strip0(name), end=' ')
print()
c.set_reply_handler(listit)
all = c.Names()
print('Total Count:', len(all))
def strip0(s):
while s and s[-1] == '\0': s = s[:-1]
return s
test()

View File

@ -1,890 +0,0 @@
# Sun RPC version 2 -- RFC1057.
# XXX There should be separate exceptions for the various reasons why
# XXX an RPC can fail, rather than using RuntimeError for everything
# XXX Need to use class based exceptions rather than string exceptions
# XXX The UDP version of the protocol resends requests when it does
# XXX not receive a timely reply -- use only for idempotent calls!
# XXX There is no provision for call timeout on TCP connections
import xdr
import socket
import os
RPCVERSION = 2
CALL = 0
REPLY = 1
AUTH_NULL = 0
AUTH_UNIX = 1
AUTH_SHORT = 2
AUTH_DES = 3
MSG_ACCEPTED = 0
MSG_DENIED = 1
SUCCESS = 0 # RPC executed successfully
PROG_UNAVAIL = 1 # remote hasn't exported program
PROG_MISMATCH = 2 # remote can't support version #
PROC_UNAVAIL = 3 # program can't support procedure
GARBAGE_ARGS = 4 # procedure can't decode params
RPC_MISMATCH = 0 # RPC version number != 2
AUTH_ERROR = 1 # remote can't authenticate caller
AUTH_BADCRED = 1 # bad credentials (seal broken)
AUTH_REJECTEDCRED = 2 # client must begin new session
AUTH_BADVERF = 3 # bad verifier (seal broken)
AUTH_REJECTEDVERF = 4 # verifier expired or replayed
AUTH_TOOWEAK = 5 # rejected for security reasons
class Packer(xdr.Packer):
def pack_auth(self, auth):
flavor, stuff = auth
self.pack_enum(flavor)
self.pack_opaque(stuff)
def pack_auth_unix(self, stamp, machinename, uid, gid, gids):
self.pack_uint(stamp)
self.pack_string(machinename)
self.pack_uint(uid)
self.pack_uint(gid)
self.pack_uint(len(gids))
for i in gids:
self.pack_uint(i)
def pack_callheader(self, xid, prog, vers, proc, cred, verf):
self.pack_uint(xid)
self.pack_enum(CALL)
self.pack_uint(RPCVERSION)
self.pack_uint(prog)
self.pack_uint(vers)
self.pack_uint(proc)
self.pack_auth(cred)
self.pack_auth(verf)
# Caller must add procedure-specific part of call
def pack_replyheader(self, xid, verf):
self.pack_uint(xid)
self.pack_enum(REPLY)
self.pack_uint(MSG_ACCEPTED)
self.pack_auth(verf)
self.pack_enum(SUCCESS)
# Caller must add procedure-specific part of reply
# Exceptions
class BadRPCFormat(Exception): pass
class BadRPCVersion(Exception): pass
class GarbageArgs(Exception): pass
class Unpacker(xdr.Unpacker):
def unpack_auth(self):
flavor = self.unpack_enum()
stuff = self.unpack_opaque()
return (flavor, stuff)
def unpack_callheader(self):
xid = self.unpack_uint()
temp = self.unpack_enum()
if temp != CALL:
raise BadRPCFormat('no CALL but %r' % (temp,))
temp = self.unpack_uint()
if temp != RPCVERSION:
raise BadRPCVersion('bad RPC version %r' % (temp,))
prog = self.unpack_uint()
vers = self.unpack_uint()
proc = self.unpack_uint()
cred = self.unpack_auth()
verf = self.unpack_auth()
return xid, prog, vers, proc, cred, verf
# Caller must add procedure-specific part of call
def unpack_replyheader(self):
xid = self.unpack_uint()
mtype = self.unpack_enum()
if mtype != REPLY:
raise RuntimeError('no REPLY but %r' % (mtype,))
stat = self.unpack_enum()
if stat == MSG_DENIED:
stat = self.unpack_enum()
if stat == RPC_MISMATCH:
low = self.unpack_uint()
high = self.unpack_uint()
raise RuntimeError('MSG_DENIED: RPC_MISMATCH: %r' % ((low, high),))
if stat == AUTH_ERROR:
stat = self.unpack_uint()
raise RuntimeError('MSG_DENIED: AUTH_ERROR: %r' % (stat,))
raise RuntimeError('MSG_DENIED: %r' % (stat,))
if stat != MSG_ACCEPTED:
raise RuntimeError('Neither MSG_DENIED nor MSG_ACCEPTED: %r' % (stat,))
verf = self.unpack_auth()
stat = self.unpack_enum()
if stat == PROG_UNAVAIL:
raise RuntimeError('call failed: PROG_UNAVAIL')
if stat == PROG_MISMATCH:
low = self.unpack_uint()
high = self.unpack_uint()
raise RuntimeError('call failed: PROG_MISMATCH: %r' % ((low, high),))
if stat == PROC_UNAVAIL:
raise RuntimeError('call failed: PROC_UNAVAIL')
if stat == GARBAGE_ARGS:
raise RuntimeError('call failed: GARBAGE_ARGS')
if stat != SUCCESS:
raise RuntimeError('call failed: %r' % (stat,))
return xid, verf
# Caller must get procedure-specific part of reply
# Subroutines to create opaque authentication objects
def make_auth_null():
return ''
def make_auth_unix(seed, host, uid, gid, groups):
p = Packer()
p.pack_auth_unix(seed, host, uid, gid, groups)
return p.get_buf()
def make_auth_unix_default():
try:
from os import getuid, getgid
uid = getuid()
gid = getgid()
except ImportError:
uid = gid = 0
import time
return make_auth_unix(int(time.time()-unix_epoch()), \
socket.gethostname(), uid, gid, [])
_unix_epoch = -1
def unix_epoch():
"""Very painful calculation of when the Unix Epoch is.
This is defined as the return value of time.time() on Jan 1st,
1970, 00:00:00 GMT.
On a Unix system, this should always return 0.0. On a Mac, the
calculations are needed -- and hard because of integer overflow
and other limitations.
"""
global _unix_epoch
if _unix_epoch >= 0: return _unix_epoch
import time
now = time.time()
localt = time.localtime(now) # (y, m, d, hh, mm, ss, ..., ..., ...)
gmt = time.gmtime(now)
offset = time.mktime(localt) - time.mktime(gmt)
y, m, d, hh, mm, ss = 1970, 1, 1, 0, 0, 0
offset, ss = divmod(ss + offset, 60)
offset, mm = divmod(mm + offset, 60)
offset, hh = divmod(hh + offset, 24)
d = d + offset
_unix_epoch = time.mktime((y, m, d, hh, mm, ss, 0, 0, 0))
print("Unix epoch:", time.ctime(_unix_epoch))
return _unix_epoch
# Common base class for clients
class Client:
def __init__(self, host, prog, vers, port):
self.host = host
self.prog = prog
self.vers = vers
self.port = port
self.makesocket() # Assigns to self.sock
self.bindsocket()
self.connsocket()
self.lastxid = 0 # XXX should be more random?
self.addpackers()
self.cred = None
self.verf = None
def close(self):
self.sock.close()
def makesocket(self):
# This MUST be overridden
raise RuntimeError('makesocket not defined')
def connsocket(self):
# Override this if you don't want/need a connection
self.sock.connect((self.host, self.port))
def bindsocket(self):
# Override this to bind to a different port (e.g. reserved)
self.sock.bind(('', 0))
def addpackers(self):
# Override this to use derived classes from Packer/Unpacker
self.packer = Packer()
self.unpacker = Unpacker('')
def make_call(self, proc, args, pack_func, unpack_func):
# Don't normally override this (but see Broadcast)
if pack_func is None and args is not None:
raise TypeError('non-null args with null pack_func')
self.start_call(proc)
if pack_func:
pack_func(args)
self.do_call()
if unpack_func:
result = unpack_func()
else:
result = None
self.unpacker.done()
return result
def start_call(self, proc):
# Don't override this
self.lastxid = xid = self.lastxid + 1
cred = self.mkcred()
verf = self.mkverf()
p = self.packer
p.reset()
p.pack_callheader(xid, self.prog, self.vers, proc, cred, verf)
def do_call(self):
# This MUST be overridden
raise RuntimeError('do_call not defined')
def mkcred(self):
# Override this to use more powerful credentials
if self.cred is None:
self.cred = (AUTH_NULL, make_auth_null())
return self.cred
def mkverf(self):
# Override this to use a more powerful verifier
if self.verf is None:
self.verf = (AUTH_NULL, make_auth_null())
return self.verf
def call_0(self): # Procedure 0 is always like this
return self.make_call(0, None, None, None)
# Record-Marking standard support
def sendfrag(sock, last, frag):
x = len(frag)
if last: x = x | 0x80000000
header = (chr(int(x>>24 & 0xff)) + chr(int(x>>16 & 0xff)) + \
chr(int(x>>8 & 0xff)) + chr(int(x & 0xff)))
sock.send(header + frag)
def sendrecord(sock, record):
sendfrag(sock, 1, record)
def recvfrag(sock):
header = sock.recv(4)
if len(header) < 4:
raise EOFError
x = int(ord(header[0]))<<24 | ord(header[1])<<16 | \
ord(header[2])<<8 | ord(header[3])
last = ((x & 0x80000000) != 0)
n = int(x & 0x7fffffff)
frag = ''
while n > 0:
buf = sock.recv(n)
if not buf: raise EOFError
n = n - len(buf)
frag = frag + buf
return last, frag
def recvrecord(sock):
record = ''
last = 0
while not last:
last, frag = recvfrag(sock)
record = record + frag
return record
# Try to bind to a reserved port (must be root)
last_resv_port_tried = None
def bindresvport(sock, host):
global last_resv_port_tried
FIRST, LAST = 600, 1024 # Range of ports to try
if last_resv_port_tried is None:
import os
last_resv_port_tried = FIRST + os.getpid() % (LAST-FIRST)
for i in range(last_resv_port_tried, LAST) + \
range(FIRST, last_resv_port_tried):
last_resv_port_tried = i
try:
sock.bind((host, i))
return last_resv_port_tried
except socket.error as e:
(errno, msg) = e
if errno != 114:
raise socket.error(errno, msg)
raise RuntimeError('can\'t assign reserved port')
# Client using TCP to a specific port
class RawTCPClient(Client):
def makesocket(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def do_call(self):
call = self.packer.get_buf()
sendrecord(self.sock, call)
reply = recvrecord(self.sock)
u = self.unpacker
u.reset(reply)
xid, verf = u.unpack_replyheader()
if xid != self.lastxid:
# Can't really happen since this is TCP...
raise RuntimeError('wrong xid in reply %r instead of %r' % (
xid, self.lastxid))
# Client using UDP to a specific port
class RawUDPClient(Client):
def makesocket(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def do_call(self):
call = self.packer.get_buf()
self.sock.send(call)
try:
from select import select
except ImportError:
print('WARNING: select not found, RPC may hang')
select = None
BUFSIZE = 8192 # Max UDP buffer size
timeout = 1
count = 5
while 1:
r, w, x = [self.sock], [], []
if select:
r, w, x = select(r, w, x, timeout)
if self.sock not in r:
count = count - 1
if count < 0: raise RuntimeError('timeout')
if timeout < 25: timeout = timeout *2
## print 'RESEND', timeout, count
self.sock.send(call)
continue
reply = self.sock.recv(BUFSIZE)
u = self.unpacker
u.reset(reply)
xid, verf = u.unpack_replyheader()
if xid != self.lastxid:
## print 'BAD xid'
continue
break
# Client using UDP broadcast to a specific port
class RawBroadcastUDPClient(RawUDPClient):
def __init__(self, bcastaddr, prog, vers, port):
RawUDPClient.__init__(self, bcastaddr, prog, vers, port)
self.reply_handler = None
self.timeout = 30
def connsocket(self):
# Don't connect -- use sendto
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
def set_reply_handler(self, reply_handler):
self.reply_handler = reply_handler
def set_timeout(self, timeout):
self.timeout = timeout # Use None for infinite timeout
def make_call(self, proc, args, pack_func, unpack_func):
if pack_func is None and args is not None:
raise TypeError('non-null args with null pack_func')
self.start_call(proc)
if pack_func:
pack_func(args)
call = self.packer.get_buf()
self.sock.sendto(call, (self.host, self.port))
try:
from select import select
except ImportError:
print('WARNING: select not found, broadcast will hang')
select = None
BUFSIZE = 8192 # Max UDP buffer size (for reply)
replies = []
if unpack_func is None:
def dummy(): pass
unpack_func = dummy
while 1:
r, w, x = [self.sock], [], []
if select:
if self.timeout is None:
r, w, x = select(r, w, x)
else:
r, w, x = select(r, w, x, self.timeout)
if self.sock not in r:
break
reply, fromaddr = self.sock.recvfrom(BUFSIZE)
u = self.unpacker
u.reset(reply)
xid, verf = u.unpack_replyheader()
if xid != self.lastxid:
## print 'BAD xid'
continue
reply = unpack_func()
self.unpacker.done()
replies.append((reply, fromaddr))
if self.reply_handler:
self.reply_handler(reply, fromaddr)
return replies
# Port mapper interface
# Program number, version and (fixed!) port number
PMAP_PROG = 100000
PMAP_VERS = 2
PMAP_PORT = 111
# Procedure numbers
PMAPPROC_NULL = 0 # (void) -> void
PMAPPROC_SET = 1 # (mapping) -> bool
PMAPPROC_UNSET = 2 # (mapping) -> bool
PMAPPROC_GETPORT = 3 # (mapping) -> unsigned int
PMAPPROC_DUMP = 4 # (void) -> pmaplist
PMAPPROC_CALLIT = 5 # (call_args) -> call_result
# A mapping is (prog, vers, prot, port) and prot is one of:
IPPROTO_TCP = 6
IPPROTO_UDP = 17
# A pmaplist is a variable-length list of mappings, as follows:
# either (1, mapping, pmaplist) or (0).
# A call_args is (prog, vers, proc, args) where args is opaque;
# a call_result is (port, res) where res is opaque.
class PortMapperPacker(Packer):
def pack_mapping(self, mapping):
prog, vers, prot, port = mapping
self.pack_uint(prog)
self.pack_uint(vers)
self.pack_uint(prot)
self.pack_uint(port)
def pack_pmaplist(self, list):
self.pack_list(list, self.pack_mapping)
def pack_call_args(self, ca):
prog, vers, proc, args = ca
self.pack_uint(prog)
self.pack_uint(vers)
self.pack_uint(proc)
self.pack_opaque(args)
class PortMapperUnpacker(Unpacker):
def unpack_mapping(self):
prog = self.unpack_uint()
vers = self.unpack_uint()
prot = self.unpack_uint()
port = self.unpack_uint()
return prog, vers, prot, port
def unpack_pmaplist(self):
return self.unpack_list(self.unpack_mapping)
def unpack_call_result(self):
port = self.unpack_uint()
res = self.unpack_opaque()
return port, res
class PartialPortMapperClient:
def addpackers(self):
self.packer = PortMapperPacker()
self.unpacker = PortMapperUnpacker('')
def Set(self, mapping):
return self.make_call(PMAPPROC_SET, mapping, \
self.packer.pack_mapping, \
self.unpacker.unpack_uint)
def Unset(self, mapping):
return self.make_call(PMAPPROC_UNSET, mapping, \
self.packer.pack_mapping, \
self.unpacker.unpack_uint)
def Getport(self, mapping):
return self.make_call(PMAPPROC_GETPORT, mapping, \
self.packer.pack_mapping, \
self.unpacker.unpack_uint)
def Dump(self):
return self.make_call(PMAPPROC_DUMP, None, \
None, \
self.unpacker.unpack_pmaplist)
def Callit(self, ca):
return self.make_call(PMAPPROC_CALLIT, ca, \
self.packer.pack_call_args, \
self.unpacker.unpack_call_result)
class TCPPortMapperClient(PartialPortMapperClient, RawTCPClient):
def __init__(self, host):
RawTCPClient.__init__(self, \
host, PMAP_PROG, PMAP_VERS, PMAP_PORT)
class UDPPortMapperClient(PartialPortMapperClient, RawUDPClient):
def __init__(self, host):
RawUDPClient.__init__(self, \
host, PMAP_PROG, PMAP_VERS, PMAP_PORT)
class BroadcastUDPPortMapperClient(PartialPortMapperClient, \
RawBroadcastUDPClient):
def __init__(self, bcastaddr):
RawBroadcastUDPClient.__init__(self, \
bcastaddr, PMAP_PROG, PMAP_VERS, PMAP_PORT)
# Generic clients that find their server through the Port mapper
class TCPClient(RawTCPClient):
def __init__(self, host, prog, vers):
pmap = TCPPortMapperClient(host)
port = pmap.Getport((prog, vers, IPPROTO_TCP, 0))
pmap.close()
if port == 0:
raise RuntimeError('program not registered')
RawTCPClient.__init__(self, host, prog, vers, port)
class UDPClient(RawUDPClient):
def __init__(self, host, prog, vers):
pmap = UDPPortMapperClient(host)
port = pmap.Getport((prog, vers, IPPROTO_UDP, 0))
pmap.close()
if port == 0:
raise RuntimeError('program not registered')
RawUDPClient.__init__(self, host, prog, vers, port)
class BroadcastUDPClient(Client):
def __init__(self, bcastaddr, prog, vers):
self.pmap = BroadcastUDPPortMapperClient(bcastaddr)
self.pmap.set_reply_handler(self.my_reply_handler)
self.prog = prog
self.vers = vers
self.user_reply_handler = None
self.addpackers()
def close(self):
self.pmap.close()
def set_reply_handler(self, reply_handler):
self.user_reply_handler = reply_handler
def set_timeout(self, timeout):
self.pmap.set_timeout(timeout)
def my_reply_handler(self, reply, fromaddr):
port, res = reply
self.unpacker.reset(res)
result = self.unpack_func()
self.unpacker.done()
self.replies.append((result, fromaddr))
if self.user_reply_handler is not None:
self.user_reply_handler(result, fromaddr)
def make_call(self, proc, args, pack_func, unpack_func):
self.packer.reset()
if pack_func:
pack_func(args)
if unpack_func is None:
def dummy(): pass
self.unpack_func = dummy
else:
self.unpack_func = unpack_func
self.replies = []
packed_args = self.packer.get_buf()
dummy_replies = self.pmap.Callit( \
(self.prog, self.vers, proc, packed_args))
return self.replies
# Server classes
# These are not symmetric to the Client classes
# XXX No attempt is made to provide authorization hooks yet
class Server:
def __init__(self, host, prog, vers, port):
self.host = host # Should normally be '' for default interface
self.prog = prog
self.vers = vers
self.port = port # Should normally be 0 for random port
self.makesocket() # Assigns to self.sock and self.prot
self.bindsocket()
self.host, self.port = self.sock.getsockname()
self.addpackers()
def register(self):
mapping = self.prog, self.vers, self.prot, self.port
p = TCPPortMapperClient(self.host)
if not p.Set(mapping):
raise RuntimeError('register failed')
def unregister(self):
mapping = self.prog, self.vers, self.prot, self.port
p = TCPPortMapperClient(self.host)
if not p.Unset(mapping):
raise RuntimeError('unregister failed')
def handle(self, call):
# Don't use unpack_header but parse the header piecewise
# XXX I have no idea if I am using the right error responses!
self.unpacker.reset(call)
self.packer.reset()
xid = self.unpacker.unpack_uint()
self.packer.pack_uint(xid)
temp = self.unpacker.unpack_enum()
if temp != CALL:
return None # Not worthy of a reply
self.packer.pack_uint(REPLY)
temp = self.unpacker.unpack_uint()
if temp != RPCVERSION:
self.packer.pack_uint(MSG_DENIED)
self.packer.pack_uint(RPC_MISMATCH)
self.packer.pack_uint(RPCVERSION)
self.packer.pack_uint(RPCVERSION)
return self.packer.get_buf()
self.packer.pack_uint(MSG_ACCEPTED)
self.packer.pack_auth((AUTH_NULL, make_auth_null()))
prog = self.unpacker.unpack_uint()
if prog != self.prog:
self.packer.pack_uint(PROG_UNAVAIL)
return self.packer.get_buf()
vers = self.unpacker.unpack_uint()
if vers != self.vers:
self.packer.pack_uint(PROG_MISMATCH)
self.packer.pack_uint(self.vers)
self.packer.pack_uint(self.vers)
return self.packer.get_buf()
proc = self.unpacker.unpack_uint()
methname = 'handle_' + repr(proc)
try:
meth = getattr(self, methname)
except AttributeError:
self.packer.pack_uint(PROC_UNAVAIL)
return self.packer.get_buf()
cred = self.unpacker.unpack_auth()
verf = self.unpacker.unpack_auth()
try:
meth() # Unpack args, call turn_around(), pack reply
except (EOFError, GarbageArgs):
# Too few or too many arguments
self.packer.reset()
self.packer.pack_uint(xid)
self.packer.pack_uint(REPLY)
self.packer.pack_uint(MSG_ACCEPTED)
self.packer.pack_auth((AUTH_NULL, make_auth_null()))
self.packer.pack_uint(GARBAGE_ARGS)
return self.packer.get_buf()
def turn_around(self):
try:
self.unpacker.done()
except RuntimeError:
raise GarbageArgs
self.packer.pack_uint(SUCCESS)
def handle_0(self): # Handle NULL message
self.turn_around()
def makesocket(self):
# This MUST be overridden
raise RuntimeError('makesocket not defined')
def bindsocket(self):
# Override this to bind to a different port (e.g. reserved)
self.sock.bind((self.host, self.port))
def addpackers(self):
# Override this to use derived classes from Packer/Unpacker
self.packer = Packer()
self.unpacker = Unpacker('')
class TCPServer(Server):
def makesocket(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.prot = IPPROTO_TCP
def loop(self):
self.sock.listen(0)
while 1:
self.session(self.sock.accept())
def session(self, connection):
sock, (host, port) = connection
while 1:
try:
call = recvrecord(sock)
except EOFError:
break
except socket.error as msg:
print('socket error:', msg)
break
reply = self.handle(call)
if reply is not None:
sendrecord(sock, reply)
def forkingloop(self):
# Like loop but uses forksession()
self.sock.listen(0)
while 1:
self.forksession(self.sock.accept())
def forksession(self, connection):
# Like session but forks off a subprocess
import os
# Wait for deceased children
try:
while 1:
pid, sts = os.waitpid(0, 1)
except os.error:
pass
pid = None
try:
pid = os.fork()
if pid: # Parent
connection[0].close()
return
# Child
self.session(connection)
finally:
# Make sure we don't fall through in the parent
if pid == 0:
os._exit(0)
class UDPServer(Server):
def makesocket(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.prot = IPPROTO_UDP
def loop(self):
while 1:
self.session()
def session(self):
call, host_port = self.sock.recvfrom(8192)
reply = self.handle(call)
if reply is not None:
self.sock.sendto(reply, host_port)
# Simple test program -- dump local portmapper status
def test():
pmap = UDPPortMapperClient('')
list = pmap.Dump()
list.sort()
for prog, vers, prot, port in list:
print(prog, vers, end=' ')
if prot == IPPROTO_TCP: print('tcp', end=' ')
elif prot == IPPROTO_UDP: print('udp', end=' ')
else: print(prot, end=' ')
print(port)
# Test program for broadcast operation -- dump everybody's portmapper status
def testbcast():
import sys
if sys.argv[1:]:
bcastaddr = sys.argv[1]
else:
bcastaddr = '<broadcast>'
def rh(reply, fromaddr):
host, port = fromaddr
print(host + '\t' + repr(reply))
pmap = BroadcastUDPPortMapperClient(bcastaddr)
pmap.set_reply_handler(rh)
pmap.set_timeout(5)
replies = pmap.Getport((100002, 1, IPPROTO_UDP, 0))
# Test program for server, with corresponding client
# On machine A: python -c 'import rpc; rpc.testsvr()'
# On machine B: python -c 'import rpc; rpc.testclt()' A
# (A may be == B)
def testsvr():
# Simple test class -- proc 1 doubles its string argument as reply
class S(UDPServer):
def handle_1(self):
arg = self.unpacker.unpack_string()
self.turn_around()
print('RPC function 1 called, arg', repr(arg))
self.packer.pack_string(arg + arg)
#
s = S('', 0x20000000, 1, 0)
try:
s.unregister()
except RuntimeError as msg:
print('RuntimeError:', msg, '(ignored)')
s.register()
print('Service started...')
try:
s.loop()
finally:
s.unregister()
print('Service interrupted.')
def testclt():
import sys
if sys.argv[1:]: host = sys.argv[1]
else: host = ''
# Client for above server
class C(UDPClient):
def call_1(self, arg):
return self.make_call(1, arg, \
self.packer.pack_string, \
self.unpacker.unpack_string)
c = C(host, 0x20000000, 1)
print('making call...')
reply = c.call_1('hello, world, ')
print('call returned', repr(reply))

View File

@ -1,24 +0,0 @@
: ${PYTHON=python}
: ${SERVER=charon.cwi.nl}
set -xe
$PYTHON -c 'from rpc import test; test()'
$PYTHON -c 'from rpc import test; test()' ${SERVER}
$PYTHON -c 'from rpc import testsvr; testsvr()' &
PID=$!
sleep 2
$PYTHON -c 'from rpc import testclt; testclt()'
kill -2 $PID
$PYTHON -c 'from mountclient import test; test()'
$PYTHON -c 'from mountclient import test; test()' gatekeeper.dec.com
$PYTHON -c 'from nfsclient import test; test()'
$PYTHON -c 'from nfsclient import test; test()' gatekeeper.dec.com
$PYTHON -c 'from nfsclient import test; test()' gatekeeper.dec.com /archive
$PYTHON -c 'from rnusersclient import test; test()' ''
$PYTHON -c 'from rpc import testbcast; testbcast()'

View File

@ -1,200 +0,0 @@
# Implement (a subset of) Sun XDR -- RFC1014.
try:
import struct
except ImportError:
struct = None
Long = type(0)
class Packer:
def __init__(self):
self.reset()
def reset(self):
self.buf = ''
def get_buf(self):
return self.buf
def pack_uint(self, x):
self.buf = self.buf + \
(chr(int(x>>24 & 0xff)) + chr(int(x>>16 & 0xff)) + \
chr(int(x>>8 & 0xff)) + chr(int(x & 0xff)))
if struct and struct.pack('l', 1) == '\0\0\0\1':
def pack_uint(self, x):
if type(x) == Long:
x = int((x + 0x80000000) % 0x100000000 \
- 0x80000000)
self.buf = self.buf + struct.pack('l', x)
pack_int = pack_uint
pack_enum = pack_int
def pack_bool(self, x):
if x: self.buf = self.buf + '\0\0\0\1'
else: self.buf = self.buf + '\0\0\0\0'
def pack_uhyper(self, x):
self.pack_uint(int(x>>32 & 0xffffffff))
self.pack_uint(int(x & 0xffffffff))
pack_hyper = pack_uhyper
def pack_float(self, x):
# XXX
self.buf = self.buf + struct.pack('f', x)
def pack_double(self, x):
# XXX
self.buf = self.buf + struct.pack('d', x)
def pack_fstring(self, n, s):
if n < 0:
raise ValueError('fstring size must be nonnegative')
n = ((n + 3)//4)*4
data = s[:n]
data = data + (n - len(data)) * '\0'
self.buf = self.buf + data
pack_fopaque = pack_fstring
def pack_string(self, s):
n = len(s)
self.pack_uint(n)
self.pack_fstring(n, s)
pack_opaque = pack_string
def pack_list(self, list, pack_item):
for item in list:
self.pack_uint(1)
pack_item(item)
self.pack_uint(0)
def pack_farray(self, n, list, pack_item):
if len(list) != n:
raise ValueError('wrong array size')
for item in list:
pack_item(item)
def pack_array(self, list, pack_item):
n = len(list)
self.pack_uint(n)
self.pack_farray(n, list, pack_item)
class Unpacker:
def __init__(self, data):
self.reset(data)
def reset(self, data):
self.buf = data
self.pos = 0
def done(self):
if self.pos < len(self.buf):
raise RuntimeError('unextracted data remains')
def unpack_uint(self):
i = self.pos
self.pos = j = i+4
data = self.buf[i:j]
if len(data) < 4:
raise EOFError
x = int(ord(data[0]))<<24 | ord(data[1])<<16 | \
ord(data[2])<<8 | ord(data[3])
# Return a Python long only if the value is not representable
# as a nonnegative Python int
if x < 0x80000000: x = int(x)
return x
if struct and struct.unpack('l', '\0\0\0\1') == 1:
def unpack_uint(self):
i = self.pos
self.pos = j = i+4
data = self.buf[i:j]
if len(data) < 4:
raise EOFError
return struct.unpack('l', data)
def unpack_int(self):
x = self.unpack_uint()
if x >= 0x80000000: x = x - 0x100000000
return int(x)
unpack_enum = unpack_int
unpack_bool = unpack_int
def unpack_uhyper(self):
hi = self.unpack_uint()
lo = self.unpack_uint()
return int(hi)<<32 | lo
def unpack_hyper(self):
x = self.unpack_uhyper()
if x >= 0x8000000000000000: x = x - 0x10000000000000000
return x
def unpack_float(self):
# XXX
i = self.pos
self.pos = j = i+4
data = self.buf[i:j]
if len(data) < 4:
raise EOFError
return struct.unpack('f', data)[0]
def unpack_double(self):
# XXX
i = self.pos
self.pos = j = i+8
data = self.buf[i:j]
if len(data) < 8:
raise EOFError
return struct.unpack('d', data)[0]
def unpack_fstring(self, n):
if n < 0:
raise ValueError('fstring size must be nonnegative')
i = self.pos
j = i + (n+3)//4*4
if j > len(self.buf):
raise EOFError
self.pos = j
return self.buf[i:i+n]
unpack_fopaque = unpack_fstring
def unpack_string(self):
n = self.unpack_uint()
return self.unpack_fstring(n)
unpack_opaque = unpack_string
def unpack_list(self, unpack_item):
list = []
while 1:
x = self.unpack_uint()
if x == 0: break
if x != 1:
raise RuntimeError('0 or 1 expected, got %r' % (x, ))
item = unpack_item()
list.append(item)
return list
def unpack_farray(self, n, unpack_item):
list = []
for i in range(n):
list.append(unpack_item())
return list
def unpack_array(self, unpack_item):
n = self.unpack_uint()
return self.unpack_farray(n, unpack_item)

View File

@ -1,198 +0,0 @@
#! /usr/bin/env python3
# Fix Python source files to use the new equality test operator, i.e.,
# if x = y: ...
# is changed to
# if x == y: ...
# The script correctly tokenizes the Python program to reliably
# distinguish between assignments and equality tests.
#
# Command line arguments are files or directories to be processed.
# Directories are searched recursively for files whose name looks
# like a python module.
# Symbolic links are always ignored (except as explicit directory
# arguments). Of course, the original file is kept as a back-up
# (with a "~" attached to its name).
# It complains about binaries (files containing null bytes)
# and about files that are ostensibly not Python files: if the first
# line starts with '#!' and does not contain the string 'python'.
#
# Changes made are reported to stdout in a diff-like format.
#
# Undoubtedly you can do this using find and sed or perl, but this is
# a nice example of Python code that recurses down a directory tree
# and uses regular expressions. Also note several subtleties like
# preserving the file's mode and avoiding to even write a temp file
# when no changes are needed for a file.
#
# NB: by changing only the function fixline() you can turn this
# into a program for a different change to Python programs...
import sys
import re
import os
from stat import *
import string
err = sys.stderr.write
dbg = err
rep = sys.stdout.write
def main():
bad = 0
if not sys.argv[1:]: # No arguments
err('usage: ' + sys.argv[0] + ' file-or-directory ...\n')
sys.exit(2)
for arg in sys.argv[1:]:
if os.path.isdir(arg):
if recursedown(arg): bad = 1
elif os.path.islink(arg):
err(arg + ': will not process symbolic links\n')
bad = 1
else:
if fix(arg): bad = 1
sys.exit(bad)
ispythonprog = re.compile('^[a-zA-Z0-9_]+\.py$')
def ispython(name):
return ispythonprog.match(name) >= 0
def recursedown(dirname):
dbg('recursedown(%r)\n' % (dirname,))
bad = 0
try:
names = os.listdir(dirname)
except os.error as msg:
err('%s: cannot list directory: %r\n' % (dirname, msg))
return 1
names.sort()
subdirs = []
for name in names:
if name in (os.curdir, os.pardir): continue
fullname = os.path.join(dirname, name)
if os.path.islink(fullname): pass
elif os.path.isdir(fullname):
subdirs.append(fullname)
elif ispython(name):
if fix(fullname): bad = 1
for fullname in subdirs:
if recursedown(fullname): bad = 1
return bad
def fix(filename):
## dbg('fix(%r)\n' % (dirname,))
try:
f = open(filename, 'r')
except IOError as msg:
err('%s: cannot open: %r\n' % (filename, msg))
return 1
head, tail = os.path.split(filename)
tempname = os.path.join(head, '@' + tail)
g = None
# If we find a match, we rewind the file and start over but
# now copy everything to a temp file.
lineno = 0
while 1:
line = f.readline()
if not line: break
lineno = lineno + 1
if g is None and '\0' in line:
# Check for binary files
err(filename + ': contains null bytes; not fixed\n')
f.close()
return 1
if lineno == 1 and g is None and line[:2] == '#!':
# Check for non-Python scripts
words = string.split(line[2:])
if words and re.search('[pP]ython', words[0]) < 0:
msg = filename + ': ' + words[0]
msg = msg + ' script; not fixed\n'
err(msg)
f.close()
return 1
while line[-2:] == '\\\n':
nextline = f.readline()
if not nextline: break
line = line + nextline
lineno = lineno + 1
newline = fixline(line)
if newline != line:
if g is None:
try:
g = open(tempname, 'w')
except IOError as msg:
f.close()
err('%s: cannot create: %r\n' % (tempname, msg))
return 1
f.seek(0)
lineno = 0
rep(filename + ':\n')
continue # restart from the beginning
rep(repr(lineno) + '\n')
rep('< ' + line)
rep('> ' + newline)
if g is not None:
g.write(newline)
# End of file
f.close()
if not g: return 0 # No changes
# Finishing touch -- move files
# First copy the file's mode to the temp file
try:
statbuf = os.stat(filename)
os.chmod(tempname, statbuf[ST_MODE] & 0o7777)
except os.error as msg:
err('%s: warning: chmod failed (%r)\n' % (tempname, msg))
# Then make a backup of the original file as filename~
try:
os.rename(filename, filename + '~')
except os.error as msg:
err('%s: warning: backup failed (%r)\n' % (filename, msg))
# Now move the temp file to the original file
try:
os.rename(tempname, filename)
except os.error as msg:
err('%s: rename failed (%r)\n' % (filename, msg))
return 1
# Return succes
return 0
from tokenize import tokenprog
match = {'if':':', 'elif':':', 'while':':', 'return':'\n', \
'(':')', '[':']', '{':'}', '`':'`'}
def fixline(line):
# Quick check for easy case
if '=' not in line: return line
i, n = 0, len(line)
stack = []
while i < n:
j = tokenprog.match(line, i)
if j < 0:
# A bad token; forget about the rest of this line
print('(Syntax error:)')
print(line, end=' ')
return line
a, b = tokenprog.regs[3] # Location of the token proper
token = line[a:b]
i = i+j
if stack and token == stack[-1]:
del stack[-1]
elif token in match:
stack.append(match[token])
elif token == '=' and stack:
line = line[:a] + '==' + line[b:]
i, n = a + len('=='), len(line)
elif token == '==' and not stack:
print('(Warning: \'==\' at top level:)')
print(line, end=' ')
return line
if __name__ == "__main__":
main()

View File

@ -1,35 +0,0 @@
#! /usr/bin/env python3
# Print From and Subject of messages in $MAIL.
# Extension to multiple mailboxes and other bells & whistles are left
# as exercises for the reader.
import sys, os
# Open mailbox file. Exits with exception when this fails.
try:
mailbox = os.environ['MAIL']
except (AttributeError, KeyError):
sys.stderr.write('No environment variable $MAIL\n')
sys.exit(2)
try:
mail = open(mailbox)
except IOError:
sys.exit('Cannot open mailbox file: ' + mailbox)
while 1:
line = mail.readline()
if not line:
break # EOF
if line.startswith('From '):
# Start of message found
print(line[:-1], end=' ')
while 1:
line = mail.readline()
if not line or line == '\n':
break
if line.startswith('Subject: '):
print(repr(line[9:-1]), end=' ')
print()

View File

@ -1,102 +0,0 @@
#! /usr/bin/env python3
# Watch line printer queue(s).
# Intended for BSD 4.3 lpq.
import os
import sys
import time
DEF_PRINTER = 'psc'
DEF_DELAY = 10
def main():
delay = DEF_DELAY # XXX Use getopt() later
try:
thisuser = os.environ['LOGNAME']
except:
thisuser = os.environ['USER']
printers = sys.argv[1:]
if printers:
# Strip '-P' from printer names just in case
# the user specified it...
for i, name in enumerate(printers):
if name[:2] == '-P':
printers[i] = name[2:]
else:
if 'PRINTER' in os.environ:
printers = [os.environ['PRINTER']]
else:
printers = [DEF_PRINTER]
clearhome = os.popen('clear', 'r').read()
while True:
text = clearhome
for name in printers:
text += makestatus(name, thisuser) + '\n'
print(text)
time.sleep(delay)
def makestatus(name, thisuser):
pipe = os.popen('lpq -P' + name + ' 2>&1', 'r')
lines = []
users = {}
aheadbytes = 0
aheadjobs = 0
userseen = False
totalbytes = 0
totaljobs = 0
for line in pipe:
fields = line.split()
n = len(fields)
if len(fields) >= 6 and fields[n-1] == 'bytes':
rank, user, job = fields[0:3]
files = fields[3:-2]
bytes = int(fields[n-2])
if user == thisuser:
userseen = True
elif not userseen:
aheadbytes += bytes
aheadjobs += 1
totalbytes += bytes
totaljobs += 1
ujobs, ubytes = users.get(user, (0, 0))
ujobs += 1
ubytes += bytes
users[user] = ujobs, ubytes
else:
if fields and fields[0] != 'Rank':
line = line.strip()
if line == 'no entries':
line = name + ': idle'
elif line[-22:] == ' is ready and printing':
line = name
lines.append(line)
if totaljobs:
line = '%d K' % ((totalbytes+1023) // 1024)
if totaljobs != len(users):
line += ' (%d jobs)' % totaljobs
if len(users) == 1:
line += ' for %s' % next(iter(users))
else:
line += ' for %d users' % len(users)
if userseen:
if aheadjobs == 0:
line += ' (%s first)' % thisuser
else:
line += ' (%d K before %s)' % (
(aheadbytes+1023) // 1024, thisuser)
lines.append(line)
sts = pipe.close()
if sts:
lines.append('lpq exit status %r' % (sts,))
return ': '.join(lines)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
pass

View File

@ -1,21 +0,0 @@
#! /usr/bin/env python3
# Like mkdir, but also make intermediate directories if necessary.
# It is not an error if the given directory already exists (as long
# as it is a directory).
# Errors are not treated specially -- you just get a Python exception.
import sys, os
def main():
for p in sys.argv[1:]:
makedirs(p)
def makedirs(p):
if p and not os.path.isdir(p):
head, tail = os.path.split(p)
makedirs(head)
os.mkdir(p, 0o777)
if __name__ == "__main__":
main()

View File

@ -1,124 +0,0 @@
#! /usr/bin/env python3
# Convert MH directories (1 message per file) or MMDF mailboxes (4x^A
# delimited) to unix mailbox (From ... delimited) on stdout.
# If -f is given, files contain one message per file (e.g. MH messages)
import rfc822
import sys
import time
import os
import stat
import getopt
import re
def main():
dofile = mmdf
try:
opts, args = getopt.getopt(sys.argv[1:], 'f')
except getopt.error as msg:
sys.stderr.write('%s\n' % msg)
sys.exit(2)
for o, a in opts:
if o == '-f':
dofile = message
if not args:
args = ['-']
sts = 0
for arg in args:
if arg == '-' or arg == '':
sts = dofile(sys.stdin) or sts
elif os.path.isdir(arg):
sts = mh(arg) or sts
elif os.path.isfile(arg):
try:
f = open(arg)
except IOError as msg:
sys.stderr.write('%s: %s\n' % (arg, msg))
sts = 1
continue
sts = dofile(f) or sts
f.close()
else:
sys.stderr.write('%s: not found\n' % arg)
sts = 1
if sts:
sys.exit(sts)
numeric = re.compile('[1-9][0-9]*')
def mh(dir):
sts = 0
msgs = os.listdir(dir)
for msg in msgs:
if numeric.match(msg) != len(msg):
continue
fn = os.path.join(dir, msg)
try:
f = open(fn)
except IOError as msg:
sys.stderr.write('%s: %s\n' % (fn, msg))
sts = 1
continue
sts = message(f) or sts
return sts
def mmdf(f):
sts = 0
while 1:
line = f.readline()
if not line:
break
if line == '\1\1\1\1\n':
sts = message(f, line) or sts
else:
sys.stderr.write(
'Bad line in MMFD mailbox: %r\n' % (line,))
return sts
counter = 0 # for generating unique Message-ID headers
def message(f, delimiter = ''):
sts = 0
# Parse RFC822 header
m = rfc822.Message(f)
# Write unix header line
fullname, email = m.getaddr('From')
tt = m.getdate('Date')
if tt:
t = time.mktime(tt)
else:
sys.stderr.write(
'Unparseable date: %r\n' % (m.get('Date'),))
t = os.fstat(f.fileno())[stat.ST_MTIME]
print('From', email, time.ctime(t))
# Copy RFC822 header
for line in m.headers:
print(line, end=' ')
# Invent Message-ID header if none is present
if 'message-id' not in m:
global counter
counter = counter + 1
msgid = "<%s.%d>" % (hex(t), counter)
sys.stderr.write("Adding Message-ID %s (From %s)\n" %
(msgid, email))
print("Message-ID:", msgid)
print()
# Copy body
while 1:
line = f.readline()
if line == delimiter:
break
if not line:
sys.stderr.write('Unexpected EOF in message\n')
sts = 1
break
if line[:5] == 'From ':
line = '>' + line
print(line, end=' ')
# Print trailing newline
print()
return sts
if __name__ == "__main__":
main()

View File

@ -1,128 +0,0 @@
#! /usr/bin/env python3
# DAH should be three DOTs.
# Space between DOTs and DAHs should be one DOT.
# Space between two letters should be one DAH.
# Space between two words should be DOT DAH DAH.
import sys, math, aifc
from contextlib import closing
DOT = 30
DAH = 3 * DOT
OCTAVE = 2 # 1 == 441 Hz, 2 == 882 Hz, ...
morsetab = {
'A': '.-', 'a': '.-',
'B': '-...', 'b': '-...',
'C': '-.-.', 'c': '-.-.',
'D': '-..', 'd': '-..',
'E': '.', 'e': '.',
'F': '..-.', 'f': '..-.',
'G': '--.', 'g': '--.',
'H': '....', 'h': '....',
'I': '..', 'i': '..',
'J': '.---', 'j': '.---',
'K': '-.-', 'k': '-.-',
'L': '.-..', 'l': '.-..',
'M': '--', 'm': '--',
'N': '-.', 'n': '-.',
'O': '---', 'o': '---',
'P': '.--.', 'p': '.--.',
'Q': '--.-', 'q': '--.-',
'R': '.-.', 'r': '.-.',
'S': '...', 's': '...',
'T': '-', 't': '-',
'U': '..-', 'u': '..-',
'V': '...-', 'v': '...-',
'W': '.--', 'w': '.--',
'X': '-..-', 'x': '-..-',
'Y': '-.--', 'y': '-.--',
'Z': '--..', 'z': '--..',
'0': '-----', ',': '--..--',
'1': '.----', '.': '.-.-.-',
'2': '..---', '?': '..--..',
'3': '...--', ';': '-.-.-.',
'4': '....-', ':': '---...',
'5': '.....', "'": '.----.',
'6': '-....', '-': '-....-',
'7': '--...', '/': '-..-.',
'8': '---..', '(': '-.--.-',
'9': '----.', ')': '-.--.-',
' ': ' ', '_': '..--.-',
}
nowave = b'\0' * 200
# If we play at 44.1 kHz (which we do), then if we produce one sine
# wave in 100 samples, we get a tone of 441 Hz. If we produce two
# sine waves in these 100 samples, we get a tone of 882 Hz. 882 Hz
# appears to be a nice one for playing morse code.
def mkwave(octave):
sinewave = bytearray()
for i in range(100):
val = int(math.sin(math.pi * i * octave / 50.0) * 30000)
sinewave.extend([(val >> 8) & 255, val & 255])
return bytes(sinewave)
defaultwave = mkwave(OCTAVE)
def main():
import getopt
try:
opts, args = getopt.getopt(sys.argv[1:], 'o:p:')
except getopt.error:
sys.stderr.write('Usage ' + sys.argv[0] +
' [ -o outfile ] [ -p octave ] [ words ] ...\n')
sys.exit(1)
wave = defaultwave
outfile = 'morse.aifc'
for o, a in opts:
if o == '-o':
outfile = a
if o == '-p':
wave = mkwave(int(a))
with closing(aifc.open(outfile, 'w')) as fp:
fp.setframerate(44100)
fp.setsampwidth(2)
fp.setnchannels(1)
if args:
source = [' '.join(args)]
else:
source = iter(sys.stdin.readline, '')
for line in source:
mline = morse(line)
play(mline, fp, wave)
# Convert a string to morse code with \001 between the characters in
# the string.
def morse(line):
res = ''
for c in line:
try:
res += morsetab[c] + '\001'
except KeyError:
pass
return res
# Play a line of morse code.
def play(line, fp, wave):
for c in line:
if c == '.':
sine(fp, DOT, wave)
elif c == '-':
sine(fp, DAH, wave)
else: # space
pause(fp, DAH + DOT)
pause(fp, DOT)
def sine(fp, length, wave):
for i in range(length):
fp.writeframesraw(wave)
def pause(fp, length):
for i in range(length):
fp.writeframesraw(nowave)
if __name__ == '__main__':
main()

View File

@ -1,59 +0,0 @@
NEWSLIST
========
A program to assist HTTP browsing of newsgroups
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
WWW browsers such as NCSA Mosaic allow the user to read newsgroup
articles by specifying the group name in a URL eg 'news:comp.answers'.
To browse through many groups, though, (and there are several thousand
of them) you really need a page or pages containing links to all the
groups. There are some good ones out there, for example,
http://info.cern.ch/hypertext/DataSources/News/Groups/Overview.html
is the standard one at CERN, but it only shows the groups available there,
which may be rather different from those available on your machine.
Newslist is a program which creates a hierarchy of pages for you based
on the groups available from YOUR server. It is written in python - a
splendid interpreted object-oriented language which I suggest you get
right now from the directory /pub/python at ftp.cwi.nl, if you haven't
already got it.
You should be able to see some sample output by looking at:
http://pelican.cl.cam.ac.uk/newspage/root.html
Descriptions of newsgroups can be added from a file with one group
per line. eg:
alt.foo Articles about foo
comp.bar Programming in 'bar' and related languages
A suitable list detailing most groups can be found at ftp.uu.net in
/uunet-info/newsgroups.gz.
Make sure you read the information at the beginning of the program source and
configure the variables before running.
In addition to python, you need:
An NNTP-based news feed.
A directory in which to put the pages.
The programming is not very beautiful, but it works! It comes with no
warranty, express or implied, but with the hope that some others may
find it useful.
Comments, improvements & suggestions welcomed.
Quentin Stafford-Fraser
----------------------------------------------------------------------
Quentin Stafford-Fraser
http://pelican.cl.cam.ac.uk/people/qs101/me.html
Cambridge University Computer Lab Rank Xerox Cambridge EuroPARC
qs101@cl.cam.ac.uk fraser@europarc.xerox.com
Tel: +44 223 334411 Tel: +44 223 341521
Fax: +44 223 334679 Fax: +44 223 341510
----------------------------------------------------------------------

View File

@ -1,361 +0,0 @@
#! /usr/bin/env python3
#######################################################################
# Newslist $Revision$
#
# Syntax:
# newslist [ -a ]
#
# This is a program to create a directory full of HTML pages
# which between them contain links to all the newsgroups available
# on your server.
#
# The -a option causes a complete list of all groups to be read from
# the server rather than just the ones which have appeared since last
# execution. This recreates the local list from scratch. Use this on
# the first invocation of the program, and from time to time thereafter.
# When new groups are first created they may appear on your server as
# empty groups. By default, empty groups are ignored by the -a option.
# However, these new groups will not be created again, and so will not
# appear in the server's list of 'new groups' at a later date. Hence it
# won't appear until you do a '-a' after some articles have appeared.
#
# I should really keep a list of ignored empty groups and re-check them
# for articles on every run, but I haven't got around to it yet.
#
# This assumes an NNTP news feed.
#
# Feel free to copy, distribute and modify this code for
# non-commercial use. If you make any useful modifications, let me
# know!
#
# (c) Quentin Stafford-Fraser 1994
# fraser@europarc.xerox.com qs101@cl.cam.ac.uk
# #
#######################################################################
import sys, nntplib, marshal, time, os
#######################################################################
# Check these variables before running! #
# Top directory.
# Filenames which don't start with / are taken as being relative to this.
topdir = os.path.expanduser('~/newspage')
# The name of your NNTP host
# eg.
# newshost = 'nntp-serv.cl.cam.ac.uk'
# or use following to get the name from the NNTPSERVER environment
# variable:
# newshost = os.environ['NNTPSERVER']
newshost = 'news.example.com'
# The filename for a local cache of the newsgroup list
treefile = 'grouptree'
# The filename for descriptions of newsgroups
# I found a suitable one at ftp.uu.net in /uunet-info/newgroups.gz
# You can set this to '' if you don't wish to use one.
descfile = 'newsgroups'
# The directory in which HTML pages should be created
# eg.
# pagedir = '/usr/local/lib/html/newspage'
# pagedir = 'pages'
pagedir = topdir
# The html prefix which will refer to this directory
# eg.
# httppref = '/newspage/',
# or leave blank for relative links between pages: (Recommended)
# httppref = ''
httppref = ''
# The name of the 'root' news page in this directory.
# A .html suffix will be added.
rootpage = 'root'
# Set skipempty to 0 if you wish to see links to empty groups as well.
# Only affects the -a option.
skipempty = 1
# pagelinkicon can contain html to put an icon after links to
# further pages. This helps to make important links stand out.
# Set to '' if not wanted, or '...' is quite a good one.
pagelinkicon = '... <img src="http://pelican.cl.cam.ac.uk/icons/page.xbm"> '
# ---------------------------------------------------------------------
# Less important personal preferences:
# Sublistsize controls the maximum number of items the will appear as
# an indented sub-list before the whole thing is moved onto a different
# page. The smaller this is, the more pages you will have, but the
# shorter each will be.
sublistsize = 4
# That should be all. #
#######################################################################
for dir in os.curdir, os.environ['HOME']:
rcfile = os.path.join(dir, '.newslistrc.py')
if os.path.exists(rcfile):
print(rcfile)
exec(open(rcfile).read())
break
from nntplib import NNTP
from stat import *
rcsrev = '$Revision$'
rcsrev = ' '.join([s for s in rcsrev.split() if '$' not in s])
desc = {}
# Make (possibly) relative filenames into absolute ones
treefile = os.path.join(topdir,treefile)
descfile = os.path.join(topdir,descfile)
page = os.path.join(topdir,pagedir)
# First the bits for creating trees ---------------------------
# Addtotree creates/augments a tree from a list of group names
def addtotree(tree, groups):
print('Updating tree...')
for i in groups:
parts = i.split('.')
makeleaf(tree, parts)
# Makeleaf makes a leaf and the branch leading to it if necessary
def makeleaf(tree,path):
j = path[0]
l = len(path)
if j not in tree:
tree[j] = {}
if l == 1:
tree[j]['.'] = '.'
if l > 1:
makeleaf(tree[j],path[1:])
# Then the bits for outputting trees as pages ----------------
# Createpage creates an HTML file named <root>.html containing links
# to those groups beginning with <root>.
def createpage(root, tree, p):
filename = os.path.join(pagedir, root+'.html')
if root == rootpage:
detail = ''
else:
detail = ' under ' + root
with open(filename, 'w') as f:
# f.write('Content-Type: text/html\n')
f.write('<html>\n<head>\n')
f.write('<title>Newsgroups available%s</title>\n' % detail)
f.write('</head>\n<body>\n')
f.write('<h1>Newsgroups available%s</h1>\n' % detail)
f.write('<a href="%s%s.html">Back to top level</a><p>\n' %
(httppref, rootpage))
printtree(f, tree, 0, p)
f.write('\n<p>')
f.write("<i>This page automatically created by 'newslist' v. %s." %
rcsrev)
f.write(time.ctime(time.time()) + '</i>\n')
f.write('</body>\n</html>\n')
# Printtree prints the groups as a bulleted list. Groups with
# more than <sublistsize> subgroups will be put on a separate page.
# Other sets of subgroups are just indented.
def printtree(f, tree, indent, p):
l = len(tree)
if l > sublistsize and indent > 0:
# Create a new page and a link to it
f.write('<li><b><a href="%s%s.html">' % (httppref, p[1:]))
f.write(p[1:] + '.*')
f.write('</a></b>%s\n' % pagelinkicon)
createpage(p[1:], tree, p)
return
kl = sorted(tree.keys())
if l > 1:
if indent > 0:
# Create a sub-list
f.write('<li>%s\n<ul>' % p[1:])
else:
# Create a main list
f.write('<ul>')
indent = indent + 1
for i in kl:
if i == '.':
# Output a newsgroup
f.write('<li><a href="news:%s">%s</a> ' % (p[1:], p[1:]))
if p[1:] in desc:
f.write(' <i>%s</i>\n' % desc[p[1:]])
else:
f.write('\n')
else:
# Output a hierarchy
printtree(f, tree[i], indent, p+'.'+i)
if l > 1:
f.write('\n</ul>')
# Reading descriptions file ---------------------------------------
# This returns a dict mapping group name to its description
def readdesc(descfile):
global desc
desc = {}
if descfile == '':
return
try:
with open(descfile, 'r') as d:
print('Reading descriptions...')
for l in d:
bits = l.split()
try:
grp = bits[0]
dsc = ' '.join(bits[1:])
if len(dsc) > 1:
desc[grp] = dsc
except IndexError:
pass
except IOError:
print('Failed to open description file ' + descfile)
return
# Check that ouput directory exists, ------------------------------
# and offer to create it if not
def checkopdir(pagedir):
if not os.path.isdir(pagedir):
print('Directory %s does not exist.' % pagedir)
print('Shall I create it for you? (y/n)')
if sys.stdin.readline()[0] == 'y':
try:
os.mkdir(pagedir, 0o777)
except:
print('Sorry - failed!')
sys.exit(1)
else:
print('OK. Exiting.')
sys.exit(1)
# Read and write current local tree ----------------------------------
def readlocallist(treefile):
print('Reading current local group list...')
tree = {}
try:
treetime = time.localtime(os.stat(treefile)[ST_MTIME])
except:
print('\n*** Failed to open local group cache '+treefile)
print('If this is the first time you have run newslist, then')
print('use the -a option to create it.')
sys.exit(1)
treedate = '%02d%02d%02d' % (treetime[0] % 100, treetime[1], treetime[2])
try:
with open(treefile, 'rb') as dump:
tree = marshal.load(dump)
except IOError:
print('Cannot open local group list ' + treefile)
return (tree, treedate)
def writelocallist(treefile, tree):
try:
with open(treefile, 'wb') as dump:
groups = marshal.dump(tree, dump)
print('Saved list to %s\n' % treefile)
except:
print('Sorry - failed to write to local group cache', treefile)
print('Does it (or its directory) have the correct permissions?')
sys.exit(1)
# Return list of all groups on server -----------------------------
def getallgroups(server):
print('Getting list of all groups...')
treedate = '010101'
info = server.list()[1]
groups = []
print('Processing...')
if skipempty:
print('\nIgnoring following empty groups:')
for i in info:
grpname = i[0].split()[0]
if skipempty and int(i[1]) < int(i[2]):
print(grpname.decode() + ' ', end=' ')
else:
groups.append(grpname.decode())
print('\n')
if skipempty:
print('(End of empty groups)')
return groups
# Return list of new groups on server -----------------------------
def getnewgroups(server, treedate):
print('Getting list of new groups since start of %s...' % treedate, end=' ')
info = server.newgroups(treedate, '000001')[1]
print('got %d.' % len(info))
print('Processing...', end=' ')
groups = []
for i in info:
grpname = i.split()[0]
groups.append(grpname.decode())
print('Done')
return groups
# Now the main program --------------------------------------------
def main():
tree = {}
# Check that the output directory exists
checkopdir(pagedir)
try:
print('Connecting to %s...' % newshost)
if sys.version[0] == '0':
s = NNTP.init(newshost)
else:
s = NNTP(newshost)
connected = True
except (nntplib.error_temp, nntplib.error_perm) as x:
print('Error connecting to host:', x)
print('I\'ll try to use just the local list.')
connected = False
# If -a is specified, read the full list of groups from server
if connected and len(sys.argv) > 1 and sys.argv[1] == '-a':
groups = getallgroups(s)
# Otherwise just read the local file and then add
# groups created since local file last modified.
else:
(tree, treedate) = readlocallist(treefile)
if connected:
groups = getnewgroups(s, treedate)
if connected:
addtotree(tree, groups)
writelocallist(treefile,tree)
# Read group descriptions
readdesc(descfile)
print('Creating pages...')
createpage(rootpage, tree, '')
print('Done')
if __name__ == "__main__":
main()
# That's all folks
######################################################################

View File

@ -1,33 +0,0 @@
#! /usr/bin/env python3
# Print digits of pi forever.
#
# The algorithm, using Python's 'long' integers ("bignums"), works
# with continued fractions, and was conceived by Lambert Meertens.
#
# See also the ABC Programmer's Handbook, by Geurts, Meertens & Pemberton,
# published by Prentice-Hall (UK) Ltd., 1990.
import sys
def main():
k, a, b, a1, b1 = 2, 4, 1, 12, 4
while True:
# Next approximation
p, q, k = k*k, 2*k+1, k+1
a, b, a1, b1 = a1, b1, p*a+q*a1, p*b+q*b1
# Print common digits
d, d1 = a//b, a1//b1
while d == d1:
output(d)
a, a1 = 10*(a%b), 10*(a1%b1)
d, d1 = a//b, a1//b1
def output(d):
# Use write() to avoid spaces between the digits
sys.stdout.write(str(d))
# Flush so the output is seen immediately
sys.stdout.flush()
if __name__ == "__main__":
main()

View File

@ -1,125 +0,0 @@
#! /usr/bin/env python3
# Emulate some Perl command line options.
# Usage: pp [-a] [-c] [-d] [-e scriptline] [-F fieldsep] [-n] [-p] [file] ...
# Where the options mean the following:
# -a : together with -n or -p, splits each line into list F
# -c : check syntax only, do not execute any code
# -d : run the script under the debugger, pdb
# -e scriptline : gives one line of the Python script; may be repeated
# -F fieldsep : sets the field separator for the -a option [not in Perl]
# -n : runs the script for each line of input
# -p : prints the line after the script has run
# When no script lines have been passed, the first file argument
# contains the script. With -n or -p, the remaining arguments are
# read as input to the script, line by line. If a file is '-'
# or missing, standard input is read.
# XXX To do:
# - add -i extension option (change files in place)
# - make a single loop over the files and lines (changes effect of 'break')?
# - add an option to specify the record separator
# - except for -n/-p, run directly from the file if at all possible
import sys
import getopt
FS = ''
SCRIPT = []
AFLAG = 0
CFLAG = 0
DFLAG = 0
NFLAG = 0
PFLAG = 0
try:
optlist, ARGS = getopt.getopt(sys.argv[1:], 'acde:F:np')
except getopt.error as msg:
sys.stderr.write('%s: %s\n' % (sys.argv[0], msg))
sys.exit(2)
for option, optarg in optlist:
if option == '-a':
AFLAG = 1
elif option == '-c':
CFLAG = 1
elif option == '-d':
DFLAG = 1
elif option == '-e':
for line in optarg.split('\n'):
SCRIPT.append(line)
elif option == '-F':
FS = optarg
elif option == '-n':
NFLAG = 1
PFLAG = 0
elif option == '-p':
NFLAG = 1
PFLAG = 1
else:
print(option, 'not recognized???')
if not ARGS: ARGS.append('-')
if not SCRIPT:
if ARGS[0] == '-':
fp = sys.stdin
else:
fp = open(ARGS[0], 'r')
while 1:
line = fp.readline()
if not line: break
SCRIPT.append(line[:-1])
del fp
del ARGS[0]
if not ARGS: ARGS.append('-')
if CFLAG:
prologue = ['if 0:']
epilogue = []
elif NFLAG:
# Note that it is on purpose that AFLAG and PFLAG are
# tested dynamically each time through the loop
prologue = [
'LINECOUNT = 0',
'for FILE in ARGS:',
' \tif FILE == \'-\':',
' \t \tFP = sys.stdin',
' \telse:',
' \t \tFP = open(FILE, \'r\')',
' \tLINENO = 0',
' \twhile 1:',
' \t \tLINE = FP.readline()',
' \t \tif not LINE: break',
' \t \tLINENO = LINENO + 1',
' \t \tLINECOUNT = LINECOUNT + 1',
' \t \tL = LINE[:-1]',
' \t \taflag = AFLAG',
' \t \tif aflag:',
' \t \t \tif FS: F = L.split(FS)',
' \t \t \telse: F = L.split()'
]
epilogue = [
' \t \tif not PFLAG: continue',
' \t \tif aflag:',
' \t \t \tif FS: print(FS.join(F))',
' \t \t \telse: print(\' \'.join(F))',
' \t \telse: print(L)',
]
else:
prologue = ['if 1:']
epilogue = []
# Note that we indent using tabs only, so that any indentation style
# used in 'command' will come out right after re-indentation.
program = '\n'.join(prologue) + '\n'
for line in SCRIPT:
program += ' \t \t' + line + '\n'
program += '\n'.join(epilogue) + '\n'
if DFLAG:
import pdb
pdb.run(program)
else:
exec(program)

View File

@ -1,31 +0,0 @@
#! /usr/bin/env python3
# Print prime numbers in a given range
def primes(min, max):
if max >= 2 >= min:
print(2)
primes = [2]
i = 3
while i <= max:
for p in primes:
if i % p == 0 or p*p > i:
break
if i % p != 0:
primes.append(i)
if i >= min:
print(i)
i += 2
def main():
import sys
min, max = 2, 0x7fffffff
if sys.argv[1:]:
min = int(sys.argv[1])
if sys.argv[2:]:
max = int(sys.argv[2])
primes(min, max)
if __name__ == "__main__":
main()

View File

@ -1,42 +0,0 @@
#! /usr/bin/env python3
# script.py -- Make typescript of terminal session.
# Usage:
# -a Append to typescript.
# -p Use Python as shell.
# Author: Steen Lumholt.
import os, time, sys, getopt
import pty
def read(fd):
data = os.read(fd, 1024)
script.write(data)
return data
shell = 'sh'
filename = 'typescript'
mode = 'wb'
if 'SHELL' in os.environ:
shell = os.environ['SHELL']
try:
opts, args = getopt.getopt(sys.argv[1:], 'ap')
except getopt.error as msg:
print('%s: %s' % (sys.argv[0], msg))
sys.exit(2)
for o, a in opts:
if o == '-a':
mode = 'ab'
elif o == '-p':
shell = 'python'
script = open(filename, mode)
sys.stdout.write('Script started, file is %s\n' % filename)
script.write(('Script started on %s\n' % time.ctime(time.time())).encode())
pty.spawn(shell, read)
script.write(('Script done on %s\n' % time.ctime(time.time())).encode())
sys.stdout.write('Script done, file is %s\n' % filename)

View File

@ -1,92 +0,0 @@
#! /usr/bin/env python3
# Update a bunch of files according to a script.
# The input file contains lines of the form <filename>:<lineno>:<text>,
# meaning that the given line of the given file is to be replaced
# by the given text. This is useful for performing global substitutions
# on grep output:
import os
import sys
import re
pat = '^([^: \t\n]+):([1-9][0-9]*):'
prog = re.compile(pat)
class FileObj:
def __init__(self, filename):
self.filename = filename
self.changed = 0
try:
self.lines = open(filename, 'r').readlines()
except IOError as msg:
print('*** Can\'t open "%s":' % filename, msg)
self.lines = None
return
print('diffing', self.filename)
def finish(self):
if not self.changed:
print('no changes to', self.filename)
return
try:
os.rename(self.filename, self.filename + '~')
fp = open(self.filename, 'w')
except (os.error, IOError) as msg:
print('*** Can\'t rewrite "%s":' % self.filename, msg)
return
print('writing', self.filename)
for line in self.lines:
fp.write(line)
fp.close()
self.changed = 0
def process(self, lineno, rest):
if self.lines is None:
print('(not processed): %s:%s:%s' % (
self.filename, lineno, rest), end=' ')
return
i = eval(lineno) - 1
if not 0 <= i < len(self.lines):
print('*** Line number out of range: %s:%s:%s' % (
self.filename, lineno, rest), end=' ')
return
if self.lines[i] == rest:
print('(no change): %s:%s:%s' % (
self.filename, lineno, rest), end=' ')
return
if not self.changed:
self.changed = 1
print('%sc%s' % (lineno, lineno))
print('<', self.lines[i], end=' ')
print('---')
self.lines[i] = rest
print('>', self.lines[i], end=' ')
def main():
if sys.argv[1:]:
try:
fp = open(sys.argv[1], 'r')
except IOError as msg:
print('Can\'t open "%s":' % sys.argv[1], msg)
sys.exit(1)
else:
fp = sys.stdin
curfile = None
while 1:
line = fp.readline()
if not line:
if curfile: curfile.finish()
break
n = prog.match(line)
if n < 0:
print('Funny line:', line, end=' ')
continue
filename, lineno = prog.group(1, 2)
if not curfile or filename != curfile.filename:
if curfile: curfile.finish()
curfile = FileObj(filename)
curfile.process(lineno, line[n:])
if __name__ == "__main__":
main()

View File

@ -1,159 +0,0 @@
# Coroutine implementation using Python threads.
#
# Combines ideas from Guido's Generator module, and from the coroutine
# features of Icon and Simula 67.
#
# To run a collection of functions as coroutines, you need to create
# a Coroutine object to control them:
# co = Coroutine()
# and then 'create' a subsidiary object for each function in the
# collection:
# cof1 = co.create(f1 [, arg1, arg2, ...]) # [] means optional,
# cof2 = co.create(f2 [, arg1, arg2, ...]) #... not list
# cof3 = co.create(f3 [, arg1, arg2, ...])
# etc. The functions need not be distinct; 'create'ing the same
# function multiple times gives you independent instances of the
# function.
#
# To start the coroutines running, use co.tran on one of the create'd
# functions; e.g., co.tran(cof2). The routine that first executes
# co.tran is called the "main coroutine". It's special in several
# respects: it existed before you created the Coroutine object; if any of
# the create'd coroutines exits (does a return, or suffers an unhandled
# exception), EarlyExit error is raised in the main coroutine; and the
# co.detach() method transfers control directly to the main coroutine
# (you can't use co.tran() for this because the main coroutine doesn't
# have a name ...).
#
# Coroutine objects support these methods:
#
# handle = .create(func [, arg1, arg2, ...])
# Creates a coroutine for an invocation of func(arg1, arg2, ...),
# and returns a handle ("name") for the coroutine so created. The
# handle can be used as the target in a subsequent .tran().
#
# .tran(target, data=None)
# Transfer control to the create'd coroutine "target", optionally
# passing it an arbitrary piece of data. To the coroutine A that does
# the .tran, .tran acts like an ordinary function call: another
# coroutine B can .tran back to it later, and if it does A's .tran
# returns the 'data' argument passed to B's tran. E.g.,
#
# in coroutine coA in coroutine coC in coroutine coB
# x = co.tran(coC) co.tran(coB) co.tran(coA,12)
# print x # 12
#
# The data-passing feature is taken from Icon, and greatly cuts
# the need to use global variables for inter-coroutine communication.
#
# .back( data=None )
# The same as .tran(invoker, data=None), where 'invoker' is the
# coroutine that most recently .tran'ed control to the coroutine
# doing the .back. This is akin to Icon's "&source".
#
# .detach( data=None )
# The same as .tran(main, data=None), where 'main' is the
# (unnameable!) coroutine that started it all. 'main' has all the
# rights of any other coroutine: upon receiving control, it can
# .tran to an arbitrary coroutine of its choosing, go .back to
# the .detach'er, or .kill the whole thing.
#
# .kill()
# Destroy all the coroutines, and return control to the main
# coroutine. None of the create'ed coroutines can be resumed after a
# .kill(). An EarlyExit exception does a .kill() automatically. It's
# a good idea to .kill() coroutines you're done with, since the
# current implementation consumes a thread for each coroutine that
# may be resumed.
import _thread as thread
import sync
class _CoEvent:
def __init__(self, func):
self.f = func
self.e = sync.event()
def __repr__(self):
if self.f is None:
return 'main coroutine'
else:
return 'coroutine for func ' + self.f.__name__
def __hash__(self):
return id(self)
def __cmp__(x,y):
return cmp(id(x), id(y))
def resume(self):
self.e.post()
def wait(self):
self.e.wait()
self.e.clear()
class Killed(Exception): pass
class EarlyExit(Exception): pass
class Coroutine:
def __init__(self):
self.active = self.main = _CoEvent(None)
self.invokedby = {self.main: None}
self.killed = 0
self.value = None
self.terminated_by = None
def create(self, func, *args):
me = _CoEvent(func)
self.invokedby[me] = None
thread.start_new_thread(self._start, (me,) + args)
return me
def _start(self, me, *args):
me.wait()
if not self.killed:
try:
try:
me.f(*args)
except Killed:
pass
finally:
if not self.killed:
self.terminated_by = me
self.kill()
def kill(self):
if self.killed:
raise TypeError('kill() called on dead coroutines')
self.killed = 1
for coroutine in self.invokedby.keys():
coroutine.resume()
def back(self, data=None):
return self.tran( self.invokedby[self.active], data )
def detach(self, data=None):
return self.tran( self.main, data )
def tran(self, target, data=None):
if target not in self.invokedby:
raise TypeError('.tran target %r is not an active coroutine' % (target,))
if self.killed:
raise TypeError('.tran target %r is killed' % (target,))
self.value = data
me = self.active
self.invokedby[target] = me
self.active = target
target.resume()
me.wait()
if self.killed:
if self.main is not me:
raise Killed
if self.terminated_by is not None:
raise EarlyExit('%r terminated early' % (self.terminated_by,))
return self.value
# end of module

View File

@ -1,92 +0,0 @@
# Generator implementation using threads
import _thread as thread
import sys
class Killed(Exception):
pass
class Generator:
# Constructor
def __init__(self, func, args):
self.getlock = thread.allocate_lock()
self.putlock = thread.allocate_lock()
self.getlock.acquire()
self.putlock.acquire()
self.func = func
self.args = args
self.done = 0
self.killed = 0
thread.start_new_thread(self._start, ())
# Internal routine
def _start(self):
try:
self.putlock.acquire()
if not self.killed:
try:
self.func(self, *self.args)
except Killed:
pass
finally:
if not self.killed:
self.done = 1
self.getlock.release()
# Called by producer for each value; raise Killed if no more needed
def put(self, value):
if self.killed:
raise TypeError('put() called on killed generator')
self.value = value
self.getlock.release() # Resume consumer thread
self.putlock.acquire() # Wait for next get() call
if self.killed:
raise Killed
# Called by producer to get next value; raise EOFError if no more
def get(self):
if self.killed:
raise TypeError('get() called on killed generator')
self.putlock.release() # Resume producer thread
self.getlock.acquire() # Wait for value to appear
if self.done:
raise EOFError # Say there are no more values
return self.value
# Called by consumer if no more values wanted
def kill(self):
if self.killed:
raise TypeError('kill() called on killed generator')
self.killed = 1
self.putlock.release()
# Clone constructor
def clone(self):
return Generator(self.func, self.args)
def pi(g):
k, a, b, a1, b1 = 2, 4, 1, 12, 4
while 1:
# Next approximation
p, q, k = k*k, 2*k+1, k+1
a, b, a1, b1 = a1, b1, p*a+q*a1, p*b+q*b1
# Print common digits
d, d1 = a//b, a1//b1
while d == d1:
g.put(int(d))
a, a1 = 10*(a%b), 10*(a1%b1)
d, d1 = a//b, a1//b1
def test():
g = Generator(pi, ())
g.kill()
g = Generator(pi, ())
for i in range(10): print(g.get(), end=' ')
print()
h = g.clone()
g.kill()
while 1:
print(h.get(), end=' ')
sys.stdout.flush()
test()

View File

@ -1,11 +0,0 @@
This directory contains some demonstrations of the thread module.
These are mostly "proof of concept" type applications:
Generator.py Generator class implemented with threads.
sync.py Condition variables primitives by Tim Peters.
telnet.py Version of ../sockets/telnet.py using threads.
Coroutine.py Coroutines using threads, by Tim Peters (22 May 94)
fcmp.py Example of above, by Tim
squasher.py Another example of above, also by Tim

View File

@ -1,64 +0,0 @@
# Coroutine example: controlling multiple instances of a single function
from Coroutine import *
# fringe visits a nested list in inorder, and detaches for each non-list
# element; raises EarlyExit after the list is exhausted
def fringe(co, list):
for x in list:
if type(x) is type([]):
fringe(co, x)
else:
co.back(x)
def printinorder(list):
co = Coroutine()
f = co.create(fringe, co, list)
try:
while 1:
print(co.tran(f), end=' ')
except EarlyExit:
pass
print()
printinorder([1,2,3]) # 1 2 3
printinorder([[[[1,[2]]],3]]) # ditto
x = [0, 1, [2, [3]], [4,5], [[[6]]] ]
printinorder(x) # 0 1 2 3 4 5 6
# fcmp lexicographically compares the fringes of two nested lists
def fcmp(l1, l2):
co1 = Coroutine(); f1 = co1.create(fringe, co1, l1)
co2 = Coroutine(); f2 = co2.create(fringe, co2, l2)
while 1:
try:
v1 = co1.tran(f1)
except EarlyExit:
try:
v2 = co2.tran(f2)
except EarlyExit:
return 0
co2.kill()
return -1
try:
v2 = co2.tran(f2)
except EarlyExit:
co1.kill()
return 1
if v1 != v2:
co1.kill(); co2.kill()
return cmp(v1,v2)
print(fcmp(range(7), x)) # 0; fringes are equal
print(fcmp(range(6), x)) # -1; 1st list ends early
print(fcmp(x, range(6))) # 1; 2nd list ends early
print(fcmp(range(8), x)) # 1; 2nd list ends early
print(fcmp(x, range(8))) # -1; 1st list ends early
print(fcmp([1,[[2],8]],
[[[1],2],8])) # 0
print(fcmp([1,[[3],8]],
[[[1],2],8])) # 1
print(fcmp([1,[[2],8]],
[[[1],2],9])) # -1
# end of example

View File

@ -1,154 +0,0 @@
# A parallelized "find(1)" using the thread module.
# This demonstrates the use of a work queue and worker threads.
# It really does do more stats/sec when using multiple threads,
# although the improvement is only about 20-30 percent.
# (That was 8 years ago. In 2002, on Linux, I can't measure
# a speedup. :-( )
# I'm too lazy to write a command line parser for the full find(1)
# command line syntax, so the predicate it searches for is wired-in,
# see function selector() below. (It currently searches for files with
# world write permission.)
# Usage: parfind.py [-w nworkers] [directory] ...
# Default nworkers is 4
import sys
import getopt
import time
import os
from stat import *
import _thread as thread
# Work queue class. Usage:
# wq = WorkQ()
# wq.addwork(func, (arg1, arg2, ...)) # one or more calls
# wq.run(nworkers)
# The work is done when wq.run() completes.
# The function calls executed by the workers may add more work.
# Don't use keyboard interrupts!
class WorkQ:
# Invariants:
# - busy and work are only modified when mutex is locked
# - len(work) is the number of jobs ready to be taken
# - busy is the number of jobs being done
# - todo is locked iff there is no work and somebody is busy
def __init__(self):
self.mutex = thread.allocate()
self.todo = thread.allocate()
self.todo.acquire()
self.work = []
self.busy = 0
def addwork(self, func, args):
job = (func, args)
self.mutex.acquire()
self.work.append(job)
self.mutex.release()
if len(self.work) == 1:
self.todo.release()
def _getwork(self):
self.todo.acquire()
self.mutex.acquire()
if self.busy == 0 and len(self.work) == 0:
self.mutex.release()
self.todo.release()
return None
job = self.work[0]
del self.work[0]
self.busy = self.busy + 1
self.mutex.release()
if len(self.work) > 0:
self.todo.release()
return job
def _donework(self):
self.mutex.acquire()
self.busy = self.busy - 1
if self.busy == 0 and len(self.work) == 0:
self.todo.release()
self.mutex.release()
def _worker(self):
time.sleep(0.00001) # Let other threads run
while 1:
job = self._getwork()
if not job:
break
func, args = job
func(*args)
self._donework()
def run(self, nworkers):
if not self.work:
return # Nothing to do
for i in range(nworkers-1):
thread.start_new(self._worker, ())
self._worker()
self.todo.acquire()
# Main program
def main():
nworkers = 4
opts, args = getopt.getopt(sys.argv[1:], '-w:')
for opt, arg in opts:
if opt == '-w':
nworkers = int(arg)
if not args:
args = [os.curdir]
wq = WorkQ()
for dir in args:
wq.addwork(find, (dir, selector, wq))
t1 = time.time()
wq.run(nworkers)
t2 = time.time()
sys.stderr.write('Total time %r sec.\n' % (t2-t1))
# The predicate -- defines what files we look for.
# Feel free to change this to suit your purpose
def selector(dir, name, fullname, stat):
# Look for world writable files that are not symlinks
return (stat[ST_MODE] & 0o002) != 0 and not S_ISLNK(stat[ST_MODE])
# The find procedure -- calls wq.addwork() for subdirectories
def find(dir, pred, wq):
try:
names = os.listdir(dir)
except os.error as msg:
print(repr(dir), ':', msg)
return
for name in names:
if name not in (os.curdir, os.pardir):
fullname = os.path.join(dir, name)
try:
stat = os.lstat(fullname)
except os.error as msg:
print(repr(fullname), ':', msg)
continue
if pred(dir, name, fullname, stat):
print(fullname)
if S_ISDIR(stat[ST_MODE]):
if not os.path.ismount(fullname):
wq.addwork(find, (fullname, pred, wq))
# Call the main program
main()

View File

@ -1,105 +0,0 @@
# Coroutine example: general coroutine transfers
#
# The program is a variation of a Simula 67 program due to Dahl & Hoare,
# (Dahl/Dijkstra/Hoare, Structured Programming; Academic Press, 1972)
# who in turn credit the original example to Conway.
#
# We have a number of input lines, terminated by a 0 byte. The problem
# is to squash them together into output lines containing 72 characters
# each. A semicolon must be added between input lines. Runs of blanks
# and tabs in input lines must be squashed into single blanks.
# Occurrences of "**" in input lines must be replaced by "^".
#
# Here's a test case:
test = """\
d = sqrt(b**2 - 4*a*c)
twoa = 2*a
L = -b/twoa
R = d/twoa
A1 = L + R
A2 = L - R\0
"""
# The program should print:
# d = sqrt(b^2 - 4*a*c);twoa = 2*a; L = -b/twoa; R = d/twoa; A1 = L + R;
#A2 = L - R
#done
# getline: delivers the next input line to its invoker
# disassembler: grabs input lines from getline, and delivers them one
# character at a time to squasher, also inserting a semicolon into
# the stream between lines
# squasher: grabs characters from disassembler and passes them on to
# assembler, first replacing "**" with "^" and squashing runs of
# whitespace
# assembler: grabs characters from squasher and packs them into lines
# with 72 character each, delivering each such line to putline;
# when it sees a null byte, passes the last line to putline and
# then kills all the coroutines
# putline: grabs lines from assembler, and just prints them
from Coroutine import *
def getline(text):
for line in string.splitfields(text, '\n'):
co.tran(codisassembler, line)
def disassembler():
while 1:
card = co.tran(cogetline)
for i in range(len(card)):
co.tran(cosquasher, card[i])
co.tran(cosquasher, ';')
def squasher():
while 1:
ch = co.tran(codisassembler)
if ch == '*':
ch2 = co.tran(codisassembler)
if ch2 == '*':
ch = '^'
else:
co.tran(coassembler, ch)
ch = ch2
if ch in ' \t':
while 1:
ch2 = co.tran(codisassembler)
if ch2 not in ' \t':
break
co.tran(coassembler, ' ')
ch = ch2
co.tran(coassembler, ch)
def assembler():
line = ''
while 1:
ch = co.tran(cosquasher)
if ch == '\0':
break
if len(line) == 72:
co.tran(coputline, line)
line = ''
line = line + ch
line = line + ' ' * (72 - len(line))
co.tran(coputline, line)
co.kill()
def putline():
while 1:
line = co.tran(coassembler)
print(line)
import string
co = Coroutine()
cogetline = co.create(getline, test)
coputline = co.create(putline)
coassembler = co.create(assembler)
codisassembler = co.create(disassembler)
cosquasher = co.create(squasher)
co.tran(coputline)
print('done')
# end of example

View File

@ -1,599 +0,0 @@
# Defines classes that provide synchronization objects. Note that use of
# this module requires that your Python support threads.
#
# condition(lock=None) # a POSIX-like condition-variable object
# barrier(n) # an n-thread barrier
# event() # an event object
# semaphore(n=1) # a semaphore object, with initial count n
# mrsw() # a multiple-reader single-writer lock
#
# CONDITIONS
#
# A condition object is created via
# import this_module
# your_condition_object = this_module.condition(lock=None)
#
# As explained below, a condition object has a lock associated with it,
# used in the protocol to protect condition data. You can specify a
# lock to use in the constructor, else the constructor will allocate
# an anonymous lock for you. Specifying a lock explicitly can be useful
# when more than one condition keys off the same set of shared data.
#
# Methods:
# .acquire()
# acquire the lock associated with the condition
# .release()
# release the lock associated with the condition
# .wait()
# block the thread until such time as some other thread does a
# .signal or .broadcast on the same condition, and release the
# lock associated with the condition. The lock associated with
# the condition MUST be in the acquired state at the time
# .wait is invoked.
# .signal()
# wake up exactly one thread (if any) that previously did a .wait
# on the condition; that thread will awaken with the lock associated
# with the condition in the acquired state. If no threads are
# .wait'ing, this is a nop. If more than one thread is .wait'ing on
# the condition, any of them may be awakened.
# .broadcast()
# wake up all threads (if any) that are .wait'ing on the condition;
# the threads are woken up serially, each with the lock in the
# acquired state, so should .release() as soon as possible. If no
# threads are .wait'ing, this is a nop.
#
# Note that if a thread does a .wait *while* a signal/broadcast is
# in progress, it's guaranteeed to block until a subsequent
# signal/broadcast.
#
# Secret feature: `broadcast' actually takes an integer argument,
# and will wake up exactly that many waiting threads (or the total
# number waiting, if that's less). Use of this is dubious, though,
# and probably won't be supported if this form of condition is
# reimplemented in C.
#
# DIFFERENCES FROM POSIX
#
# + A separate mutex is not needed to guard condition data. Instead, a
# condition object can (must) be .acquire'ed and .release'ed directly.
# This eliminates a common error in using POSIX conditions.
#
# + Because of implementation difficulties, a POSIX `signal' wakes up
# _at least_ one .wait'ing thread. Race conditions make it difficult
# to stop that. This implementation guarantees to wake up only one,
# but you probably shouldn't rely on that.
#
# PROTOCOL
#
# Condition objects are used to block threads until "some condition" is
# true. E.g., a thread may wish to wait until a producer pumps out data
# for it to consume, or a server may wish to wait until someone requests
# its services, or perhaps a whole bunch of threads want to wait until a
# preceding pass over the data is complete. Early models for conditions
# relied on some other thread figuring out when a blocked thread's
# condition was true, and made the other thread responsible both for
# waking up the blocked thread and guaranteeing that it woke up with all
# data in a correct state. This proved to be very delicate in practice,
# and gave conditions a bad name in some circles.
#
# The POSIX model addresses these problems by making a thread responsible
# for ensuring that its own state is correct when it wakes, and relies
# on a rigid protocol to make this easy; so long as you stick to the
# protocol, POSIX conditions are easy to "get right":
#
# A) The thread that's waiting for some arbitrarily-complex condition
# (ACC) to become true does:
#
# condition.acquire()
# while not (code to evaluate the ACC):
# condition.wait()
# # That blocks the thread, *and* releases the lock. When a
# # condition.signal() happens, it will wake up some thread that
# # did a .wait, *and* acquire the lock again before .wait
# # returns.
# #
# # Because the lock is acquired at this point, the state used
# # in evaluating the ACC is frozen, so it's safe to go back &
# # reevaluate the ACC.
#
# # At this point, ACC is true, and the thread has the condition
# # locked.
# # So code here can safely muck with the shared state that
# # went into evaluating the ACC -- if it wants to.
# # When done mucking with the shared state, do
# condition.release()
#
# B) Threads that are mucking with shared state that may affect the
# ACC do:
#
# condition.acquire()
# # muck with shared state
# condition.release()
# if it's possible that ACC is true now:
# condition.signal() # or .broadcast()
#
# Note: You may prefer to put the "if" clause before the release().
# That's fine, but do note that anyone waiting on the signal will
# stay blocked until the release() is done (since acquiring the
# condition is part of what .wait() does before it returns).
#
# TRICK OF THE TRADE
#
# With simpler forms of conditions, it can be impossible to know when
# a thread that's supposed to do a .wait has actually done it. But
# because this form of condition releases a lock as _part_ of doing a
# wait, the state of that lock can be used to guarantee it.
#
# E.g., suppose thread A spawns thread B and later wants to wait for B to
# complete:
#
# In A: In B:
#
# B_done = condition() ... do work ...
# B_done.acquire() B_done.acquire(); B_done.release()
# spawn B B_done.signal()
# ... some time later ... ... and B exits ...
# B_done.wait()
#
# Because B_done was in the acquire'd state at the time B was spawned,
# B's attempt to acquire B_done can't succeed until A has done its
# B_done.wait() (which releases B_done). So B's B_done.signal() is
# guaranteed to be seen by the .wait(). Without the lock trick, B
# may signal before A .waits, and then A would wait forever.
#
# BARRIERS
#
# A barrier object is created via
# import this_module
# your_barrier = this_module.barrier(num_threads)
#
# Methods:
# .enter()
# the thread blocks until num_threads threads in all have done
# .enter(). Then the num_threads threads that .enter'ed resume,
# and the barrier resets to capture the next num_threads threads
# that .enter it.
#
# EVENTS
#
# An event object is created via
# import this_module
# your_event = this_module.event()
#
# An event has two states, `posted' and `cleared'. An event is
# created in the cleared state.
#
# Methods:
#
# .post()
# Put the event in the posted state, and resume all threads
# .wait'ing on the event (if any).
#
# .clear()
# Put the event in the cleared state.
#
# .is_posted()
# Returns 0 if the event is in the cleared state, or 1 if the event
# is in the posted state.
#
# .wait()
# If the event is in the posted state, returns immediately.
# If the event is in the cleared state, blocks the calling thread
# until the event is .post'ed by another thread.
#
# Note that an event, once posted, remains posted until explicitly
# cleared. Relative to conditions, this is both the strength & weakness
# of events. It's a strength because the .post'ing thread doesn't have to
# worry about whether the threads it's trying to communicate with have
# already done a .wait (a condition .signal is seen only by threads that
# do a .wait _prior_ to the .signal; a .signal does not persist). But
# it's a weakness because .clear'ing an event is error-prone: it's easy
# to mistakenly .clear an event before all the threads you intended to
# see the event get around to .wait'ing on it. But so long as you don't
# need to .clear an event, events are easy to use safely.
#
# SEMAPHORES
#
# A semaphore object is created via
# import this_module
# your_semaphore = this_module.semaphore(count=1)
#
# A semaphore has an integer count associated with it. The initial value
# of the count is specified by the optional argument (which defaults to
# 1) passed to the semaphore constructor.
#
# Methods:
#
# .p()
# If the semaphore's count is greater than 0, decrements the count
# by 1 and returns.
# Else if the semaphore's count is 0, blocks the calling thread
# until a subsequent .v() increases the count. When that happens,
# the count will be decremented by 1 and the calling thread resumed.
#
# .v()
# Increments the semaphore's count by 1, and wakes up a thread (if
# any) blocked by a .p(). It's an (detected) error for a .v() to
# increase the semaphore's count to a value larger than the initial
# count.
#
# MULTIPLE-READER SINGLE-WRITER LOCKS
#
# A mrsw lock is created via
# import this_module
# your_mrsw_lock = this_module.mrsw()
#
# This kind of lock is often useful with complex shared data structures.
# The object lets any number of "readers" proceed, so long as no thread
# wishes to "write". When a (one or more) thread declares its intention
# to "write" (e.g., to update a shared structure), all current readers
# are allowed to finish, and then a writer gets exclusive access; all
# other readers & writers are blocked until the current writer completes.
# Finally, if some thread is waiting to write and another is waiting to
# read, the writer takes precedence.
#
# Methods:
#
# .read_in()
# If no thread is writing or waiting to write, returns immediately.
# Else blocks until no thread is writing or waiting to write. So
# long as some thread has completed a .read_in but not a .read_out,
# writers are blocked.
#
# .read_out()
# Use sometime after a .read_in to declare that the thread is done
# reading. When all threads complete reading, a writer can proceed.
#
# .write_in()
# If no thread is writing (has completed a .write_in, but hasn't yet
# done a .write_out) or reading (similarly), returns immediately.
# Else blocks the calling thread, and threads waiting to read, until
# the current writer completes writing or all the current readers
# complete reading; if then more than one thread is waiting to
# write, one of them is allowed to proceed, but which one is not
# specified.
#
# .write_out()
# Use sometime after a .write_in to declare that the thread is done
# writing. Then if some other thread is waiting to write, it's
# allowed to proceed. Else all threads (if any) waiting to read are
# allowed to proceed.
#
# .write_to_read()
# Use instead of a .write_in to declare that the thread is done
# writing but wants to continue reading without other writers
# intervening. If there are other threads waiting to write, they
# are allowed to proceed only if the current thread calls
# .read_out; threads waiting to read are only allowed to proceed
# if there are are no threads waiting to write. (This is a
# weakness of the interface!)
import _thread as thread
class condition:
def __init__(self, lock=None):
# the lock actually used by .acquire() and .release()
if lock is None:
self.mutex = thread.allocate_lock()
else:
if hasattr(lock, 'acquire') and \
hasattr(lock, 'release'):
self.mutex = lock
else:
raise TypeError('condition constructor requires ' \
'a lock argument')
# lock used to block threads until a signal
self.checkout = thread.allocate_lock()
self.checkout.acquire()
# internal critical-section lock, & the data it protects
self.idlock = thread.allocate_lock()
self.id = 0
self.waiting = 0 # num waiters subject to current release
self.pending = 0 # num waiters awaiting next signal
self.torelease = 0 # num waiters to release
self.releasing = 0 # 1 iff release is in progress
def acquire(self):
self.mutex.acquire()
def release(self):
self.mutex.release()
def wait(self):
mutex, checkout, idlock = self.mutex, self.checkout, self.idlock
if not mutex.locked():
raise ValueError("condition must be .acquire'd when .wait() invoked")
idlock.acquire()
myid = self.id
self.pending = self.pending + 1
idlock.release()
mutex.release()
while 1:
checkout.acquire(); idlock.acquire()
if myid < self.id:
break
checkout.release(); idlock.release()
self.waiting = self.waiting - 1
self.torelease = self.torelease - 1
if self.torelease:
checkout.release()
else:
self.releasing = 0
if self.waiting == self.pending == 0:
self.id = 0
idlock.release()
mutex.acquire()
def signal(self):
self.broadcast(1)
def broadcast(self, num = -1):
if num < -1:
raise ValueError('.broadcast called with num %r' % (num,))
if num == 0:
return
self.idlock.acquire()
if self.pending:
self.waiting = self.waiting + self.pending
self.pending = 0
self.id = self.id + 1
if num == -1:
self.torelease = self.waiting
else:
self.torelease = min( self.waiting,
self.torelease + num )
if self.torelease and not self.releasing:
self.releasing = 1
self.checkout.release()
self.idlock.release()
class barrier:
def __init__(self, n):
self.n = n
self.togo = n
self.full = condition()
def enter(self):
full = self.full
full.acquire()
self.togo = self.togo - 1
if self.togo:
full.wait()
else:
self.togo = self.n
full.broadcast()
full.release()
class event:
def __init__(self):
self.state = 0
self.posted = condition()
def post(self):
self.posted.acquire()
self.state = 1
self.posted.broadcast()
self.posted.release()
def clear(self):
self.posted.acquire()
self.state = 0
self.posted.release()
def is_posted(self):
self.posted.acquire()
answer = self.state
self.posted.release()
return answer
def wait(self):
self.posted.acquire()
if not self.state:
self.posted.wait()
self.posted.release()
class semaphore:
def __init__(self, count=1):
if count <= 0:
raise ValueError('semaphore count %d; must be >= 1' % count)
self.count = count
self.maxcount = count
self.nonzero = condition()
def p(self):
self.nonzero.acquire()
while self.count == 0:
self.nonzero.wait()
self.count = self.count - 1
self.nonzero.release()
def v(self):
self.nonzero.acquire()
if self.count == self.maxcount:
raise ValueError('.v() tried to raise semaphore count above ' \
'initial value %r' % self.maxcount)
self.count = self.count + 1
self.nonzero.signal()
self.nonzero.release()
class mrsw:
def __init__(self):
# critical-section lock & the data it protects
self.rwOK = thread.allocate_lock()
self.nr = 0 # number readers actively reading (not just waiting)
self.nw = 0 # number writers either waiting to write or writing
self.writing = 0 # 1 iff some thread is writing
# conditions
self.readOK = condition(self.rwOK) # OK to unblock readers
self.writeOK = condition(self.rwOK) # OK to unblock writers
def read_in(self):
self.rwOK.acquire()
while self.nw:
self.readOK.wait()
self.nr = self.nr + 1
self.rwOK.release()
def read_out(self):
self.rwOK.acquire()
if self.nr <= 0:
raise ValueError('.read_out() invoked without an active reader')
self.nr = self.nr - 1
if self.nr == 0:
self.writeOK.signal()
self.rwOK.release()
def write_in(self):
self.rwOK.acquire()
self.nw = self.nw + 1
while self.writing or self.nr:
self.writeOK.wait()
self.writing = 1
self.rwOK.release()
def write_out(self):
self.rwOK.acquire()
if not self.writing:
raise ValueError('.write_out() invoked without an active writer')
self.writing = 0
self.nw = self.nw - 1
if self.nw:
self.writeOK.signal()
else:
self.readOK.broadcast()
self.rwOK.release()
def write_to_read(self):
self.rwOK.acquire()
if not self.writing:
raise ValueError('.write_to_read() invoked without an active writer')
self.writing = 0
self.nw = self.nw - 1
self.nr = self.nr + 1
if not self.nw:
self.readOK.broadcast()
self.rwOK.release()
# The rest of the file is a test case, that runs a number of parallelized
# quicksorts in parallel. If it works, you'll get about 600 lines of
# tracing output, with a line like
# test passed! 209 threads created in all
# as the last line. The content and order of preceding lines will
# vary across runs.
def _new_thread(func, *args):
global TID
tid.acquire(); id = TID = TID+1; tid.release()
io.acquire(); alive.append(id); \
print('starting thread', id, '--', len(alive), 'alive'); \
io.release()
thread.start_new_thread( func, (id,) + args )
def _qsort(tid, a, l, r, finished):
# sort a[l:r]; post finished when done
io.acquire(); print('thread', tid, 'qsort', l, r); io.release()
if r-l > 1:
pivot = a[l]
j = l+1 # make a[l:j] <= pivot, and a[j:r] > pivot
for i in range(j, r):
if a[i] <= pivot:
a[j], a[i] = a[i], a[j]
j = j + 1
a[l], a[j-1] = a[j-1], pivot
l_subarray_sorted = event()
r_subarray_sorted = event()
_new_thread(_qsort, a, l, j-1, l_subarray_sorted)
_new_thread(_qsort, a, j, r, r_subarray_sorted)
l_subarray_sorted.wait()
r_subarray_sorted.wait()
io.acquire(); print('thread', tid, 'qsort done'); \
alive.remove(tid); io.release()
finished.post()
def _randarray(tid, a, finished):
io.acquire(); print('thread', tid, 'randomizing array'); \
io.release()
for i in range(1, len(a)):
wh.acquire(); j = randint(0,i); wh.release()
a[i], a[j] = a[j], a[i]
io.acquire(); print('thread', tid, 'randomizing done'); \
alive.remove(tid); io.release()
finished.post()
def _check_sort(a):
if a != range(len(a)):
raise ValueError('a not sorted', a)
def _run_one_sort(tid, a, bar, done):
# randomize a, and quicksort it
# for variety, all the threads running this enter a barrier
# at the end, and post `done' after the barrier exits
io.acquire(); print('thread', tid, 'randomizing', a); \
io.release()
finished = event()
_new_thread(_randarray, a, finished)
finished.wait()
io.acquire(); print('thread', tid, 'sorting', a); io.release()
finished.clear()
_new_thread(_qsort, a, 0, len(a), finished)
finished.wait()
_check_sort(a)
io.acquire(); print('thread', tid, 'entering barrier'); \
io.release()
bar.enter()
io.acquire(); print('thread', tid, 'leaving barrier'); \
io.release()
io.acquire(); alive.remove(tid); io.release()
bar.enter() # make sure they've all removed themselves from alive
## before 'done' is posted
bar.enter() # just to be cruel
done.post()
def test():
global TID, tid, io, wh, randint, alive
import random
randint = random.randint
TID = 0 # thread ID (1, 2, ...)
tid = thread.allocate_lock() # for changing TID
io = thread.allocate_lock() # for printing, and 'alive'
wh = thread.allocate_lock() # for calls to random
alive = [] # IDs of active threads
NSORTS = 5
arrays = []
for i in range(NSORTS):
arrays.append( range( (i+1)*10 ) )
bar = barrier(NSORTS)
finished = event()
for i in range(NSORTS):
_new_thread(_run_one_sort, arrays[i], bar, finished)
finished.wait()
print('all threads done, and checking results ...')
if alive:
raise ValueError('threads still alive at end', alive)
for i in range(NSORTS):
a = arrays[i]
if len(a) != (i+1)*10:
raise ValueError('length of array', i, 'screwed up')
_check_sort(a)
print('test passed!', TID, 'threads created in all')
if __name__ == '__main__':
test()
# end of module

View File

@ -1,114 +0,0 @@
# Minimal interface to the Internet telnet protocol.
#
# *** modified to use threads ***
#
# It refuses all telnet options and does not recognize any of the other
# telnet commands, but can still be used to connect in line-by-line mode.
# It's also useful to play with a number of other services,
# like time, finger, smtp and even ftp.
#
# Usage: telnet host [port]
#
# The port may be a service name or a decimal port number;
# it defaults to 'telnet'.
import sys, os, time
from socket import *
import _thread as thread
BUFSIZE = 8*1024
# Telnet protocol characters
IAC = chr(255) # Interpret as command
DONT = chr(254)
DO = chr(253)
WONT = chr(252)
WILL = chr(251)
def main():
if len(sys.argv) < 2:
sys.stderr.write('usage: telnet hostname [port]\n')
sys.exit(2)
host = sys.argv[1]
try:
hostaddr = gethostbyname(host)
except error:
sys.stderr.write(sys.argv[1] + ': bad host name\n')
sys.exit(2)
#
if len(sys.argv) > 2:
servname = sys.argv[2]
else:
servname = 'telnet'
#
if '0' <= servname[:1] <= '9':
port = eval(servname)
else:
try:
port = getservbyname(servname, 'tcp')
except error:
sys.stderr.write(servname + ': bad tcp service name\n')
sys.exit(2)
#
s = socket(AF_INET, SOCK_STREAM)
#
try:
s.connect((host, port))
except error as msg:
sys.stderr.write('connect failed: %r\n' % (msg,))
sys.exit(1)
#
thread.start_new(child, (s,))
parent(s)
def parent(s):
# read socket, write stdout
iac = 0 # Interpret next char as command
opt = '' # Interpret next char as option
while 1:
data, dummy = s.recvfrom(BUFSIZE)
if not data:
# EOF -- exit
sys.stderr.write( '(Closed by remote host)\n')
sys.exit(1)
cleandata = ''
for c in data:
if opt:
print(ord(c))
## print '(replying: %r)' % (opt+c,)
s.send(opt + c)
opt = ''
elif iac:
iac = 0
if c == IAC:
cleandata = cleandata + c
elif c in (DO, DONT):
if c == DO: print('(DO)', end=' ')
else: print('(DONT)', end=' ')
opt = IAC + WONT
elif c in (WILL, WONT):
if c == WILL: print('(WILL)', end=' ')
else: print('(WONT)', end=' ')
opt = IAC + DONT
else:
print('(command)', ord(c))
elif c == IAC:
iac = 1
print('(IAC)', end=' ')
else:
cleandata = cleandata + c
sys.stdout.write(cleandata)
sys.stdout.flush()
## print 'Out:', repr(cleandata)
def child(s):
# read stdin, write socket
while 1:
line = sys.stdin.readline()
## print 'Got:', repr(line)
if not line: break
s.send(line)
main()

View File

@ -1,42 +0,0 @@
"""
A simple demo that reads in an XML document and displays the number of
elements and attributes as well as a tally of elements and attributes by name.
"""
import sys
from collections import defaultdict
from xml.sax import make_parser, handler
class FancyCounter(handler.ContentHandler):
def __init__(self):
self._elems = 0
self._attrs = 0
self._elem_types = defaultdict(int)
self._attr_types = defaultdict(int)
def startElement(self, name, attrs):
self._elems += 1
self._attrs += len(attrs)
self._elem_types[name] += 1
for name in attrs.keys():
self._attr_types[name] += 1
def endDocument(self):
print("There were", self._elems, "elements.")
print("There were", self._attrs, "attributes.")
print("---ELEMENT TYPES")
for pair in self._elem_types.items():
print("%20s %d" % pair)
print("---ATTRIBUTE TYPES")
for pair in self._attr_types.items():
print("%20s %d" % pair)
if __name__ == '__main__':
parser = make_parser()
parser.setContentHandler(FancyCounter())
parser.parse(sys.argv[1])

View File

@ -1,46 +0,0 @@
"""
A simple demo that reads in an XML document and spits out an equivalent,
but not necessarily identical, document.
"""
import sys
from xml.sax import saxutils, handler, make_parser
# --- The ContentHandler
class ContentGenerator(handler.ContentHandler):
def __init__(self, out=sys.stdout):
handler.ContentHandler.__init__(self)
self._out = out
# ContentHandler methods
def startDocument(self):
self._out.write('<?xml version="1.0" encoding="iso-8859-1"?>\n')
def startElement(self, name, attrs):
self._out.write('<' + name)
for (name, value) in attrs.items():
self._out.write(' %s="%s"' % (name, saxutils.escape(value)))
self._out.write('>')
def endElement(self, name):
self._out.write('</%s>' % name)
def characters(self, content):
self._out.write(saxutils.escape(content))
def ignorableWhitespace(self, content):
self._out.write(content)
def processingInstruction(self, target, data):
self._out.write('<?%s %s?>' % (target, data))
# --- The main program
if __name__ == '__main__':
parser = make_parser()
parser.setContentHandler(ContentGenerator())
parser.parse(sys.argv[1])

View File

@ -1,97 +0,0 @@
"""
A demo that reads in an RSS XML document and emits an HTML file containing
a list of the individual items in the feed.
"""
import sys
import codecs
from xml.sax import make_parser, handler
# --- Templates
top = """\
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>%s</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<h1>%s</h1>
"""
bottom = """
</ul>
<hr>
<address>
Converted to HTML by rss2html.py.
</address>
</body>
</html>
"""
# --- The ContentHandler
class RSSHandler(handler.ContentHandler):
def __init__(self, out=sys.stdout):
handler.ContentHandler.__init__(self)
self._out = out
self._text = ""
self._parent = None
self._list_started = False
self._title = None
self._link = None
self._descr = ""
# ContentHandler methods
def startElement(self, name, attrs):
if name == "channel" or name == "image" or name == "item":
self._parent = name
self._text = ""
def endElement(self, name):
if self._parent == "channel":
if name == "title":
self._out.write(top % (self._text, self._text))
elif name == "description":
self._out.write("<p>%s</p>\n" % self._text)
elif self._parent == "item":
if name == "title":
self._title = self._text
elif name == "link":
self._link = self._text
elif name == "description":
self._descr = self._text
elif name == "item":
if not self._list_started:
self._out.write("<ul>\n")
self._list_started = True
self._out.write(' <li><a href="%s">%s</a> %s\n' %
(self._link, self._title, self._descr))
self._title = None
self._link = None
self._descr = ""
if name == "rss":
self._out.write(bottom)
def characters(self, content):
self._text = self._text + content
# --- Main program
if __name__ == '__main__':
parser = make_parser()
parser.setContentHandler(RSSHandler())
parser.parse(sys.argv[1])

View File

@ -1,134 +0,0 @@
#!/usr/bin/env python3
# Demo program for zlib; it compresses or decompresses files, but *doesn't*
# delete the original. This doesn't support all of gzip's options.
#
# The 'gzip' module in the standard library provides a more complete
# implementation of gzip-format files.
import zlib, sys, os
FTEXT, FHCRC, FEXTRA, FNAME, FCOMMENT = 1, 2, 4, 8, 16
def write32(output, value):
output.write(bytes([value & 255])) ; value=value // 256
output.write(bytes([value & 255])) ; value=value // 256
output.write(bytes([value & 255])) ; value=value // 256
output.write(bytes([value & 255]))
def read32(input):
v = ord(input.read(1))
v += (ord(input.read(1)) << 8 )
v += (ord(input.read(1)) << 16)
v += (ord(input.read(1)) << 24)
return v
def compress(filename, input, output):
output.write(b'\037\213\010') # Write the header, ...
output.write(bytes([FNAME])) # ... flag byte ...
statval = os.stat(filename) # ... modification time ...
mtime = statval[8]
write32(output, mtime)
output.write(b'\002') # ... slowest compression alg. ...
output.write(b'\377') # ... OS (=unknown) ...
bfilename = os.fsencode(filename)
output.write(bfilename + b'\000') # ... original filename ...
crcval = zlib.crc32(b'')
compobj = zlib.compressobj(9, zlib.DEFLATED, -zlib.MAX_WBITS,
zlib.DEF_MEM_LEVEL, 0)
while True:
data = input.read(1024)
if data == b'':
break
crcval = zlib.crc32(data, crcval)
output.write(compobj.compress(data))
output.write(compobj.flush())
write32(output, crcval) # ... the CRC ...
write32(output, statval[6]) # and the file size.
def decompress(input, output):
magic = input.read(2)
if magic != b'\037\213':
print('Not a gzipped file')
sys.exit(0)
if ord(input.read(1)) != 8:
print('Unknown compression method')
sys.exit(0)
flag = ord(input.read(1))
input.read(4+1+1) # Discard modification time,
# extra flags, and OS byte.
if flag & FEXTRA:
# Read & discard the extra field, if present
xlen = ord(input.read(1))
xlen += 256*ord(input.read(1))
input.read(xlen)
if flag & FNAME:
# Read and discard a null-terminated string containing the filename
while True:
s = input.read(1)
if s == b'\0': break
if flag & FCOMMENT:
# Read and discard a null-terminated string containing a comment
while True:
s = input.read(1)
if s == b'\0': break
if flag & FHCRC:
input.read(2) # Read & discard the 16-bit header CRC
decompobj = zlib.decompressobj(-zlib.MAX_WBITS)
crcval = zlib.crc32(b'')
length = 0
while True:
data = input.read(1024)
if data == b"":
break
decompdata = decompobj.decompress(data)
output.write(decompdata)
length += len(decompdata)
crcval = zlib.crc32(decompdata, crcval)
decompdata = decompobj.flush()
output.write(decompdata)
length += len(decompdata)
crcval = zlib.crc32(decompdata, crcval)
# We've read to the end of the file, so we have to rewind in order
# to reread the 8 bytes containing the CRC and the file size. The
# decompressor is smart and knows when to stop, so feeding it
# extra data is harmless.
input.seek(-8, 2)
crc32 = read32(input)
isize = read32(input)
if crc32 != crcval:
print('CRC check failed.')
if isize != length:
print('Incorrect length of data produced')
def main():
if len(sys.argv)!=2:
print('Usage: minigzip.py <filename>')
print(' The file will be compressed or decompressed.')
sys.exit(0)
filename = sys.argv[1]
if filename.endswith('.gz'):
compressing = False
outputname = filename[:-3]
else:
compressing = True
outputname = filename + '.gz'
input = open(filename, 'rb')
output = open(outputname, 'wb')
if compressing:
compress(filename, input, output)
else:
decompress(input, output)
input.close()
output.close()
if __name__ == '__main__':
main()

View File

@ -1,47 +0,0 @@
#!/usr/bin/env python3
# Takes an optional filename, defaulting to this file itself.
# Reads the file and compresses the content using level 1 and level 9
# compression, printing a summary of the results.
import zlib, sys
def main():
if len(sys.argv) > 1:
filename = sys.argv[1]
else:
filename = sys.argv[0]
print('Reading', filename)
with open(filename, 'rb') as f: # Get the data to compress
s = f.read()
# First, we'll compress the string in one step
comptext = zlib.compress(s, 1)
decomp = zlib.decompress(comptext)
print('1-step compression: (level 1)')
print(' Original:', len(s), 'Compressed:', len(comptext), end=' ')
print('Uncompressed:', len(decomp))
# Now, let's compress the string in stages; set chunk to work in smaller steps
chunk = 256
compressor = zlib.compressobj(9)
decompressor = zlib.decompressobj()
comptext = decomp = b''
for i in range(0, len(s), chunk):
comptext += compressor.compress(s[i:i+chunk])
# Don't forget to call flush()!!
comptext += compressor.flush()
for i in range(0, len(comptext), chunk):
decomp += decompressor.decompress(comptext[i:i+chunk])
decomp += decompressor.flush()
print('Progressive compression (level 9):')
print(' Original:', len(s), 'Compressed:', len(comptext), end=' ')
print('Uncompressed:', len(decomp))
if __name__ == '__main__':
main()

View File

@ -45,3 +45,50 @@ The :mod:`pty` module defines the following functions:
a file descriptor. The defaults try to read 1024 bytes each time they are
called.
Example
-------
.. sectionauthor:: Steen Lumholt
The following program acts like the Unix command :manpage:`script(1)`, using a
pseudo-terminal to record all input and output of a terminal session in a
"typescript". ::
import sys, os, time, getopt
import pty
mode = 'wb'
shell = 'sh'
filename = 'typescript'
if 'SHELL' in os.environ:
shell = os.environ['SHELL']
try:
opts, args = getopt.getopt(sys.argv[1:], 'ap')
except getopt.error as msg:
print('%s: %s' % (sys.argv[0], msg))
sys.exit(2)
for opt, arg in opts:
# option -a: append to typescript file
if opt == '-a':
mode = 'ab'
# option -p: use a Python shell as the terminal command
elif opt == '-p':
shell = sys.executable
if args:
filename = args[0]
script = open(filename, mode)
def read(fd):
data = os.read(fd, 1024)
script.write(data)
return data
sys.stdout.write('Script started, file is %s\n' % filename)
script.write(('Script started on %s\n' % time.asctime()).encode())
pty.spawn(shell, read)
script.write(('Script done on %s\n' % time.asctime()).encode())
sys.stdout.write('Script done, file is %s\n' % filename)