mirror of
https://github.com/python/cpython.git
synced 2024-11-27 11:55:13 +08:00
Remove some of the old demos. (Put a few somewhere else.)
This commit is contained in:
parent
d1fc34d563
commit
4cf83f4d12
@ -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
|
@ -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
|
@ -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")
|
@ -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()
|
@ -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()
|
123
Demo/cgi/wiki.py
123
Demo/cgi/wiki.py
@ -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)
|
@ -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
|
@ -1,4 +0,0 @@
|
||||
^def
|
||||
^class
|
||||
^import
|
||||
^from
|
@ -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()
|
@ -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()
|
@ -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()
|
@ -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)
|
@ -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)
|
@ -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)
|
@ -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)
|
@ -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.
|
@ -1 +0,0 @@
|
||||
abc
|
@ -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()
|
@ -1,6 +0,0 @@
|
||||
Demo/parser
|
||||
Doc/libparser.tex
|
||||
Lib/AST.py
|
||||
Lib/symbol.py
|
||||
Lib/token.py
|
||||
Modules/parsermodule.c
|
@ -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!
|
@ -1,2 +0,0 @@
|
||||
"""Some documentation.
|
||||
"""
|
@ -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, '')
|
||||
))
|
@ -1 +0,0 @@
|
||||
def f(): "maybe a docstring"
|
@ -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
|
@ -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()
|
@ -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
|
@ -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
|
@ -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!
|
@ -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);
|
||||
}
|
@ -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()
|
@ -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
|
@ -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/).
|
@ -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)
|
@ -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])
|
@ -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)
|
@ -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()
|
890
Demo/rpc/rpc.py
890
Demo/rpc/rpc.py
@ -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))
|
@ -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()'
|
200
Demo/rpc/xdr.py
200
Demo/rpc/xdr.py
@ -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)
|
@ -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()
|
@ -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()
|
@ -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
|
@ -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()
|
@ -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()
|
@ -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()
|
@ -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
|
||||
----------------------------------------------------------------------
|
@ -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
|
||||
######################################################################
|
@ -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()
|
@ -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)
|
@ -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()
|
@ -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)
|
@ -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()
|
@ -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
|
@ -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()
|
@ -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
|
@ -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
|
@ -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()
|
@ -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
|
@ -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
|
@ -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()
|
@ -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])
|
@ -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])
|
@ -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])
|
@ -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()
|
@ -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()
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user