[Python-checkins] CVS: python/dist/src/Tools/scripts dutree.doc,NONE,1.1.12.1 dutree.py,NONE,1.10.6.1 eptags.py,NONE,1.8.8.1 findlinksto.py,NONE,1.8.6.1 fixcid.py,NONE,1.9.6.1 fixheader.py,NONE,1.3.6.1 fixnotice.py,NONE,1.5.6.1 fixps.py,NONE,1.5.6.1 ftpmirror.py,NONE,1.14.2.1 gencodec.py,NONE,1.6.2.1 h2py.py,NONE,1.12.6.1 ifdef.py,NONE,1.4.6.1 lfcr.py,NONE,1.3.10.1 linktree.py,NONE,1.6.6.1 lll.py,NONE,1.5.6.1 logmerge.py,NONE,1.7.4.1 mailerdaemon.py,NONE,1.9.6.1 md5sum.py,NONE,1.1.2.1 methfix.py,NONE,1.6.6.1 mkreal.py,NONE,1.6.6.1 ndiff.py,NONE,1.8.6.1 nm2def.py,NONE,1.4.6.1 objgraph.py,NONE,1.5.6.1 parseentities.py,NONE,1.3.6.1 pathfix.py,NONE,1.4.6.1 pdeps.py,NONE,1.5.6.1 pindent.py,NONE,1.10.6.1 ptags.py,NONE,1.7.6.1 pydoc.pyw,NONE,1.1.4.1 redemo.py,NONE,1.2.6.1 reindent.py,NONE,1.1.8.1 rgrep.py,NONE,1.1.12.1 suff.py,NONE,1.5.6.1 sum5.py,NONE,1.3.6.1 texi2html.py,NONE,1.12.6.1 trace.py,NONE,1.4.2.1 treesync.py,NONE,1.5.6.1 untabify.py,NONE,1.2.12.1 which.py,NONE,1.9.6.1 xxci.py,NONE,1.14.6.1

Tim Peters tim_one@users.sourceforge.net
2001年7月06日 10:08:51 -0700


Update of /cvsroot/python/python/dist/src/Tools/scripts
In directory usw-pr-cvs1:/tmp/cvs-serv3084
Added Files:
 Tag: descr-branch
	dutree.doc dutree.py eptags.py findlinksto.py fixcid.py 
	fixheader.py fixnotice.py fixps.py ftpmirror.py gencodec.py 
	h2py.py ifdef.py lfcr.py linktree.py lll.py logmerge.py 
	mailerdaemon.py md5sum.py methfix.py mkreal.py ndiff.py 
	nm2def.py objgraph.py parseentities.py pathfix.py pdeps.py 
	pindent.py ptags.py pydoc.pyw redemo.py reindent.py rgrep.py 
	suff.py sum5.py texi2html.py trace.py treesync.py untabify.py 
	which.py xxci.py 
Log Message:
Adding "the rest" of Tools/scripts to descr-branch.
--- NEW FILE: dutree.doc ---
Path: cwi.nl!sun4nl!mcsun!uunet!cs.utexas.edu!convex!usenet
From: tchrist@convex.COM (Tom Christiansen)
Newsgroups: comp.lang.perl
Subject: Re: The problems of Perl (Re: Question (silly?))
Message-ID: <1992Jan17.053115.4220@convex.com>
Date: 17 Jan 92 05:31:15 GMT
References: <17458@ector.cs.purdue.edu> <1992Jan16.165347.25583@cherokee.uswest.com> <=#Hues+4@cs.psu.edu>
Sender: usenet@convex.com (news access account)
Reply-To: tchrist@convex.COM (Tom Christiansen)
Organization: CONVEX Realtime Development, Colorado Springs, CO
Lines: 83
Nntp-Posting-Host: pixel.convex.com
>From the keyboard of flee@cs.psu.edu (Felix Lee):
:And Perl is definitely awkward with data types. I haven't yet found a
:pleasant way of shoving non-trivial data types into Perl's grammar.

Yes, it's pretty aweful at that, alright. Sometimes I write perl programs
that need them, and sometimes it just takes a little creativity. But
sometimes it's not worth it. I actually wrote a C program the other day
(gasp) because I didn't want to deal with a game matrix with six links per node.
:Here's a very simple problem that's tricky to express in Perl: process
:the output of "du" to produce output that's indented to reflect the
:tree structure, and with each subtree sorted by size. Something like:
: 434 /etc
: | 344 .
: | 50 install
: | 35 uucp
: | 3 nserve
: | | 2 .
: | | 1 auth.info
: | 1 sm
: | 1 sm.bak

At first I thought I could just keep one local list around
at once, but this seems inherently recursive. Which means 
I need an real recursive data structure. Maybe you could
do it with one of the %assoc arrays Larry uses in the begat
programs, but I broke down and got dirty. I think the hardest
part was matching Felix's desired output exactly. It's not 
blazingly fast: I should probably inline the &childof routine,
but it *was* faster to write than I could have written the 
equivalent C program.
--tom
--
"GUIs normally make it simple to accomplish simple actions and impossible
to accomplish complex actions." --Doug Gwyn (22/Jun/91 in comp.unix.wizards)
 Tom Christiansen tchrist@convex.com convex!tchrist
--- NEW FILE: dutree.py ---
#! /usr/bin/env python
# Format du output in a tree shape
import os, string, sys, errno
def main():
 p = os.popen('du ' + string.join(sys.argv[1:]), 'r')
 total, d = None, {}
 for line in p.readlines():
 i = 0
 while line[i] in '0123456789': i = i+1
 size = eval(line[:i])
 while line[i] in ' \t': i = i+1
 file = line[i:-1]
 comps = string.splitfields(file, '/')
 if comps[0] == '': comps[0] = '/'
 if comps[len(comps)-1] == '': del comps[len(comps)-1]
 total, d = store(size, comps, total, d)
 try:
 display(total, d)
 except IOError, e:
 if e.errno != errno.EPIPE:
 raise
def store(size, comps, total, d):
 if comps == []:
 return size, d
 if not d.has_key(comps[0]):
 d[comps[0]] = None, {}
 t1, d1 = d[comps[0]]
 d[comps[0]] = store(size, comps[1:], t1, d1)
 return total, d
def display(total, d):
 show(total, d, '')
def show(total, d, prefix):
 if not d: return
 list = []
 sum = 0
 for key in d.keys():
 tsub, dsub = d[key]
 list.append((tsub, key))
 if tsub is not None: sum = sum + tsub
## if sum < total:
## list.append((total - sum, os.curdir))
 list.sort()
 list.reverse()
 width = len(`list[0][0]`)
 for tsub, key in list:
 if tsub is None:
 psub = prefix
 else:
 print prefix + string.rjust(`tsub`, width) + ' ' + key
 psub = prefix + ' '*(width-1) + '|' + ' '*(len(key)+1)
 if d.has_key(key):
 show(tsub, d[key][1], psub)
main()
--- NEW FILE: eptags.py ---
#! /usr/bin/env python
"""Create a TAGS file for Python programs, usable with GNU Emacs.
usage: eptags pyfiles...
The output TAGS file is usable with Emacs version 18, 19, 20.
Tagged are:
 - functions (even inside other defs or classes)
 - classes
eptags warns about files it cannot open.
eptags will not give warnings about duplicate tags.
BUGS:
 Because of tag duplication (methods with the same name in different
 classes), TAGS files are not very useful for most object-oriented
 python projects.
"""
import sys,re
expr = r'^[ \t]*(def|class)[ \t]+([a-zA-Z_][a-zA-Z0-9_]*)[ \t]*[:\(]'
matcher = re.compile(expr)
def treat_file(file, outfp):
 """Append tags found in file named 'file' to the open file 'outfp'"""
 try:
 fp = open(file, 'r')
 except:
 sys.stderr.write('Cannot open %s\n'%file)
 return
 charno = 0
 lineno = 0
 tags = []
 size = 0
 while 1:
 line = fp.readline()
 if not line:
 break
 lineno = lineno + 1
 m = matcher.search(line)
 if m:
 tag = m.group(0) + '177円%d,%d\n'%(lineno,charno)
 tags.append(tag)
 size = size + len(tag)
 charno = charno + len(line)
 outfp.write('\f\n%s,%d\n'%(file,size))
 for tag in tags:
 outfp.write(tag)
def main():
 outfp = open('TAGS', 'w')
 for file in sys.argv[1:]:
 treat_file(file, outfp)
if __name__=="__main__":
 main()
--- NEW FILE: findlinksto.py ---
#! /usr/bin/env python
# findlinksto
#
# find symbolic links to a path matching a regular expression
import os
import sys
import regex
import getopt
def main():
 try:
 opts, args = getopt.getopt(sys.argv[1:], '')
 if len(args) < 2:
 raise getopt.error, 'not enough arguments'
 except getopt.error, msg:
 sys.stdout = sys.stderr
 print msg
 print 'usage: findlinksto pattern directory ...'
 sys.exit(2)
 pat, dirs = args[0], args[1:]
 prog = regex.compile(pat)
 for dirname in dirs:
 os.path.walk(dirname, visit, prog)
def visit(prog, dirname, names):
 if os.path.islink(dirname):
 names[:] = []
 return
 if os.path.ismount(dirname):
 print 'descend into', dirname
 for name in names:
 name = os.path.join(dirname, name)
 try:
 linkto = os.readlink(name)
 if prog.search(linkto) >= 0:
 print name, '->', linkto
 except os.error:
 pass
main()
--- NEW FILE: fixcid.py ---
#! /usr/bin/env python
# Perform massive identifier substitution on C source files.
# This actually tokenizes the files (to some extent) so it can
# avoid making substitutions inside strings or comments.
# Inside strings, substitutions are never made; inside comments,
# it is a user option (off by default).
#
# The substitutions are read from one or more files whose lines,
# when not empty, after stripping comments starting with #,
# must contain exactly two words separated by whitespace: the
# old identifier and its replacement.
#
# The option -r reverses the sense of the substitutions (this may be
# useful to undo a particular substitution).
#
# If the old identifier is prefixed with a '*' (with no intervening
# whitespace), then it will not be substituted inside comments.
#
# Command line arguments are files or directories to be processed.
# Directories are searched recursively for files whose name looks
# like a C file (ends in .h or .c). The special filename '-' means
# operate in filter mode: read stdin, write stdout.
#
# Symbolic links are always ignored (except as explicit directory
# arguments).
#
# The original files are kept as back-up with a "~" suffix.
#
# Changes made are reported to stdout in a diff-like format.
#
# NB: by changing only the function fixline() you can turn this
# into a program for different changes to C source files; by
# changing the function wanted() you can make a different selection of
# files.
import sys
import regex
import string
import os
from stat import *
import getopt
err = sys.stderr.write
dbg = err
rep = sys.stdout.write
def usage():
 progname = sys.argv[0]
 err('Usage: ' + progname +
 ' [-c] [-r] [-s file] ... file-or-directory ...\n')
 err('\n')
 err('-c : substitute inside comments\n')
 err('-r : reverse direction for following -s options\n')
 err('-s substfile : add a file of substitutions\n')
 err('\n')
 err('Each non-empty non-comment line in a substitution file must\n')
 err('contain exactly two words: an identifier and its replacement.\n')
 err('Comments start with a # character and end at end of line.\n')
 err('If an identifier is preceded with a *, it is not substituted\n')
 err('inside a comment even when -c is specified.\n')
def main():
 try:
 opts, args = getopt.getopt(sys.argv[1:], 'crs:')
 except getopt.error, msg:
 err('Options error: ' + str(msg) + '\n')
 usage()
 sys.exit(2)
 bad = 0
 if not args: # No arguments
 usage()
 sys.exit(2)
 for opt, arg in opts:
 if opt == '-c':
 setdocomments()
 if opt == '-r':
 setreverse()
 if opt == '-s':
 addsubst(arg)
 for arg in args:
 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)
# Change this regular expression to select a different set of files
Wanted = '^[a-zA-Z0-9_]+\.[ch]$'
def wanted(name):
 return regex.match(Wanted, name) >= 0
def recursedown(dirname):
 dbg('recursedown(' + `dirname` + ')\n')
 bad = 0
 try:
 names = os.listdir(dirname)
 except os.error, msg:
 err(dirname + ': cannot list directory: ' + str(msg) + '\n')
 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 wanted(name):
 if fix(fullname): bad = 1
 for fullname in subdirs:
 if recursedown(fullname): bad = 1
 return bad
def fix(filename):
## dbg('fix(' + `filename` + ')\n')
 if filename == '-':
 # Filter mode
 f = sys.stdin
 g = sys.stdout
 else:
 # File replacement mode
 try:
 f = open(filename, 'r')
 except IOError, msg:
 err(filename + ': cannot open: ' + str(msg) + '\n')
 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
 initfixline()
 while 1:
 line = f.readline()
 if not line: break
 lineno = lineno + 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, msg:
 f.close()
 err(tempname+': cannot create: '+
 str(msg)+'\n')
 return 1
 f.seek(0)
 lineno = 0
 initfixline()
 rep(filename + ':\n')
 continue # restart from the beginning
 rep(`lineno` + '\n')
 rep('< ' + line)
 rep('> ' + newline)
 if g is not None:
 g.write(newline)
 # End of file
 if filename == '-': return 0 # Done in filter mode
 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] & 07777)
 except os.error, msg:
 err(tempname + ': warning: chmod failed (' + str(msg) + ')\n')
 # Then make a backup of the original file as filename~
 try:
 os.rename(filename, filename + '~')
 except os.error, msg:
 err(filename + ': warning: backup failed (' + str(msg) + ')\n')
 # Now move the temp file to the original file
 try:
 os.rename(tempname, filename)
 except os.error, msg:
 err(filename + ': rename failed (' + str(msg) + ')\n')
 return 1
 # Return succes
 return 0
# Tokenizing ANSI C (partly)
Identifier = '\(struct \)?[a-zA-Z_][a-zA-Z0-9_]+'
String = '"\([^\n\\"]\|\\\\.\)*"'
Char = '\'\([^\n\\\']\|\\\\.\)*\''
CommentStart = '/\*'
CommentEnd = '\*/'
Hexnumber = '0[xX][0-9a-fA-F]*[uUlL]*'
Octnumber = '0[0-7]*[uUlL]*'
Decnumber = '[1-9][0-9]*[uUlL]*'
Intnumber = Hexnumber + '\|' + Octnumber + '\|' + Decnumber
Exponent = '[eE][-+]?[0-9]+'
Pointfloat = '\([0-9]+\.[0-9]*\|\.[0-9]+\)\(' + Exponent + '\)?'
Expfloat = '[0-9]+' + Exponent
Floatnumber = Pointfloat + '\|' + Expfloat
Number = Floatnumber + '\|' + Intnumber
# Anything else is an operator -- don't list this explicitly because of '/*'
OutsideComment = (Identifier, Number, String, Char, CommentStart)
OutsideCommentPattern = '\(' + string.joinfields(OutsideComment, '\|') + '\)'
OutsideCommentProgram = regex.compile(OutsideCommentPattern)
InsideComment = (Identifier, Number, CommentEnd)
InsideCommentPattern = '\(' + string.joinfields(InsideComment, '\|') + '\)'
InsideCommentProgram = regex.compile(InsideCommentPattern)
def initfixline():
 global Program
 Program = OutsideCommentProgram
def fixline(line):
 global Program
## print '-->', `line`
 i = 0
 while i < len(line):
 i = Program.search(line, i)
 if i < 0: break
 found = Program.group(0)
## if Program is InsideCommentProgram: print '...',
## else: print ' ',
## print found
 if len(found) == 2:
 if found == '/*':
 Program = InsideCommentProgram
 elif found == '*/':
 Program = OutsideCommentProgram
 n = len(found)
 if Dict.has_key(found):
 subst = Dict[found]
 if Program is InsideCommentProgram:
 if not Docomments:
 print 'Found in comment:', found
 i = i + n
 continue
 if NotInComment.has_key(found):
## print 'Ignored in comment:',
## print found, '-->', subst
## print 'Line:', line,
 subst = found
## else:
## print 'Substituting in comment:',
## print found, '-->', subst
## print 'Line:', line,
 line = line[:i] + subst + line[i+n:]
 n = len(subst)
 i = i + n
 return line
Docomments = 0
def setdocomments():
 global Docomments
 Docomments = 1
Reverse = 0
def setreverse():
 global Reverse
 Reverse = (not Reverse)
Dict = {}
NotInComment = {}
def addsubst(substfile):
 try:
 fp = open(substfile, 'r')
 except IOError, msg:
 err(substfile + ': cannot read substfile: ' + str(msg) + '\n')
 sys.exit(1)
 lineno = 0
 while 1:
 line = fp.readline()
 if not line: break
 lineno = lineno + 1
 try:
 i = string.index(line, '#')
 except string.index_error:
 i = -1 # Happens to delete trailing \n
 words = string.split(line[:i])
 if not words: continue
 if len(words) == 3 and words[0] == 'struct':
 words[:2] = [words[0] + ' ' + words[1]]
 elif len(words) <> 2:
 err(substfile + ':' + `lineno` +
 ': warning: bad line: ' + line)
 continue
 if Reverse:
 [value, key] = words
 else:
 [key, value] = words
 if value[0] == '*':
 value = value[1:]
 if key[0] == '*':
 key = key[1:]
 NotInComment[key] = value
 if Dict.has_key(key):
 err(substfile + ':' + `lineno` +
 ': warning: overriding: ' +
 key + ' ' + value + '\n')
 err(substfile + ':' + `lineno` +
 ': warning: previous: ' + Dict[key] + '\n')
 Dict[key] = value
 fp.close()
main()
--- NEW FILE: fixheader.py ---
#! /usr/bin/env python
# Add some standard cpp magic to a header file
import sys
import string
def main():
 args = sys.argv[1:]
 for file in args:
 process(file)
def process(file):
 try:
 f = open(file, 'r')
 except IOError, msg:
 sys.stderr.write('%s: can\'t open: %s\n' % (file, str(msg)))
 return
 data = f.read()
 f.close()
 if data[:2] <> '/*':
 sys.stderr.write('%s does not begin with C comment\n' % file)
 return
 try:
 f = open(file, 'w')
 except IOError, msg:
 sys.stderr.write('%s: can\'t write: %s\n' % (file, str(msg)))
 return
 sys.stderr.write('Processing %s ...\n' % file)
 magic = 'Py_'
 for c in file:
 if c in string.letters + string.digits:
 magic = magic + string.upper(c)
 else: magic = magic + '_'
 sys.stdout = f
 print '#ifndef', magic
 print '#define', magic
 print '#ifdef __cplusplus'
 print 'extern "C" {'
 print '#endif'
 print
 f.write(data)
 print
 print '#ifdef __cplusplus'
 print '}'
 print '#endif'
 print '#endif /*', '!'+magic, '*/'
main()
--- NEW FILE: fixnotice.py ---
#! /usr/bin/env python
OLD_NOTICE = """/***********************************************************
Copyright (c) 2000, BeOpen.com.
Copyright (c) 1995-2000, Corporation for National Research Initiatives.
Copyright (c) 1990-1995, Stichting Mathematisch Centrum.
All rights reserved.
See the file "Misc/COPYRIGHT" for information on usage and
redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
******************************************************************/
"""
NEW_NOTICE = ""
# " <-- Help Emacs
import os, sys, string
def main():
 args = sys.argv[1:]
 if not args:
 print "No arguments."
 for arg in args:
 process(arg)
def process(arg):
 f = open(arg)
 data = f.read()
 f.close()
 i = string.find(data, OLD_NOTICE)
 if i < 0:
## print "No old notice in", arg
 return
 data = data[:i] + NEW_NOTICE + data[i+len(OLD_NOTICE):]
 new = arg + ".new"
 backup = arg + ".bak"
 print "Replacing notice in", arg, "...",
 sys.stdout.flush()
 f = open(new, "w")
 f.write(data)
 f.close()
 os.rename(arg, backup)
 os.rename(new, arg)
 print "done"
if __name__ == '__main__':
 main()
--- NEW FILE: fixps.py ---
#!/usr/bin/env python
# Fix Python script(s) to reference the interpreter via /usr/bin/env python.
# Warning: this overwrites the file without making a backup.
import sys
import re
def main():
 for file in sys.argv[1:]:
 try:
 f = open(file, 'r')
 except IOError, msg:
 print file, ': can\'t open :', msg
 continue
 line = f.readline()
 if not re.match('^#! */usr/local/bin/python', line):
 print file, ': not a /usr/local/bin/python script'
 f.close()
 continue
 rest = f.read()
 f.close()
 line = re.sub('/usr/local/bin/python',
 '/usr/bin/env python', line)
 print file, ':', `line`
 f = open(file, "w")
 f.write(line)
 f.write(rest)
 f.close()
main()
--- NEW FILE: ftpmirror.py ---
#! /usr/bin/env python
"""Mirror a remote ftp subtree into a local directory tree.
usage: ftpmirror [-v] [-q] [-i] [-m] [-n] [-r] [-s pat]
 [-l username [-p passwd [-a account]]]
 hostname [remotedir [localdir]]
-v: verbose
-q: quiet
-i: interactive mode
-m: macintosh server (NCSA telnet 2.4) (implies -n -s '*.o')
-n: don't log in
-r: remove local files/directories no longer pertinent
-l username [-p passwd [-a account]]: login info (default .netrc or anonymous)
-s pat: skip files matching pattern
hostname: remote host
remotedir: remote directory (default initial)
localdir: local directory (default current)
"""
import os
import sys
import time
import getopt
import string
import ftplib
import netrc
from fnmatch import fnmatch
# Print usage message and exit
def usage(*args):
 sys.stdout = sys.stderr
 for msg in args: print msg
 print __doc__
 sys.exit(2)
verbose = 1 # 0 for -q, 2 for -v
interactive = 0
mac = 0
rmok = 0
nologin = 0
skippats = ['.', '..', '.mirrorinfo']
# Main program: parse command line and start processing
def main():
 global verbose, interactive, mac, rmok, nologin
 try:
 opts, args = getopt.getopt(sys.argv[1:], 'a:bil:mnp:qrs:v')
 except getopt.error, msg:
 usage(msg)
 login = ''
 passwd = ''
 account = ''
 if not args: usage('hostname missing')
 host = args[0]
 try:
 auth = netrc.netrc().authenticators(host)
 if auth is not None:
 login, account, passwd = auth
 except (netrc.NetrcParseError, IOError):
 pass
 for o, a in opts:
 if o == '-l': login = a
 if o == '-p': passwd = a
 if o == '-a': account = a
 if o == '-v': verbose = verbose + 1
 if o == '-q': verbose = 0
 if o == '-i': interactive = 1
 if o == '-m': mac = 1; nologin = 1; skippats.append('*.o')
 if o == '-n': nologin = 1
 if o == '-r': rmok = 1
 if o == '-s': skippats.append(a)
 remotedir = ''
 localdir = ''
 if args[1:]:
 remotedir = args[1]
 if args[2:]:
 localdir = args[2]
 if args[3:]: usage('too many arguments')
 #
 f = ftplib.FTP()
 if verbose: print 'Connecting to %s...' % `host`
 f.connect(host)
 if not nologin:
 if verbose:
 print 'Logging in as %s...' % `login or 'anonymous'`
 f.login(login, passwd, account)
 if verbose: print 'OK.'
 pwd = f.pwd()
 if verbose > 1: print 'PWD =', `pwd`
 if remotedir:
 if verbose > 1: print 'cwd(%s)' % `remotedir`
 f.cwd(remotedir)
 if verbose > 1: print 'OK.'
 pwd = f.pwd()
 if verbose > 1: print 'PWD =', `pwd`
 #
 mirrorsubdir(f, localdir)
# Core logic: mirror one subdirectory (recursively)
def mirrorsubdir(f, localdir):
 pwd = f.pwd()
 if localdir and not os.path.isdir(localdir):
 if verbose: print 'Creating local directory', `localdir`
 try:
 makedir(localdir)
 except os.error, msg:
 print "Failed to establish local directory", `localdir`
 return
 infofilename = os.path.join(localdir, '.mirrorinfo')
 try:
 text = open(infofilename, 'r').read()
 except IOError, msg:
 text = '{}'
 try:
 info = eval(text)
 except (SyntaxError, NameError):
 print 'Bad mirror info in %s' % `infofilename`
 info = {}
 subdirs = []
 listing = []
 if verbose: print 'Listing remote directory %s...' % `pwd`
 f.retrlines('LIST', listing.append)
 filesfound = []
 for line in listing:
 if verbose > 1: print '-->', `line`
 if mac:
 # Mac listing has just filenames;
 # trailing / means subdirectory
 filename = string.strip(line)
 mode = '-'
 if filename[-1:] == '/':
 filename = filename[:-1]
 mode = 'd'
 infostuff = ''
 else:
 # Parse, assuming a UNIX listing
 words = string.split(line, None, 8)
 if len(words) < 6:
 if verbose > 1: print 'Skipping short line'
 continue
 filename = string.lstrip(words[-1])
 i = string.find(filename, " -> ")
 if i >= 0:
 # words[0] had better start with 'l'...
 if verbose > 1:
 print 'Found symbolic link %s' % `filename`
 linkto = filename[i+4:]
 filename = filename[:i]
 infostuff = words[-5:-1]
 mode = words[0]
 skip = 0
 for pat in skippats:
 if fnmatch(filename, pat):
 if verbose > 1:
 print 'Skip pattern', `pat`,
 print 'matches', `filename`
 skip = 1
 break
 if skip:
 continue
 if mode[0] == 'd':
 if verbose > 1:
 print 'Remembering subdirectory', `filename`
 subdirs.append(filename)
 continue
 filesfound.append(filename)
 if info.has_key(filename) and info[filename] == infostuff:
 if verbose > 1:
 print 'Already have this version of',`filename`
 continue
 fullname = os.path.join(localdir, filename)
 tempname = os.path.join(localdir, '@'+filename)
 if interactive:
 doit = askabout('file', filename, pwd)
 if not doit:
 if not info.has_key(filename):
 info[filename] = 'Not retrieved'
 continue
 try:
 os.unlink(tempname)
 except os.error:
 pass
 if mode[0] == 'l':
 if verbose:
 print "Creating symlink %s -> %s" % (
 `filename`, `linkto`)
 try:
 os.symlink(linkto, tempname)
 except IOError, msg:
 print "Can't create %s: %s" % (
 `tempname`, str(msg))
 continue
 else:
 try:
 fp = open(tempname, 'wb')
 except IOError, msg:
 print "Can't create %s: %s" % (
 `tempname`, str(msg))
 continue
 if verbose:
 print 'Retrieving %s from %s as %s...' % \
 (`filename`, `pwd`, `fullname`)
 if verbose:
 fp1 = LoggingFile(fp, 1024, sys.stdout)
 else:
 fp1 = fp
 t0 = time.time()
 try:
 f.retrbinary('RETR ' + filename,
 fp1.write, 8*1024)
 except ftplib.error_perm, msg:
 print msg
 t1 = time.time()
 bytes = fp.tell()
 fp.close()
 if fp1 != fp:
 fp1.close()
 try:
 os.unlink(fullname)
 except os.error:
 pass # Ignore the error
 try:
 os.rename(tempname, fullname)
 except os.error, msg:
 print "Can't rename %s to %s: %s" % (`tempname`,
 `fullname`,
 str(msg))
 continue
 info[filename] = infostuff
 writedict(info, infofilename)
 if verbose and mode[0] != 'l':
 dt = t1 - t0
 kbytes = bytes / 1024.0
 print int(round(kbytes)),
 print 'Kbytes in',
 print int(round(dt)),
 print 'seconds',
 if t1 > t0:
 print '(~%d Kbytes/sec)' % \
 int(round(kbytes/dt),)
 print
 #
 # Remove files from info that are no longer remote
 deletions = 0
 for filename in info.keys():
 if filename not in filesfound:
 if verbose:
 print "Removing obsolete info entry for",
 print `filename`, "in", `localdir or "."`
 del info[filename]
 deletions = deletions + 1
 if deletions:
 writedict(info, infofilename)
 #
 # Remove local files that are no longer in the remote directory
 try:
 if not localdir: names = os.listdir(os.curdir)
 else: names = os.listdir(localdir)
 except os.error:
 names = []
 for name in names:
 if name[0] == '.' or info.has_key(name) or name in subdirs:
 continue
 skip = 0
 for pat in skippats:
 if fnmatch(name, pat):
 if verbose > 1:
 print 'Skip pattern', `pat`,
 print 'matches', `name`
 skip = 1
 break
 if skip:
 continue
 fullname = os.path.join(localdir, name)
 if not rmok:
 if verbose:
 print 'Local file', `fullname`,
 print 'is no longer pertinent'
 continue
 if verbose: print 'Removing local file/dir', `fullname`
 remove(fullname)
 #
 # Recursively mirror subdirectories
 for subdir in subdirs:
 if interactive:
 doit = askabout('subdirectory', subdir, pwd)
 if not doit: continue
 if verbose: print 'Processing subdirectory', `subdir`
 localsubdir = os.path.join(localdir, subdir)
 pwd = f.pwd()
 if verbose > 1:
 print 'Remote directory now:', `pwd`
 print 'Remote cwd', `subdir`
 try:
 f.cwd(subdir)
 except ftplib.error_perm, msg:
 print "Can't chdir to", `subdir`, ":", `msg`
 else:
 if verbose: print 'Mirroring as', `localsubdir`
 mirrorsubdir(f, localsubdir)
 if verbose > 1: print 'Remote cwd ..'
 f.cwd('..')
 newpwd = f.pwd()
 if newpwd != pwd:
 print 'Ended up in wrong directory after cd + cd ..'
 print 'Giving up now.'
 break
 else:
 if verbose > 1: print 'OK.'
# Helper to remove a file or directory tree
def remove(fullname):
 if os.path.isdir(fullname) and not os.path.islink(fullname):
 try:
 names = os.listdir(fullname)
 except os.error:
 names = []
 ok = 1
 for name in names:
 if not remove(os.path.join(fullname, name)):
 ok = 0
 if not ok:
 return 0
 try:
 os.rmdir(fullname)
 except os.error, msg:
 print "Can't remove local directory %s: %s" % \
 (`fullname`, str(msg))
 return 0
 else:
 try:
 os.unlink(fullname)
 except os.error, msg:
 print "Can't remove local file %s: %s" % \
 (`fullname`, str(msg))
 return 0
 return 1
# Wrapper around a file for writing to write a hash sign every block.
class LoggingFile:
 def __init__(self, fp, blocksize, outfp):
 self.fp = fp
 self.bytes = 0
 self.hashes = 0
 self.blocksize = blocksize
 self.outfp = outfp
 def write(self, data):
 self.bytes = self.bytes + len(data)
 hashes = int(self.bytes) / self.blocksize
 while hashes > self.hashes:
 self.outfp.write('#')
 self.outfp.flush()
 self.hashes = self.hashes + 1
 self.fp.write(data)
 def close(self):
 self.outfp.write('\n')
# Ask permission to download a file.
def askabout(filetype, filename, pwd):
 prompt = 'Retrieve %s %s from %s ? [ny] ' % (filetype, filename, pwd)
 while 1:
 reply = string.lower(string.strip(raw_input(prompt)))
 if reply in ['y', 'ye', 'yes']:
 return 1
 if reply in ['', 'n', 'no', 'nop', 'nope']:
 return 0
 print 'Please answer yes or no.'
# Create a directory if it doesn't exist. Recursively create the
# parent directory as well if needed.
def makedir(pathname):
 if os.path.isdir(pathname):
 return
 dirname = os.path.dirname(pathname)
 if dirname: makedir(dirname)
 os.mkdir(pathname, 0777)
# Write a dictionary to a file in a way that can be read back using
# rval() but is still somewhat readable (i.e. not a single long line).
# Also creates a backup file.
def writedict(dict, filename):
 dir, file = os.path.split(filename)
 tempname = os.path.join(dir, '@' + file)
 backup = os.path.join(dir, file + '~')
 try:
 os.unlink(backup)
 except os.error:
 pass
 fp = open(tempname, 'w')
 fp.write('{\n')
 for key, value in dict.items():
 fp.write('%s: %s,\n' % (`key`, `value`))
 fp.write('}\n')
 fp.close()
 try:
 os.rename(filename, backup)
 except os.error:
 pass
 os.rename(tempname, filename)
if __name__ == '__main__':
 main()
--- NEW FILE: gencodec.py ---
""" Unicode Mapping Parser and Codec Generator.
This script parses Unicode mapping files as available from the Unicode
site (ftp://ftp.unicode.org/Public/MAPPINGS/) and creates Python codec
modules from them. The codecs use the standard character mapping codec
to actually apply the mapping.
Synopsis: gencodec.py dir codec_prefix
All files in dir are scanned and those producing non-empty mappings
will be written to <codec_prefix><mapname>.py with <mapname> being the
first part of the map's filename ('a' in a.b.c.txt) converted to
lowercase with hyphens replaced by underscores.
The tool also writes marshalled versions of the mapping tables to the
same location (with .mapping extension).
Written by Marc-Andre Lemburg (mal@lemburg.com).
(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
(c) Copyright Guido van Rossum, 2000.
"""#"
import string,re,os,time,marshal
# Create numeric tables or character based ones ?
numeric = 1
mapRE = re.compile('((?:0x[0-9a-fA-F]+\+?)+)'
 '\s+'
 '((?:(?:0x[0-9a-fA-Z]+|<[A-Za-z]+>)\+?)*)'
 '\s*'
 '(#.+)?')
def parsecodes(codes,
 split=string.split,atoi=string.atoi,len=len,
 filter=filter,range=range):
 """ Converts code combinations to either a single code integer
 or a tuple of integers.
 meta-codes (in angular brackets, e.g. <LR> and <RL>) are
 ignored.
 Empty codes or illegal ones are returned as None.
 """
 if not codes:
 return None
 l = split(codes,'+')
 if len(l) == 1:
 return atoi(l[0],16)
 for i in range(len(l)):
 try:
 l[i] = atoi(l[i],16)
 except ValueError:
 l[i] = None
 l = filter(lambda x: x is not None, l)
 if len(l) == 1:
 return l[0]
 else:
 return tuple(l)
def readmap(filename,
 strip=string.strip):
 f = open(filename,'r')
 lines = f.readlines()
 f.close()
 enc2uni = {}
 identity = []
 unmapped = range(256)
 for i in range(256):
 unmapped[i] = i
 for line in lines:
 line = strip(line)
 if not line or line[0] == '#':
 continue
 m = mapRE.match(line)
 if not m:
 #print '* not matched: %s' % repr(line)
 continue
 enc,uni,comment = m.groups()
 enc = parsecodes(enc)
 uni = parsecodes(uni)
 if not comment:
 comment = ''
 else:
 comment = comment[1:]
 if enc < 256:
 unmapped.remove(enc)
 if enc == uni:
 identity.append(enc)
 else:
 enc2uni[enc] = (uni,comment)
 else:
 enc2uni[enc] = (uni,comment)
 # If there are more identity-mapped entries than unmapped entries,
 # it pays to generate an identity dictionary first, add add explicit
 # mappings to None for the rest
 if len(identity)>=len(unmapped):
 for enc in unmapped:
 enc2uni[enc] = (None, "")
 enc2uni['IDENTITY'] = 256
 return enc2uni
def hexrepr(t,
 join=string.join):
 if t is None:
 return 'None'
 try:
 len(t)
 except:
 return '0x%04x' % t
 return '(' + join(map(lambda t: '0x%04x' % t, t),', ') + ')'
def unicoderepr(t,
 join=string.join):
 if t is None:
 return 'None'
 if numeric:
 return hexrepr(t)
 else:
 try:
 len(t)
 except:
 return repr(unichr(t))
 return repr(join(map(unichr, t),''))
def keyrepr(t,
 join=string.join):
 if t is None:
 return 'None'
 if numeric:
 return hexrepr(t)
 else:
 try:
 len(t)
 except:
 if t < 256:
 return repr(chr(t))
 else:
 return repr(unichr(t))
 return repr(join(map(chr, t),''))
def codegen(name,map,comments=1):
 """ Returns Python source for the given map.
 Comments are included in the source, if comments is true (default).
 """
 l = [
 '''\
""" Python Character Mapping Codec generated from '%s' with gencodec.py.
Written by Marc-Andre Lemburg (mal@lemburg.com).
(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
(c) Copyright 2000 Guido van Rossum.
"""#"
import codecs
### Codec APIs
class Codec(codecs.Codec):
 def encode(self,input,errors='strict'):
 return codecs.charmap_encode(input,errors,encoding_map)
 def decode(self,input,errors='strict'):
 return codecs.charmap_decode(input,errors,decoding_map)
class StreamWriter(Codec,codecs.StreamWriter):
 pass
class StreamReader(Codec,codecs.StreamReader):
 pass
### encodings module API
def getregentry():
 return (Codec().encode,Codec().decode,StreamReader,StreamWriter)
### Decoding Map
''' % name,
 ]
 if map.has_key("IDENTITY"):
 l.append("decoding_map = codecs.make_identity_dict(range(%d))"
 % map["IDENTITY"])
 l.append("decoding_map.update({")
 splits = 1
 del map["IDENTITY"]
 else:
 l.append("decoding_map = {")
 splits = 0
 mappings = map.items()
 mappings.sort()
 append = l.append
 i = 0
 for e,value in mappings:
 try:
 (u,c) = value
 except TypeError:
 u = value
 c = ''
 key = keyrepr(e)
 if c and comments:
 append('\t%s: %s,\t# %s' % (key,unicoderepr(u),c))
 else:
 append('\t%s: %s,' % (key,unicoderepr(u)))
 i += 1
 if i == 4096:
 # Split the definition into parts to that the Python
 # parser doesn't dump core
 if splits == 0:
 append('}')
 else:
 append('})')
 append('decoding_map.update({')
 i = 0
 splits = splits + 1
 if splits == 0:
 append('}')
 else:
 append('})')
 append('''
### Encoding Map
encoding_map = codecs.make_encoding_map(decoding_map)
''')
 return string.join(l,'\n')
def pymap(name,map,pyfile,comments=1):
 code = codegen(name,map,comments)
 f = open(pyfile,'w')
 f.write(code)
 f.close()
def marshalmap(name,map,marshalfile):
 d = {}
 for e,(u,c) in map.items():
 d[e] = (u,c)
 f = open(marshalfile,'wb')
 marshal.dump(d,f)
 f.close()
def convertdir(dir,prefix='',comments=1):
 mapnames = os.listdir(dir)
 for mapname in mapnames:
 name = os.path.split(mapname)[1]
 name = string.replace(name,'-','_')
 name = string.split(name, '.')[0]
 name = string.lower(name)
 codefile = name + '.py'
 marshalfile = name + '.mapping'
 print 'converting %s to %s and %s' % (mapname,
 prefix + codefile,
 prefix + marshalfile)
 try:
 map = readmap(os.path.join(dir,mapname))
 if not map:
 print '* map is empty; skipping'
 else:
 pymap(mapname, map, prefix + codefile,comments)
 marshalmap(mapname, map, prefix + marshalfile)
 except ValueError:
 print '* conversion failed'
def rewritepythondir(dir,prefix='',comments=1):
 mapnames = os.listdir(dir)
 for mapname in mapnames:
 if not mapname.endswith('.mapping'):
 continue
 codefile = mapname[:-len('.mapping')] + '.py'
 print 'converting %s to %s' % (mapname,
 prefix + codefile)
 try:
 map = marshal.load(open(os.path.join(dir,mapname),
 'rb'))
 if not map:
 print '* map is empty; skipping'
 else:
 pymap(mapname, map, prefix + codefile,comments)
 except ValueError, why:
 print '* conversion failed: %s' % why
if __name__ == '__main__':
 import sys
 if 1:
 apply(convertdir,tuple(sys.argv[1:]))
 else:
 apply(rewritepythondir,tuple(sys.argv[1:]))
--- NEW FILE: h2py.py ---
#! /usr/bin/env python
# Read #define's and translate to Python code.
# Handle #include statements.
# Handle #define macros with one argument.
# Anything that isn't recognized or doesn't translate into valid
# Python is ignored.
# Without filename arguments, acts as a filter.
# If one or more filenames are given, output is written to corresponding
# filenames in the local directory, translated to all uppercase, with
# the extension replaced by ".py".
# By passing one or more options of the form "-i regular_expression"
# you can specify additional strings to be ignored. This is useful
# e.g. to ignore casts to u_long: simply specify "-i '(u_long)'".
# XXX To do:
# - turn trailing C comments into Python comments
# - turn C Boolean operators "&& || !" into Python "and or not"
# - what to do about #if(def)?
# - what to do about macros with multiple parameters?
import sys, regex, regsub, string, getopt, os
p_define = regex.compile('^[\t ]*#[\t ]*define[\t ]+\([a-zA-Z0-9_]+\)[\t ]+')
p_macro = regex.compile(
 '^[\t ]*#[\t ]*define[\t ]+'
 '\([a-zA-Z0-9_]+\)(\([_a-zA-Z][_a-zA-Z0-9]*\))[\t ]+')
p_include = regex.compile('^[\t ]*#[\t ]*include[\t ]+<\([a-zA-Z0-9_/\.]+\)')
p_comment = regex.compile('/\*\([^*]+\|\*+[^/]\)*\(\*+/\)?')
p_cpp_comment = regex.compile('//.*')
ignores = [p_comment, p_cpp_comment]
p_char = regex.compile("'\(\\\\.[^\\\\]*\|[^\\\\]\)'")
filedict = {}
try:
 searchdirs=string.splitfields(os.environ['include'],';')
except KeyError:
 try:
 searchdirs=string.splitfields(os.environ['INCLUDE'],';')
 except KeyError:
 try:
 if string.find( sys.platform, "beos" ) == 0:
 searchdirs=string.splitfields(os.environ['BEINCLUDES'],';')
 else:
 raise KeyError
 except KeyError:
 searchdirs=['/usr/include']
def main():
 global filedict
 opts, args = getopt.getopt(sys.argv[1:], 'i:')
 for o, a in opts:
 if o == '-i':
 ignores.append(regex.compile(a))
 if not args:
 args = ['-']
 for filename in args:
 if filename == '-':
 sys.stdout.write('# Generated by h2py from stdin\n')
 process(sys.stdin, sys.stdout)
 else:
 fp = open(filename, 'r')
 outfile = os.path.basename(filename)
 i = string.rfind(outfile, '.')
 if i > 0: outfile = outfile[:i]
 outfile = string.upper(outfile)
 outfile = outfile + '.py'
 outfp = open(outfile, 'w')
 outfp.write('# Generated by h2py from %s\n' % filename)
 filedict = {}
 for dir in searchdirs:
 if filename[:len(dir)] == dir:
 filedict[filename[len(dir)+1:]] = None # no '/' trailing
 break
 process(fp, outfp)
 outfp.close()
 fp.close()
def process(fp, outfp, env = {}):
 lineno = 0
 while 1:
 line = fp.readline()
 if not line: break
 lineno = lineno + 1
 n = p_define.match(line)
 if n >= 0:
 # gobble up continuation lines
 while line[-2:] == '\\\n':
 nextline = fp.readline()
 if not nextline: break
 lineno = lineno + 1
 line = line + nextline
 name = p_define.group(1)
 body = line[n:]
 # replace ignored patterns by spaces
 for p in ignores:
 body = regsub.gsub(p, ' ', body)
 # replace char literals by ord(...)
 body = regsub.gsub(p_char, 'ord(\0円)', body)
 stmt = '%s = %s\n' % (name, string.strip(body))
 ok = 0
 try:
 exec stmt in env
 except:
 sys.stderr.write('Skipping: %s' % stmt)
 else:
 outfp.write(stmt)
 n =p_macro.match(line)
 if n >= 0:
 macro, arg = p_macro.group(1, 2)
 body = line[n:]
 for p in ignores:
 body = regsub.gsub(p, ' ', body)
 body = regsub.gsub(p_char, 'ord(\0円)', body)
 stmt = 'def %s(%s): return %s\n' % (macro, arg, body)
 try:
 exec stmt in env
 except:
 sys.stderr.write('Skipping: %s' % stmt)
 else:
 outfp.write(stmt)
 if p_include.match(line) >= 0:
 regs = p_include.regs
 a, b = regs[1]
 filename = line[a:b]
 if not filedict.has_key(filename):
 filedict[filename] = None
 inclfp = None
 for dir in searchdirs:
 try:
 inclfp = open(dir + '/' + filename, 'r')
 break
 except IOError:
 pass
 if inclfp:
 outfp.write(
 '\n# Included from %s\n' % filename)
 process(inclfp, outfp, env)
 else:
 sys.stderr.write('Warning - could not find file %s' % filename)
main()
--- NEW FILE: ifdef.py ---
#! /usr/bin/env python
# Selectively preprocess #ifdef / #ifndef statements.
# Usage:
# ifdef [-Dname] ... [-Uname] ... [file] ...
#
# This scans the file(s), looking for #ifdef and #ifndef preprocessor
# commands that test for one of the names mentioned in the -D and -U
# options. On standard output it writes a copy of the input file(s)
# minus those code sections that are suppressed by the selected
# combination of defined/undefined symbols. The #if(n)def/#else/#else
# lines themselfs (if the #if(n)def tests for one of the mentioned
# names) are removed as well.
# Features: Arbitrary nesting of recognized and unrecognized
# preprocesor statements works correctly. Unrecognized #if* commands
# are left in place, so it will never remove too much, only too
# little. It does accept whitespace around the '#' character.
# Restrictions: There should be no comments or other symbols on the
# #if(n)def lines. The effect of #define/#undef commands in the input
# file or in included files is not taken into account. Tests using
# #if and the defined() pseudo function are not recognized. The #elif
# command is not recognized. Improperly nesting is not detected.
# Lines that look like preprocessor commands but which are actually
# part of comments or string literals will be mistaken for
# preprocessor commands.
import sys
import regex
import getopt
import string
defs = []
undefs = []
def main():
 opts, args = getopt.getopt(sys.argv[1:], 'D:U:')
 for o, a in opts:
 if o == '-D':
 defs.append(a)
 if o == '-U':
 undefs.append(a)
 if not args:
 args = ['-']
 for file in args:
 if file == '-':
 process(sys.stdin, sys.stdout)
 else:
 f = open(file, 'r')
 process(f, sys.stdout)
 f.close()
def process(fpi, fpo):
 keywords = ('if', 'ifdef', 'ifndef', 'else', 'endif')
 ok = 1
 stack = []
 while 1:
 line = fpi.readline()
 if not line: break
 while line[-2:] == '\\\n':
 nextline = fpi.readline()
 if not nextline: break
 line = line + nextline
 tmp = string.strip(line)
 if tmp[:1] != '#':
 if ok: fpo.write(line)
 continue
 tmp = string.strip(tmp[1:])
 words = string.split(tmp)
 keyword = words[0]
 if keyword not in keywords:
 if ok: fpo.write(line)
 continue
 if keyword in ('ifdef', 'ifndef') and len(words) == 2:
 if keyword == 'ifdef':
 ko = 1
 else:
 ko = 0
 word = words[1]
 if word in defs:
 stack.append((ok, ko, word))
 if not ko: ok = 0
 elif word in undefs:
 stack.append((ok, not ko, word))
 if ko: ok = 0
 else:
 stack.append((ok, -1, word))
 if ok: fpo.write(line)
 elif keyword == 'if':
 stack.append((ok, -1, ''))
 if ok: fpo.write(line)
 elif keyword == 'else' and stack:
 s_ok, s_ko, s_word = stack[-1]
 if s_ko < 0:
 if ok: fpo.write(line)
 else:
 s_ko = not s_ko
 ok = s_ok
 if not s_ko: ok = 0
 stack[-1] = s_ok, s_ko, s_word
 elif keyword == 'endif' and stack:
 s_ok, s_ko, s_word = stack[-1]
 if s_ko < 0:
 if ok: fpo.write(line)
 del stack[-1]
 ok = s_ok
 else:
 sys.stderr.write('Unknown keyword %s\n' % keyword)
 if stack:
 sys.stderr.write('stack: %s\n' % stack)
main()
--- NEW FILE: lfcr.py ---
#! /usr/bin/env python
"Replace LF with CRLF in argument files. Print names of changed files."
import sys, re, os
for file in sys.argv[1:]:
 if os.path.isdir(file):
 print file, "Directory!"
 continue
 data = open(file, "rb").read()
 if '0円' in data:
 print file, "Binary!"
 continue
 newdata = re.sub("\r?\n", "\r\n", data)
 if newdata != data:
 print file
 f = open(file, "wb")
 f.write(newdata)
 f.close()
--- NEW FILE: linktree.py ---
#! /usr/bin/env python
# linktree
#
# Make a copy of a directory tree with symbolic links to all files in the
# original tree.
# All symbolic links go to a special symbolic link at the top, so you
# can easily fix things if the original source tree moves.
# See also "mkreal".
#
# usage: mklinks oldtree newtree
import sys, os
LINK = '.LINK' # Name of special symlink at the top.
debug = 0
def main():
 if not 3 <= len(sys.argv) <= 4:
 print 'usage:', sys.argv[0], 'oldtree newtree [linkto]'
 return 2
 oldtree, newtree = sys.argv[1], sys.argv[2]
 if len(sys.argv) > 3:
 link = sys.argv[3]
 link_may_fail = 1
 else:
 link = LINK
 link_may_fail = 0
 if not os.path.isdir(oldtree):
 print oldtree + ': not a directory'
 return 1
 try:
 os.mkdir(newtree, 0777)
 except os.error, msg:
 print newtree + ': cannot mkdir:', msg
 return 1
 linkname = os.path.join(newtree, link)
 try:
 os.symlink(os.path.join(os.pardir, oldtree), linkname)
 except os.error, msg:
 if not link_may_fail:
 print linkname + ': cannot symlink:', msg
 return 1
 else:
 print linkname + ': warning: cannot symlink:', msg
 linknames(oldtree, newtree, link)
 return 0
def linknames(old, new, link):
 if debug: print 'linknames', (old, new, link)
 try:
 names = os.listdir(old)
 except os.error, msg:
 print old + ': warning: cannot listdir:', msg
 return
 for name in names:
 if name not in (os.curdir, os.pardir):
 oldname = os.path.join(old, name)
 linkname = os.path.join(link, name)
 newname = os.path.join(new, name)
 if debug > 1: print oldname, newname, linkname
 if os.path.isdir(oldname) and \
 not os.path.islink(oldname):
 try:
 os.mkdir(newname, 0777)
 ok = 1
 except:
 print newname + \
 ': warning: cannot mkdir:', msg
 ok = 0
 if ok:
 linkname = os.path.join(os.pardir,
 linkname)
 linknames(oldname, newname, linkname)
 else:
 os.symlink(linkname, newname)
sys.exit(main())
--- NEW FILE: lll.py ---
#! /usr/bin/env python
# Find symbolic links and show where they point to.
# Arguments are directories to search; default is current directory.
# No recursion.
# (This is a totally different program from "findsymlinks.py"!)
import sys, os
def lll(dirname):
 for name in os.listdir(dirname):
 if name not in (os.curdir, os.pardir):
 full = os.path.join(dirname, name)
 if os.path.islink(full):
 print name, '->', os.readlink(full)
args = sys.argv[1:]
if not args: args = [os.curdir]
first = 1
for arg in args:
 if len(args) > 1:
 if not first: print
 first = 0
 print arg + ':'
 lll(arg)
--- NEW FILE: logmerge.py ---
#! /usr/bin/env python
"""Consolidate a bunch of CVS or RCS logs read from stdin.
Input should be the output of a CVS or RCS logging command, e.g.
 cvs log -rrelease14:
which dumps all log messages from release1.4 upwards (assuming that
release 1.4 was tagged with tag 'release14'). Note the trailing
colon!
This collects all the revision records and outputs them sorted by date
rather than by file, collapsing duplicate revision record, i.e.,
records with the same message for different files.
The -t option causes it to truncate (discard) the last revision log
entry; this is useful when using something like the above cvs log
command, which shows the revisions including the given tag, while you
probably want everything *since* that tag.
XXX This code was created by reverse engineering CVS 1.9 and RCS 5.7
from their output.
"""
import os, sys, getopt, string, re
sep1 = '='*77 + '\n' # file separator
sep2 = '-'*28 + '\n' # revision separator
def main():
 """Main program"""
 truncate_last = 0
 reverse = 0
 opts, args = getopt.getopt(sys.argv[1:], "tr")
 for o, a in opts:
 if o == '-t':
 truncate_last = 1
 elif o == '-r':
 reverse = 1
 database = []
 while 1:
 chunk = read_chunk(sys.stdin)
 if not chunk:
 break
 records = digest_chunk(chunk)
 if truncate_last:
 del records[-1]
 database[len(database):] = records
 database.sort()
 if not reverse:
 database.reverse()
 format_output(database)
def read_chunk(fp):
 """Read a chunk -- data for one file, ending with sep1.
 Split the chunk in parts separated by sep2.
 """
 chunk = []
 lines = []
 while 1:
 line = fp.readline()
 if not line:
 break
 if line == sep1:
 if lines:
 chunk.append(lines)
 break
 if line == sep2:
 if lines:
 chunk.append(lines)
 lines = []
 else:
 lines.append(line)
 return chunk
def digest_chunk(chunk):
 """Digest a chunk -- extrach working file name and revisions"""
 lines = chunk[0]
 key = 'Working file:'
 keylen = len(key)
 for line in lines:
 if line[:keylen] == key:
 working_file = string.strip(line[keylen:])
 break
 else:
 working_file = None
 records = []
 for lines in chunk[1:]:
 revline = lines[0]
 dateline = lines[1]
 text = lines[2:]
 words = string.split(dateline)
 author = None
 if len(words) >= 3 and words[0] == 'date:':
 dateword = words[1]
 timeword = words[2]
 if timeword[-1:] == ';':
 timeword = timeword[:-1]
 date = dateword + ' ' + timeword
 if len(words) >= 5 and words[3] == 'author:':
 author = words[4]
 if author[-1:] == ';':
 author = author[:-1]
 else:
 date = None
 text.insert(0, revline)
 words = string.split(revline)
 if len(words) >= 2 and words[0] == 'revision':
 rev = words[1]
 else:
 rev = None
 text.insert(0, revline)
 records.append((date, working_file, rev, author, text))
 return records
def format_output(database):
 prevtext = None
 prev = []
 database.append((None, None, None, None, None)) # Sentinel
 for (date, working_file, rev, author, text) in database:
 if text != prevtext:
 if prev:
 print sep2,
 for (p_date, p_working_file, p_rev, p_author) in prev:
 print p_date, p_author, p_working_file, p_rev
 sys.stdout.writelines(prevtext)
 prev = []
 prev.append((date, working_file, rev, author))
 prevtext = text
main()
--- NEW FILE: mailerdaemon.py ---
"""mailerdaemon - classes to parse mailer-daemon messages"""
import string
import rfc822
import calendar
import re
import os
import sys
Unparseable = 'mailerdaemon.Unparseable'
class ErrorMessage(rfc822.Message):
 def __init__(self, fp):
 rfc822.Message.__init__(self, fp)
 self.sub = ''
 def is_warning(self):
 sub = self.getheader('Subject')
 if not sub:
 return 0
 sub = string.lower(sub)
 if sub[:12] == 'waiting mail': return 1
 if string.find(sub, 'warning') >= 0: return 1
 self.sub = sub
 return 0
 def get_errors(self):
 for p in EMPARSERS:
 self.rewindbody()
 try:
 return p(self.fp, self.sub)
 except Unparseable:
 pass
 raise Unparseable
# List of re's or tuples of re's.
# If a re, it should contain at least a group (?P<email>...) which
# should refer to the email address. The re can also contain a group
# (?P<reason>...) which should refer to the reason (error message).
# If no reason is present, the emparse_list_reason list is used to
# find a reason.
# If a tuple, the tuple should contain 2 re's. The first re finds a
# location, the second re is repeated one or more times to find
# multiple email addresses. The second re is matched (not searched)
# where the previous match ended.
# The re's are compiled using the re module.
emparse_list_list = [
 'error: (?P<reason>unresolvable): (?P<email>.+)',
 ('----- The following addresses had permanent fatal errors -----\n',
 '(?P<email>[^ \n].*)\n( .*\n)?'),
 'remote execution.*\n.*rmail (?P<email>.+)',
 ('The following recipients did not receive your message:\n\n',
 ' +(?P<email>.*)\n(The following recipients did not receive your message:\n\n)?'),
 '------- Failure Reasons --------\n\n(?P<reason>.*)\n(?P<email>.*)',
 '^<(?P<email>.*)>:\n(?P<reason>.*)',
 '^(?P<reason>User mailbox exceeds allowed size): (?P<email>.+)',
 '^5\\d{2} <(?P<email>[^\n>]+)>\\.\\.\\. (?P<reason>.+)',
 '^Original-Recipient: rfc822;(?P<email>.*)',
 '^did not reach the following recipient\\(s\\):\n\n(?P<email>.*) on .*\n +(?P<reason>.*)',
 '^ <(?P<email>[^\n>]+)> \\.\\.\\. (?P<reason>.*)',
 '^Report on your message to: (?P<email>.*)\nReason: (?P<reason>.*)',
 '^Your message was not delivered to +(?P<email>.*)\n +for the following reason:\n +(?P<reason>.*)',
 '^ was not +(?P<email>[^ \n].*?) *\n.*\n.*\n.*\n because:.*\n +(?P<reason>[^ \n].*?) *\n',
 ]
# compile the re's in the list and store them in-place.
for i in range(len(emparse_list_list)):
 x = emparse_list_list[i]
 if type(x) is type(''):
 x = re.compile(x, re.MULTILINE)
 else:
 xl = []
 for x in x:
 xl.append(re.compile(x, re.MULTILINE))
 x = tuple(xl)
 del xl
 emparse_list_list[i] = x
 del x
del i
# list of re's used to find reasons (error messages).
# if a string, "<>" is replaced by a copy of the email address.
# The expressions are searched for in order. After the first match,
# no more expressions are searched for. So, order is important.
emparse_list_reason = [
 r'^5\d{2} <>\.\.\. (?P<reason>.*)',
 '<>\.\.\. (?P<reason>.*)',
 re.compile(r'^<<< 5\d{2} (?P<reason>.*)', re.MULTILINE),
 re.compile('===== stderr was =====\nrmail: (?P<reason>.*)'),
 re.compile('^Diagnostic-Code: (?P<reason>.*)', re.MULTILINE),
 ]
emparse_list_from = re.compile('^From:', re.IGNORECASE|re.MULTILINE)
def emparse_list(fp, sub):
 data = fp.read()
 res = emparse_list_from.search(data)
 if res is None:
 from_index = len(data)
 else:
 from_index = res.start(0)
 errors = []
 emails = []
 reason = None
 for regexp in emparse_list_list:
 if type(regexp) is type(()):
 res = regexp[0].search(data, 0, from_index)
 if res is not None:
 try:
 reason = res.group('reason')
 except IndexError:
 pass
 while 1:
 res = regexp[1].match(data, res.end(0), from_index)
 if res is None:
 break
 emails.append(res.group('email'))
 break
 else:
 res = regexp.search(data, 0, from_index)
 if res is not None:
 emails.append(res.group('email'))
 try:
 reason = res.group('reason')
 except IndexError:
 pass
 break
 if not emails:
 raise Unparseable
 if not reason:
 reason = sub
 if reason[:15] == 'returned mail: ':
 reason = reason[15:]
 for regexp in emparse_list_reason:
 if type(regexp) is type(''):
 for i in range(len(emails)-1,-1,-1):
 email = emails[i]
 exp = re.compile(string.join(string.split(regexp, '<>'), re.escape(email)), re.MULTILINE)
 res = exp.search(data)
 if res is not None:
 errors.append(string.join(string.split(string.strip(email)+': '+res.group('reason'))))
 del emails[i]
 continue
 res = regexp.search(data)
 if res is not None:
 reason = res.group('reason')
 break
 for email in emails:
 errors.append(string.join(string.split(string.strip(email)+': '+reason)))
 return errors
EMPARSERS = [emparse_list, ]
def sort_numeric(a, b):
 a = string.atoi(a)
 b = string.atoi(b)
 if a < b: return -1
 elif a > b: return 1
 else: return 0
def parsedir(dir, modify):
 os.chdir(dir)
 pat = re.compile('^[0-9]*$')
 errordict = {}
 errorfirst = {}
 errorlast = {}
 nok = nwarn = nbad = 0
 # find all numeric file names and sort them
 files = filter(lambda fn, pat=pat: pat.match(fn) is not None, os.listdir('.'))
 files.sort(sort_numeric)
 for fn in files:
 # Lets try to parse the file.
 fp = open(fn)
 m = ErrorMessage(fp)
 sender = m.getaddr('From')
 print '%s\t%-40s\t'%(fn, sender[1]),
 if m.is_warning():
 fp.close()
 print 'warning only'
 nwarn = nwarn + 1
 if modify:
 os.rename(fn, ','+fn)
## os.unlink(fn)
 continue
 try:
 errors = m.get_errors()
 except Unparseable:
 print '** Not parseable'
 nbad = nbad + 1
 fp.close()
 continue
 print len(errors), 'errors'
 # Remember them
 for e in errors:
 try:
 mm, dd = m.getdate('date')[1:1+2]
 date = '%s %02d' % (calendar.month_abbr[mm], dd)
 except:
 date = '??????'
 if not errordict.has_key(e):
 errordict[e] = 1
 errorfirst[e] = '%s (%s)' % (fn, date)
 else:
 errordict[e] = errordict[e] + 1
 errorlast[e] = '%s (%s)' % (fn, date)
 fp.close()
 nok = nok + 1
 if modify:
 os.rename(fn, ','+fn)
## os.unlink(fn)
 print '--------------'
 print nok, 'files parsed,',nwarn,'files warning-only,',
 print nbad,'files unparseable'
 print '--------------'
 list = []
 for e in errordict.keys():
 list.append((errordict[e], errorfirst[e], errorlast[e], e))
 list.sort()
 for num, first, last, e in list:
 print '%d %s - %s\t%s' % (num, first, last, e)
def main():
 modify = 0
 if len(sys.argv) > 1 and sys.argv[1] == '-d':
 modify = 1
 del sys.argv[1]
 if len(sys.argv) > 1:
 for folder in sys.argv[1:]:
 parsedir(folder, modify)
 else:
 parsedir('/ufs/jack/Mail/errorsinbox', modify)
if __name__ == '__main__' or sys.argv[0] == __name__:
 main()
--- NEW FILE: md5sum.py ---
#! /usr/bin/env python
"""Python utility to print MD5 checksums of argument files.
Works with Python 1.5.2 and later.
"""
import sys, md5
BLOCKSIZE = 1024*1024
def hexify(s):
 return ("%02x"*len(s)) % tuple(map(ord, s))
def main():
 args = sys.argv[1:]
 if not args:
 sys.stderr.write("usage: %s file ...\n" % sys.argv[0])
 sys.exit(2)
 for file in sys.argv[1:]:
 f = open(file, "rb")
 sum = md5.new()
 while 1:
 block = f.read(BLOCKSIZE)
 if not block:
 break
 sum.update(block)
 f.close()
 print hexify(sum.digest()), file
if __name__ == "__main__":
 main()
--- NEW FILE: methfix.py ---
#! /usr/bin/env python
# Fix Python source files to avoid using
# def method(self, (arg1, ..., argn)):
# instead of the more rational
# def method(self, arg1, ..., argn):
#
# 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 regex
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 = regex.compile('^[a-zA-Z0-9_]+\.py$')
def ispython(name):
 return ispythonprog.match(name) >= 0
def recursedown(dirname):
 dbg('recursedown(' + `dirname` + ')\n')
 bad = 0
 try:
 names = os.listdir(dirname)
 except os.error, msg:
 err(dirname + ': cannot list directory: ' + `msg` + '\n')
 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(' + `filename` + ')\n')
 try:
 f = open(filename, 'r')
 except IOError, msg:
 err(filename + ': cannot open: ' + `msg` + '\n')
 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 regex.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, msg:
 f.close()
 err(tempname+': cannot create: '+\
 `msg`+'\n')
 return 1
 f.seek(0)
 lineno = 0
 rep(filename + ':\n')
 continue # restart from the beginning
 rep(`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] & 07777)
 except os.error, msg:
 err(tempname + ': warning: chmod failed (' + `msg` + ')\n')
 # Then make a backup of the original file as filename~
 try:
 os.rename(filename, filename + '~')
 except os.error, msg:
 err(filename + ': warning: backup failed (' + `msg` + ')\n')
 # Now move the temp file to the original file
 try:
 os.rename(tempname, filename)
 except os.error, msg:
 err(filename + ': rename failed (' + `msg` + ')\n')
 return 1
 # Return succes
 return 0
fixpat = '^[ \t]+def +[a-zA-Z0-9_]+ *( *self *, *\(( *\(.*\) *)\) *) *:'
fixprog = regex.compile(fixpat)
def fixline(line):
 if fixprog.match(line) >= 0:
 (a, b), (c, d) = fixprog.regs[1:3]
 line = line[:a] + line[c:d] + line[b:]
 return line
main()
--- NEW FILE: mkreal.py ---
#! /usr/bin/env python
# mkreal
#
# turn a symlink to a directory into a real directory
import sys
import os
from stat import *
join = os.path.join
error = 'mkreal error'
BUFSIZE = 32*1024
def mkrealfile(name):
 st = os.stat(name) # Get the mode
 mode = S_IMODE(st[ST_MODE])
 linkto = os.readlink(name) # Make sure again it's a symlink
 f_in = open(name, 'r') # This ensures it's a file
 os.unlink(name)
 f_out = open(name, 'w')
 while 1:
 buf = f_in.read(BUFSIZE)
 if not buf: break
 f_out.write(buf)
 del f_out # Flush data to disk before changing mode
 os.chmod(name, mode)
def mkrealdir(name):
 st = os.stat(name) # Get the mode
 mode = S_IMODE(st[ST_MODE])
 linkto = os.readlink(name)
 files = os.listdir(name)
 os.unlink(name)
 os.mkdir(name, mode)
 os.chmod(name, mode)
 linkto = join(os.pardir, linkto)
 #
 for file in files:
 if file not in (os.curdir, os.pardir):
 os.symlink(join(linkto, file), join(name, file))
def main():
 sys.stdout = sys.stderr
 progname = os.path.basename(sys.argv[0])
 if progname == '-c': progname = 'mkreal'
 args = sys.argv[1:]
 if not args:
 print 'usage:', progname, 'path ...'
 sys.exit(2)
 status = 0
 for name in args:
 if not os.path.islink(name):
 print progname+':', name+':', 'not a symlink'
 status = 1
 else:
 if os.path.isdir(name):
 mkrealdir(name)
 else:
 mkrealfile(name)
 sys.exit(status)
main()
--- NEW FILE: ndiff.py ---
#! /usr/bin/env python
# Module ndiff version 1.6.0
# Released to the public domain 08-Dec-2000,
# by Tim Peters (tim.one@home.com).
# Provided as-is; use at your own risk; no warranty; no promises; enjoy!
"""ndiff [-q] file1 file2
 or
ndiff (-r1 | -r2) < ndiff_output > file1_or_file2
Print a human-friendly file difference report to stdout. Both inter-
and intra-line differences are noted. In the second form, recreate file1
(-r1) or file2 (-r2) on stdout, from an ndiff report on stdin.
In the first form, if -q ("quiet") is not specified, the first two lines
of output are
-: file1
+: file2
Each remaining line begins with a two-letter code:
 "- " line unique to file1
 "+ " line unique to file2
 " " line common to both files
 "? " line not present in either input file
Lines beginning with "? " attempt to guide the eye to intraline
differences, and were not present in either input file. These lines can be
confusing if the source files contain tab characters.
The first file can be recovered by retaining only lines that begin with
" " or "- ", and deleting those 2-character prefixes; use ndiff with -r1.
The second file can be recovered similarly, but by retaining only " " and
"+ " lines; use ndiff with -r2; or, on Unix, the second file can be
recovered by piping the output through
 sed -n '/^[+ ] /s/^..//p'
See module comments for details and programmatic interface.
"""
__version__ = 1, 5, 0
# SequenceMatcher tries to compute a "human-friendly diff" between
# two sequences (chiefly picturing a file as a sequence of lines,
# and a line as a sequence of characters, here). Unlike e.g. UNIX(tm)
# diff, the fundamental notion is the longest *contiguous* & junk-free
# matching subsequence. That's what catches peoples' eyes. The
# Windows(tm) windiff has another interesting notion, pairing up elements
# that appear uniquely in each sequence. That, and the method here,
# appear to yield more intuitive difference reports than does diff. This
# method appears to be the least vulnerable to synching up on blocks
# of "junk lines", though (like blank lines in ordinary text files,
# or maybe "<P>" lines in HTML files). That may be because this is
# the only method of the 3 that has a *concept* of "junk" <wink>.
#
# Note that ndiff makes no claim to produce a *minimal* diff. To the
# contrary, minimal diffs are often counter-intuitive, because they
# synch up anywhere possible, sometimes accidental matches 100 pages
# apart. Restricting synch points to contiguous matches preserves some
# notion of locality, at the occasional cost of producing a longer diff.
#
# With respect to junk, an earlier version of ndiff simply refused to
# *start* a match with a junk element. The result was cases like this:
# before: private Thread currentThread;
# after: private volatile Thread currentThread;
# If you consider whitespace to be junk, the longest contiguous match
# not starting with junk is "e Thread currentThread". So ndiff reported
# that "e volatil" was inserted between the 't' and the 'e' in "private".
# While an accurate view, to people that's absurd. The current version
# looks for matching blocks that are entirely junk-free, then extends the
# longest one of those as far as possible but only with matching junk.
# So now "currentThread" is matched, then extended to suck up the
# preceding blank; then "private" is matched, and extended to suck up the
# following blank; then "Thread" is matched; and finally ndiff reports
# that "volatile " was inserted before "Thread". The only quibble
# remaining is that perhaps it was really the case that " volatile"
# was inserted after "private". I can live with that <wink>.
#
# NOTE on junk: the module-level names
# IS_LINE_JUNK
# IS_CHARACTER_JUNK
# can be set to any functions you like. The first one should accept
# a single string argument, and return true iff the string is junk.
# The default is whether the regexp r"\s*#?\s*$" matches (i.e., a
# line without visible characters, except for at most one splat).
# The second should accept a string of length 1 etc. The default is
# whether the character is a blank or tab (note: bad idea to include
# newline in this!).
#
# After setting those, you can call fcompare(f1name, f2name) with the
# names of the files you want to compare. The difference report
# is sent to stdout. Or you can call main(args), passing what would
# have been in sys.argv[1:] had the cmd-line form been used.
from difflib import SequenceMatcher
import string
TRACE = 0
# define what "junk" means
import re
def IS_LINE_JUNK(line, pat=re.compile(r"\s*#?\s*$").match):
 return pat(line) is not None
def IS_CHARACTER_JUNK(ch, ws=" \t"):
 return ch in ws
del re
# meant for dumping lines
def dump(tag, x, lo, hi):
 for i in xrange(lo, hi):
 print tag, x[i],
def plain_replace(a, alo, ahi, b, blo, bhi):
 assert alo < ahi and blo < bhi
 # dump the shorter block first -- reduces the burden on short-term
 # memory if the blocks are of very different sizes
 if bhi - blo < ahi - alo:
 dump('+', b, blo, bhi)
 dump('-', a, alo, ahi)
 else:
 dump('-', a, alo, ahi)
 dump('+', b, blo, bhi)
# When replacing one block of lines with another, this guy searches
# the blocks for *similar* lines; the best-matching pair (if any) is
# used as a synch point, and intraline difference marking is done on
# the similar pair. Lots of work, but often worth it.
def fancy_replace(a, alo, ahi, b, blo, bhi):
 if TRACE:
 print '*** fancy_replace', alo, ahi, blo, bhi
 dump('>', a, alo, ahi)
 dump('<', b, blo, bhi)
 # don't synch up unless the lines have a similarity score of at
 # least cutoff; best_ratio tracks the best score seen so far
 best_ratio, cutoff = 0.74, 0.75
 cruncher = SequenceMatcher(IS_CHARACTER_JUNK)
 eqi, eqj = None, None # 1st indices of equal lines (if any)
 # search for the pair that matches best without being identical
 # (identical lines must be junk lines, & we don't want to synch up
 # on junk -- unless we have to)
 for j in xrange(blo, bhi):
 bj = b[j]
 cruncher.set_seq2(bj)
 for i in xrange(alo, ahi):
 ai = a[i]
 if ai == bj:
 if eqi is None:
 eqi, eqj = i, j
 continue
 cruncher.set_seq1(ai)
 # computing similarity is expensive, so use the quick
 # upper bounds first -- have seen this speed up messy
 # compares by a factor of 3.
 # note that ratio() is only expensive to compute the first
 # time it's called on a sequence pair; the expensive part
 # of the computation is cached by cruncher
 if cruncher.real_quick_ratio() > best_ratio and \
 cruncher.quick_ratio() > best_ratio and \
 cruncher.ratio() > best_ratio:
 best_ratio, best_i, best_j = cruncher.ratio(), i, j
 if best_ratio < cutoff:
 # no non-identical "pretty close" pair
 if eqi is None:
 # no identical pair either -- treat it as a straight replace
 plain_replace(a, alo, ahi, b, blo, bhi)
 return
 # no close pair, but an identical pair -- synch up on that
 best_i, best_j, best_ratio = eqi, eqj, 1.0
 else:
 # there's a close pair, so forget the identical pair (if any)
 eqi = None
 # a[best_i] very similar to b[best_j]; eqi is None iff they're not
 # identical
 if TRACE:
 print '*** best_ratio', best_ratio, best_i, best_j
 dump('>', a, best_i, best_i+1)
 dump('<', b, best_j, best_j+1)
 # pump out diffs from before the synch point
 fancy_helper(a, alo, best_i, b, blo, best_j)
 # do intraline marking on the synch pair
 aelt, belt = a[best_i], b[best_j]
 if eqi is None:
 # pump out a '-', '?', '+', '?' quad for the synched lines
 atags = btags = ""
 cruncher.set_seqs(aelt, belt)
 for tag, ai1, ai2, bj1, bj2 in cruncher.get_opcodes():
 la, lb = ai2 - ai1, bj2 - bj1
 if tag == 'replace':
 atags += '^' * la
 btags += '^' * lb
 elif tag == 'delete':
 atags += '-' * la
 elif tag == 'insert':
 btags += '+' * lb
 elif tag == 'equal':
 atags += ' ' * la
 btags += ' ' * lb
 else:
 raise ValueError, 'unknown tag ' + `tag`
 printq(aelt, belt, atags, btags)
 else:
 # the synch pair is identical
 print ' ', aelt,
 # pump out diffs from after the synch point
 fancy_helper(a, best_i+1, ahi, b, best_j+1, bhi)
def fancy_helper(a, alo, ahi, b, blo, bhi):
 if alo < ahi:
 if blo < bhi:
 fancy_replace(a, alo, ahi, b, blo, bhi)
 else:
 dump('-', a, alo, ahi)
 elif blo < bhi:
 dump('+', b, blo, bhi)
# Crap to deal with leading tabs in "?" output. Can hurt, but will
# probably help most of the time.
def printq(aline, bline, atags, btags):
 common = min(count_leading(aline, "\t"),
 count_leading(bline, "\t"))
 common = min(common, count_leading(atags[:common], " "))
 print "-", aline,
 if count_leading(atags, " ") < len(atags):
 print "?", "\t" * common + atags[common:]
 print "+", bline,
 if count_leading(btags, " ") < len(btags):
 print "?", "\t" * common + btags[common:]
def count_leading(line, ch):
 i, n = 0, len(line)
 while i < n and line[i] == ch:
 i += 1
 return i
def fail(msg):
 import sys
 out = sys.stderr.write
 out(msg + "\n\n")
 out(__doc__)
 return 0
# open a file & return the file object; gripe and return 0 if it
# couldn't be opened
def fopen(fname):
 try:
 return open(fname, 'r')
 except IOError, detail:
 return fail("couldn't open " + fname + ": " + str(detail))
# open two files & spray the diff to stdout; return false iff a problem
def fcompare(f1name, f2name):
 f1 = fopen(f1name)
 f2 = fopen(f2name)
 if not f1 or not f2:
 return 0
 a = f1.readlines(); f1.close()
 b = f2.readlines(); f2.close()
 cruncher = SequenceMatcher(IS_LINE_JUNK, a, b)
 for tag, alo, ahi, blo, bhi in cruncher.get_opcodes():
 if tag == 'replace':
 fancy_replace(a, alo, ahi, b, blo, bhi)
 elif tag == 'delete':
 dump('-', a, alo, ahi)
 elif tag == 'insert':
 dump('+', b, blo, bhi)
 elif tag == 'equal':
 dump(' ', a, alo, ahi)
 else:
 raise ValueError, 'unknown tag ' + `tag`
 return 1
# crack args (sys.argv[1:] is normal) & compare;
# return false iff a problem
def main(args):
 import getopt
 try:
 opts, args = getopt.getopt(args, "qr:")
 except getopt.error, detail:
 return fail(str(detail))
 noisy = 1
 qseen = rseen = 0
 for opt, val in opts:
 if opt == "-q":
 qseen = 1
 noisy = 0
 elif opt == "-r":
 rseen = 1
 whichfile = val
 if qseen and rseen:
 return fail("can't specify both -q and -r")
 if rseen:
 if args:
 return fail("no args allowed with -r option")
 if whichfile in "12":
 restore(whichfile)
 return 1
 return fail("-r value must be 1 or 2")
 if len(args) != 2:
 return fail("need 2 filename args")
 f1name, f2name = args
 if noisy:
 print '-:', f1name
 print '+:', f2name
 return fcompare(f1name, f2name)
def restore(which):
 import sys
 tag = {"1": "- ", "2": "+ "}[which]
 prefixes = (" ", tag)
 for line in sys.stdin.readlines():
 if line[:2] in prefixes:
 print line[2:],
if __name__ == '__main__':
 import sys
 args = sys.argv[1:]
 if "-profile" in args:
 import profile, pstats
 args.remove("-profile")
 statf = "ndiff.pro"
 profile.run("main(args)", statf)
 stats = pstats.Stats(statf)
 stats.strip_dirs().sort_stats('time').print_stats()
 else:
 main(args)
--- NEW FILE: nm2def.py ---
#! /usr/bin/env python
"""nm2def.py
Helpers to extract symbols from Unix libs and auto-generate
Windows definition files from them. Depends on nm(1). Tested
on Linux and Solaris only (-p option to nm is for Solaris only).
By Marc-Andre Lemburg, Aug 1998.
Additional notes: the output of nm is supposed to look like this:
acceler.o:
000001fd T PyGrammar_AddAccelerators
 U PyGrammar_FindDFA
00000237 T PyGrammar_RemoveAccelerators
 U _IO_stderr_
 U exit
 U fprintf
 U free
 U malloc
 U printf
grammar1.o:
00000000 T PyGrammar_FindDFA
00000034 T PyGrammar_LabelRepr
 U _PyParser_TokenNames
 U abort
 U printf
 U sprintf
...
Even if this isn't the default output of your nm, there is generally an
option to produce this format (since it is the original v7 Unix format).
"""
import os,re,string,sys
PYTHONLIB = 'libpython'+sys.version[:3]+'.a'
PC_PYTHONLIB = 'Python'+sys.version[0]+sys.version[2]+'.dll'
NM = 'nm -p -g %s' # For Linux, use "nm -g %s"
def symbols(lib=PYTHONLIB,types=('T','C','D')):
 lines = os.popen(NM % lib).readlines()
 lines = map(string.strip,lines)
 symbols = {}
 for line in lines:
 if len(line) == 0 or ':' in line:
 continue
 items = string.split(line)
 if len(items) != 3:
 continue
 address, type, name = items
 if type not in types:
 continue
 symbols[name] = address,type
 return symbols
def export_list(symbols):
 data = []
 code = []
 for name,(addr,type) in symbols.items():
 if type in ('C','D'):
 data.append('\t'+name)
 else:
 code.append('\t'+name)
 data.sort()
 data.append('')
 code.sort()
 return string.join(data,' DATA\n')+'\n'+string.join(code,'\n')
# Definition file template
DEF_TEMPLATE = """\
EXPORTS
%s
"""
# Special symbols that have to be included even though they don't
# pass the filter
SPECIALS = (
 )
def filter_Python(symbols,specials=SPECIALS):
 for name in symbols.keys():
 if name[:2] == 'Py' or name[:3] == '_Py':
 pass
 elif name not in specials:
 del symbols[name]
def main():
 s = symbols(PYTHONLIB)
 filter_Python(s)
 exports = export_list(s)
 f = sys.stdout # open('PC/python_nt.def','w')
 f.write(DEF_TEMPLATE % (exports))
 f.close()
if __name__ == '__main__':
 main()
--- NEW FILE: objgraph.py ---
#! /usr/bin/env python
# objgraph
#
# Read "nm -o" input (on IRIX: "nm -Bo") of a set of libraries or modules
# and print various interesting listings, such as:
#
# - which names are used but not defined in the set (and used where),
# - which names are defined in the set (and where),
# - which modules use which other modules,
# - which modules are used by which other modules.
#
# Usage: objgraph [-cdu] [file] ...
# -c: print callers per objectfile
# -d: print callees per objectfile
# -u: print usage of undefined symbols
# If none of -cdu is specified, all are assumed.
# Use "nm -o" to generate the input (on IRIX: "nm -Bo"),
# e.g.: nm -o /lib/libc.a | objgraph
import sys
import string
import os
import getopt
import regex
# Types of symbols.
#
definitions = 'TRGDSBAEC'
externals = 'UV'
ignore = 'Nntrgdsbavuc'
# Regular expression to parse "nm -o" output.
#
matcher = regex.compile('\(.*\):\t?........ \(.\) \(.*\)$')
# Store "item" in "dict" under "key".
# The dictionary maps keys to lists of items.
# If there is no list for the key yet, it is created.
#
def store(dict, key, item):
 if dict.has_key(key):
 dict[key].append(item)
 else:
 dict[key] = [item]
# Return a flattened version of a list of strings: the concatenation
# of its elements with intervening spaces.
#
def flat(list):
 s = ''
 for item in list:
 s = s + ' ' + item
 return s[1:]
# Global variables mapping defined/undefined names to files and back.
#
file2undef = {}
def2file = {}
file2def = {}
undef2file = {}
# Read one input file and merge the data into the tables.
# Argument is an open file.
#
def readinput(file):
 while 1:
 s = file.readline()
 if not s:
 break
 # If you get any output from this line,
 # it is probably caused by an unexpected input line:
 if matcher.search(s) < 0: s; continue # Shouldn't happen
 (ra, rb), (r1a, r1b), (r2a, r2b), (r3a, r3b) = matcher.regs[:4]
 fn, name, type = s[r1a:r1b], s[r3a:r3b], s[r2a:r2b]
 if type in definitions:
 store(def2file, name, fn)
 store(file2def, fn, name)
 elif type in externals:
 store(file2undef, fn, name)
 store(undef2file, name, fn)
 elif not type in ignore:
 print fn + ':' + name + ': unknown type ' + type
# Print all names that were undefined in some module and where they are
# defined.
#
def printcallee():
 flist = file2undef.keys()
 flist.sort()
 for file in flist:
 print file + ':'
 elist = file2undef[file]
 elist.sort()
 for ext in elist:
 if len(ext) >= 8:
 tabs = '\t'
 else:
 tabs = '\t\t'
 if not def2file.has_key(ext):
 print '\t' + ext + tabs + ' *undefined'
 else:
 print '\t' + ext + tabs + flat(def2file[ext])
# Print for each module the names of the other modules that use it.
#
def printcaller():
 files = file2def.keys()
 files.sort()
 for file in files:
 callers = []
 for label in file2def[file]:
 if undef2file.has_key(label):
 callers = callers + undef2file[label]
 if callers:
 callers.sort()
 print file + ':'
 lastfn = ''
 for fn in callers:
 if fn <> lastfn:
 print '\t' + fn
 lastfn = fn
 else:
 print file + ': unused'
# Print undefine names and where they are used.
#
def printundef():
 undefs = {}
 for file in file2undef.keys():
 for ext in file2undef[file]:
 if not def2file.has_key(ext):
 store(undefs, ext, file)
 elist = undefs.keys()
 elist.sort()
 for ext in elist:
 print ext + ':'
 flist = undefs[ext]
 flist.sort()
 for file in flist:
 print '\t' + file
# Print warning messages about names defined in more than one file.
#
def warndups():
 savestdout = sys.stdout
 sys.stdout = sys.stderr
 names = def2file.keys()
 names.sort()
 for name in names:
 if len(def2file[name]) > 1:
 print 'warning:', name, 'multiply defined:',
 print flat(def2file[name])
 sys.stdout = savestdout
# Main program
#
def main():
 try:
 optlist, args = getopt.getopt(sys.argv[1:], 'cdu')
 except getopt.error:
 sys.stdout = sys.stderr
 print 'Usage:', os.path.basename(sys.argv[0]),
 print '[-cdu] [file] ...'
 print '-c: print callers per objectfile'
 print '-d: print callees per objectfile'
 print '-u: print usage of undefined symbols'
 print 'If none of -cdu is specified, all are assumed.'
 print 'Use "nm -o" to generate the input (on IRIX: "nm -Bo"),'
 print 'e.g.: nm -o /lib/libc.a | objgraph'
 return 1
 optu = optc = optd = 0
 for opt, void in optlist:
 if opt == '-u':
 optu = 1
 elif opt == '-c':
 optc = 1
 elif opt == '-d':
 optd = 1
 if optu == optc == optd == 0:
 optu = optc = optd = 1
 if not args:
 args = ['-']
 for file in args:
 if file == '-':
 readinput(sys.stdin)
 else:
 readinput(open(file, 'r'))
 #
 warndups()
 #
 more = (optu + optc + optd > 1)
 if optd:
 if more:
 print '---------------All callees------------------'
 printcallee()
 if optu:
 if more:
 print '---------------Undefined callees------------'
 printundef()
 if optc:
 if more:
 print '---------------All Callers------------------'
 printcaller()
 return 0
# Call the main program.
# Use its return value as exit status.
# Catch interrupts to avoid stack trace.
#
try:
 sys.exit(main())
except KeyboardInterrupt:
 sys.exit(1)
--- NEW FILE: parseentities.py ---
#!/usr/local/bin/python
""" Utility for parsing HTML entity definitions available from:
 http://www.w3.org/ as e.g.
 http://www.w3.org/TR/REC-html40/HTMLlat1.ent
 Input is read from stdin, output is written to stdout in form of a
 Python snippet defining a dictionary "entitydefs" mapping literal
 entity name to character or numeric entity.
 Marc-Andre Lemburg, mal@lemburg.com, 1999.
 Use as you like. NO WARRANTIES.
"""
import re,sys
import TextTools
entityRE = re.compile('<!ENTITY +(\w+) +CDATA +"([^"]+)" +-- +((?:.|\n)+?) *-->')
def parse(text,pos=0,endpos=None):
 pos = 0
 if endpos is None:
 endpos = len(text)
 d = {}
 while 1:
 m = entityRE.search(text,pos,endpos)
 if not m:
 break
 name,charcode,comment = m.groups()
 d[name] = charcode,comment
 pos = m.end()
 return d
def writefile(f,defs):
 f.write("entitydefs = {\n")
 items = defs.items()
 items.sort()
 for name,(charcode,comment) in items:
 if charcode[:2] == '&#':
 code = int(charcode[2:-1])
 if code < 256:
 charcode = "'\%o'" % code
 else:
 charcode = repr(charcode)
 else:
 charcode = repr(charcode)
 comment = TextTools.collapse(comment)
 f.write(" '%s':\t%s, \t# %s\n" % (name,charcode,comment))
 f.write('\n}\n')
if __name__ == '__main__':
 if len(sys.argv) > 1:
 infile = open(sys.argv[1])
 else:
 infile = sys.stdin
 if len(sys.argv) > 2:
 outfile = open(sys.argv[2],'w')
 else:
 outfile = sys.stdout
 text = infile.read()
 defs = parse(text)
 writefile(outfile,defs)
--- NEW FILE: pathfix.py ---
#! /usr/bin/env python
# Change the #! line occurring in Python scripts. The new interpreter
# pathname must be given with a -i option.
#
# 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).
#
# 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 fixfile() you can turn this
# into a program for a different change to Python programs...
import sys
import regex
import os
from stat import *
import string
import getopt
err = sys.stderr.write
dbg = err
rep = sys.stdout.write
new_interpreter = None
def main():
 global new_interpreter
 usage = ('usage: %s -i /interpreter file-or-directory ...\n' %
 sys.argv[0])
 try:
 opts, args = getopt.getopt(sys.argv[1:], 'i:')
 except getopt.error, msg:
 err(msg + '\n')
 err(usage)
 sys.exit(2)
 for o, a in opts:
 if o == '-i':
 new_interpreter = a
 if not new_interpreter or new_interpreter[0] != '/' or not args:
 err('-i option or file-or-directory missing\n')
 err(usage)
 sys.exit(2)
 bad = 0
 for arg in args:
 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 = regex.compile('^[a-zA-Z0-9_]+\.py$')
def ispython(name):
 return ispythonprog.match(name) >= 0
def recursedown(dirname):
 dbg('recursedown(' + `dirname` + ')\n')
 bad = 0
 try:
 names = os.listdir(dirname)
 except os.error, msg:
 err(dirname + ': cannot list directory: ' + `msg` + '\n')
 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(' + `filename` + ')\n')
 try:
 f = open(filename, 'r')
 except IOError, msg:
 err(filename + ': cannot open: ' + `msg` + '\n')
 return 1
 line = f.readline()
 fixed = fixline(line)
 if line == fixed:
 rep(filename+': no change\n')
 f.close()
 return
 head, tail = os.path.split(filename)
 tempname = os.path.join(head, '@' + tail)
 try:
 g = open(tempname, 'w')
 except IOError, msg:
 f.close()
 err(tempname+': cannot create: '+`msg`+'\n')
 return 1
 rep(filename + ': updating\n')
 g.write(fixed)
 BUFSIZE = 8*1024
 while 1:
 buf = f.read(BUFSIZE)
 if not buf: break
 g.write(buf)
 g.close()
 f.close()
 # 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] & 07777)
 except os.error, msg:
 err(tempname + ': warning: chmod failed (' + `msg` + ')\n')
 # Then make a backup of the original file as filename~
 try:
 os.rename(filename, filename + '~')
 except os.error, msg:
 err(filename + ': warning: backup failed (' + `msg` + ')\n')
 # Now move the temp file to the original file
 try:
 os.rename(tempname, filename)
 except os.error, msg:
 err(filename + ': rename failed (' + `msg` + ')\n')
 return 1
 # Return succes
 return 0
def fixline(line):
 if line[:2] != '#!':
 return line
 if string.find(line, "python") < 0:
 return line
 return '#! %s\n' % new_interpreter
main()
--- NEW FILE: pdeps.py ---
#! /usr/bin/env python
# pdeps
#
# Find dependencies between a bunch of Python modules.
#
# Usage:
# pdeps file1.py file2.py ...
#
# Output:
# Four tables separated by lines like '--- Closure ---':
# 1) Direct dependencies, listing which module imports which other modules
# 2) The inverse of (1)
# 3) Indirect dependencies, or the closure of the above
# 4) The inverse of (3)
#
# To do:
# - command line options to select output type
# - option to automatically scan the Python library for referenced modules
# - option to limit output to particular modules
import sys
import regex
import os
import string
# Main program
#
def main():
 args = sys.argv[1:]
 if not args:
 print 'usage: pdeps file.py file.py ...'
 return 2
 #
 table = {}
 for arg in args:
 process(arg, table)
 #
 print '--- Uses ---'
 printresults(table)
 #
 print '--- Used By ---'
 inv = inverse(table)
 printresults(inv)
 #
 print '--- Closure of Uses ---'
 reach = closure(table)
 printresults(reach)
 #
 print '--- Closure of Used By ---'
 invreach = inverse(reach)
 printresults(invreach)
 #
 return 0
# Compiled regular expressions to search for import statements
#
m_import = regex.compile('^[ \t]*from[ \t]+\([^ \t]+\)[ \t]+')
m_from = regex.compile('^[ \t]*import[ \t]+\([^#]+\)')
# Collect data from one file
#
def process(filename, table):
 fp = open(filename, 'r')
 mod = os.path.basename(filename)
 if mod[-3:] == '.py':
 mod = mod[:-3]
 table[mod] = list = []
 while 1:
 line = fp.readline()
 if not line: break
 while line[-1:] == '\\':
 nextline = fp.readline()
 if not nextline: break
 line = line[:-1] + nextline
 if m_import.match(line) >= 0:
 (a, b), (a1, b1) = m_import.regs[:2]
 elif m_from.match(line) >= 0:
 (a, b), (a1, b1) = m_from.regs[:2]
 else: continue
 words = string.splitfields(line[a1:b1], ',')
 # print '#', line, words
 for word in words:
 word = string.strip(word)
 if word not in list:
 list.append(word)
# Compute closure (this is in fact totally general)
#
def closure(table):
 modules = table.keys()
 #
 # Initialize reach with a copy of table
 #
 reach = {}
 for mod in modules:
 reach[mod] = table[mod][:]
 #
 # Iterate until no more change
 #
 change = 1
 while change:
 change = 0
 for mod in modules:
 for mo in reach[mod]:
 if mo in modules:
 for m in reach[mo]:
 if m not in reach[mod]:
 reach[mod].append(m)
 change = 1
 #
 return reach
# Invert a table (this is again totally general).
# All keys of the original table are made keys of the inverse,
# so there may be empty lists in the inverse.
#
def inverse(table):
 inv = {}
 for key in table.keys():
 if not inv.has_key(key):
 inv[key] = []
 for item in table[key]:
 store(inv, item, key)
 return inv
# Store "item" in "dict" under "key".
# The dictionary maps keys to lists of items.
# If there is no list for the key yet, it is created.
#
def store(dict, key, item):
 if dict.has_key(key):
 dict[key].append(item)
 else:
 dict[key] = [item]
# Tabulate results neatly
#
def printresults(table):
 modules = table.keys()
 maxlen = 0
 for mod in modules: maxlen = max(maxlen, len(mod))
 modules.sort()
 for mod in modules:
 list = table[mod]
 list.sort()
 print string.ljust(mod, maxlen), ':',
 if mod in list:
 print '(*)',
 for ref in list:
 print ref,
 print
# Call main and honor exit status
try:
 sys.exit(main())
except KeyboardInterrupt:
 sys.exit(1)
--- NEW FILE: pindent.py ---
#! /usr/bin/env python
# This file contains a class and a main program that perform three
# related (though complimentary) formatting operations on Python
# programs. When called as "pindent -c", it takes a valid Python
# program as input and outputs a version augmented with block-closing
# comments. When called as "pindent -d", it assumes its input is a
# Python program with block-closing comments and outputs a commentless
# version. When called as "pindent -r" it assumes its input is a
# Python program with block-closing comments but with its indentation
# messed up, and outputs a properly indented version.
# A "block-closing comment" is a comment of the form '# end <keyword>'
# where <keyword> is the keyword that opened the block. If the
# opening keyword is 'def' or 'class', the function or class name may
# be repeated in the block-closing comment as well. Here is an
# example of a program fully augmented with block-closing comments:
# def foobar(a, b):
# if a == b:
# a = a+1
# elif a < b:
# b = b-1
# if b > a: a = a-1
# # end if
# else:
# print 'oops!'
# # end if
# # end def foobar
# Note that only the last part of an if...elif...else... block needs a
# block-closing comment; the same is true for other compound
# statements (e.g. try...except). Also note that "short-form" blocks
# like the second 'if' in the example must be closed as well;
# otherwise the 'else' in the example would be ambiguous (remember
# that indentation is not significant when interpreting block-closing
# comments).
# The operations are idempotent (i.e. applied to their own output
# they yield an identical result). Running first "pindent -c" and
# then "pindent -r" on a valid Python program produces a program that
# is semantically identical to the input (though its indentation may
# be different). Running "pindent -e" on that output produces a
# program that only differs from the original in indentation.
# Other options:
# -s stepsize: set the indentation step size (default 8)
# -t tabsize : set the number of spaces a tab character is worth (default 8)
# -e : expand TABs into spaces
# file ... : input file(s) (default standard input)
# The results always go to standard output
# Caveats:
# - comments ending in a backslash will be mistaken for continued lines
# - continuations using backslash are always left unchanged
# - continuations inside parentheses are not extra indented by -r
# but must be indented for -c to work correctly (this breaks
# idempotency!)
# - continued lines inside triple-quoted strings are totally garbled
# Secret feature:
# - On input, a block may also be closed with an "end statement" --
# this is a block-closing comment without the '#' sign.
# Possible improvements:
# - check syntax based on transitions in 'next' table
# - better error reporting
# - better error recovery
# - check identifier after class/def
# The following wishes need a more complete tokenization of the source:
# - Don't get fooled by comments ending in backslash
# - reindent continuation lines indicated by backslash
# - handle continuation lines inside parentheses/braces/brackets
# - handle triple quoted strings spanning lines
# - realign comments
# - optionally do much more thorough reformatting, a la C indent
# Defaults
STEPSIZE = 8
TABSIZE = 8
EXPANDTABS = 0
import os
import re
import string
import sys
next = {}
next['if'] = next['elif'] = 'elif', 'else', 'end'
next['while'] = next['for'] = 'else', 'end'
next['try'] = 'except', 'finally'
next['except'] = 'except', 'else', 'end'
next['else'] = next['finally'] = next['def'] = next['class'] = 'end'
next['end'] = ()
start = 'if', 'while', 'for', 'try', 'def', 'class'
class PythonIndenter:
 def __init__(self, fpi = sys.stdin, fpo = sys.stdout,
 indentsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS):
 self.fpi = fpi
 self.fpo = fpo
 self.indentsize = indentsize
 self.tabsize = tabsize
 self.lineno = 0
 self.expandtabs = expandtabs
 self._write = fpo.write
 self.kwprog = re.compile(
 r'^\s*(?P<kw>[a-z]+)'
 r'(\s+(?P<id>[a-zA-Z_]\w*))?'
 r'[^\w]')
 self.endprog = re.compile(
 r'^\s*#?\s*end\s+(?P<kw>[a-z]+)'
 r'(\s+(?P<id>[a-zA-Z_]\w*))?'
 r'[^\w]')
 self.wsprog = re.compile(r'^[ \t]*')
 # end def __init__
 def write(self, line):
 if self.expandtabs:
 self._write(string.expandtabs(line, self.tabsize))
 else:
 self._write(line)
 # end if
 # end def write
 def readline(self):
 line = self.fpi.readline()
 if line: self.lineno = self.lineno + 1
 # end if
 return line
 # end def readline
 def error(self, fmt, *args):
 if args: fmt = fmt % args
 # end if
 sys.stderr.write('Error at line %d: %s\n' % (self.lineno, fmt))
 self.write('### %s ###\n' % fmt)
 # end def error
 def getline(self):
 line = self.readline()
 while line[-2:] == '\\\n':
 line2 = self.readline()
 if not line2: break
 # end if
 line = line + line2
 # end while
 return line
 # end def getline
 def putline(self, line, indent = None):
 if indent is None:
 self.write(line)
 return
 # end if
 tabs, spaces = divmod(indent*self.indentsize, self.tabsize)
 i = 0
 m = self.wsprog.match(line)
 if m: i = m.end()
 # end if
 self.write('\t'*tabs + ' '*spaces + line[i:])
 # end def putline
 def reformat(self):
 stack = []
 while 1:
 line = self.getline()
 if not line: break # EOF
 # end if
 m = self.endprog.match(line)
 if m:
 kw = 'end'
 kw2 = m.group('kw')
 if not stack:
 self.error('unexpected end')
 elif stack[-1][0] != kw2:
 self.error('unmatched end')
 # end if
 del stack[-1:]
 self.putline(line, len(stack))
 continue
 # end if
 m = self.kwprog.match(line)
 if m:
 kw = m.group('kw')
 if kw in start:
 self.putline(line, len(stack))
 stack.append((kw, kw))
 continue
 # end if
 if next.has_key(kw) and stack:
 self.putline(line, len(stack)-1)
 kwa, kwb = stack[-1]
 stack[-1] = kwa, kw
 continue
 # end if
 # end if
 self.putline(line, len(stack))
 # end while
 if stack:
 self.error('unterminated keywords')
 for kwa, kwb in stack:
 self.write('\t%s\n' % kwa)
 # end for
 # end if
 # end def reformat
 def delete(self):
 begin_counter = 0
 end_counter = 0
 while 1:
 line = self.getline()
 if not line: break # EOF
 # end if
 m = self.endprog.match(line)
 if m:
 end_counter = end_counter + 1
 continue
 # end if
 m = self.kwprog.match(line)
 if m:
 kw = m.group('kw')
 if kw in start:
 begin_counter = begin_counter + 1
 # end if
 # end if
 self.putline(line)
 # end while
 if begin_counter - end_counter < 0:
 sys.stderr.write('Warning: input contained more end tags than expected\n')
 elif begin_counter - end_counter > 0:
 sys.stderr.write('Warning: input contained less end tags than expected\n')
 # end if
 # end def delete
 def complete(self):
 self.indentsize = 1
 stack = []
 todo = []
 current, firstkw, lastkw, topid = 0, '', '', ''
 while 1:
 line = self.getline()
 i = 0
 m = self.wsprog.match(line)
 if m: i = m.end()
 # end if
 m = self.endprog.match(line)
 if m:
 thiskw = 'end'
 endkw = m.group('kw')
 thisid = m.group('id')
 else:
 m = self.kwprog.match(line)
 if m:
 thiskw = m.group('kw')
 if not next.has_key(thiskw):
 thiskw = ''
 # end if
 if thiskw in ('def', 'class'):
 thisid = m.group('id')
 else:
 thisid = ''
 # end if
 elif line[i:i+1] in ('\n', '#'):
 todo.append(line)
 continue
 else:
 thiskw = ''
 # end if
 # end if
 indent = len(string.expandtabs(line[:i], self.tabsize))
 while indent < current:
 if firstkw:
 if topid:
 s = '# end %s %s\n' % (
 firstkw, topid)
 else:
 s = '# end %s\n' % firstkw
 # end if
 self.putline(s, current)
 firstkw = lastkw = ''
 # end if
 current, firstkw, lastkw, topid = stack[-1]
 del stack[-1]
 # end while
 if indent == current and firstkw:
 if thiskw == 'end':
 if endkw != firstkw:
 self.error('mismatched end')
 # end if
 firstkw = lastkw = ''
 elif not thiskw or thiskw in start:
 if topid:
 s = '# end %s %s\n' % (
 firstkw, topid)
 else:
 s = '# end %s\n' % firstkw
 # end if
 self.putline(s, current)
 firstkw = lastkw = topid = ''
 # end if
 # end if
 if indent > current:
 stack.append((current, firstkw, lastkw, topid))
 if thiskw and thiskw not in start:
 # error
 thiskw = ''
 # end if
 current, firstkw, lastkw, topid = \
 indent, thiskw, thiskw, thisid
 # end if
 if thiskw:
 if thiskw in start:
 firstkw = lastkw = thiskw
 topid = thisid
 else:
 lastkw = thiskw
 # end if
 # end if
 for l in todo: self.write(l)
 # end for
 todo = []
 if not line: break
 # end if
 self.write(line)
 # end while
 # end def complete
# end class PythonIndenter
# Simplified user interface
# - xxx_filter(input, output): read and write file objects
# - xxx_string(s): take and return string object
# - xxx_file(filename): process file in place, return true iff changed
def complete_filter(input = sys.stdin, output = sys.stdout,
 stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS):
 pi = PythonIndenter(input, output, stepsize, tabsize, expandtabs)
 pi.complete()
# end def complete_filter
def delete_filter(input= sys.stdin, output = sys.stdout,
 stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS):
 pi = PythonIndenter(input, output, stepsize, tabsize, expandtabs)
 pi.delete()
# end def delete_filter
def reformat_filter(input = sys.stdin, output = sys.stdout,
 stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS):
 pi = PythonIndenter(input, output, stepsize, tabsize, expandtabs)
 pi.reformat()
# end def reformat_filter
class StringReader:
 def __init__(self, buf):
 self.buf = buf
 self.pos = 0
 self.len = len(self.buf)
 # end def __init__
 def read(self, n = 0):
 if n <= 0:
 n = self.len - self.pos
 else:
 n = min(n, self.len - self.pos)
 # end if
 r = self.buf[self.pos : self.pos + n]
 self.pos = self.pos + n
 return r
 # end def read
 def readline(self):
 i = string.find(self.buf, '\n', self.pos)
 return self.read(i + 1 - self.pos)
 # end def readline
 def readlines(self):
 lines = []
 line = self.readline()
 while line:
 lines.append(line)
 line = self.readline()
 # end while
 return lines
 # end def readlines
 # seek/tell etc. are left as an exercise for the reader
# end class StringReader
class StringWriter:
 def __init__(self):
 self.buf = ''
 # end def __init__
 def write(self, s):
 self.buf = self.buf + s
 # end def write
 def getvalue(self):
 return self.buf
 # end def getvalue
# end class StringWriter
def complete_string(source, stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS):
 input = StringReader(source)
 output = StringWriter()
 pi = PythonIndenter(input, output, stepsize, tabsize, expandtabs)
 pi.complete()
 return output.getvalue()
# end def complete_string
def delete_string(source, stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS):
 input = StringReader(source)
 output = StringWriter()
 pi = PythonIndenter(input, output, stepsize, tabsize, expandtabs)
 pi.delete()
 return output.getvalue()
# end def delete_string
def reformat_string(source, stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS):
 input = StringReader(source)
 output = StringWriter()
 pi = PythonIndenter(input, output, stepsize, tabsize, expandtabs)
 pi.reformat()
 return output.getvalue()
# end def reformat_string
def complete_file(filename, stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS):
 source = open(filename, 'r').read()
 result = complete_string(source, stepsize, tabsize, expandtabs)
 if source == result: return 0
 # end if
 import os
 try: os.rename(filename, filename + '~')
 except os.error: pass
 # end try
 f = open(filename, 'w')
 f.write(result)
 f.close()
 return 1
# end def complete_file
def delete_file(filename, stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS):
 source = open(filename, 'r').read()
 result = delete_string(source, stepsize, tabsize, expandtabs)
 if source == result: return 0
 # end if
 import os
 try: os.rename(filename, filename + '~')
 except os.error: pass
 # end try
 f = open(filename, 'w')
 f.write(result)
 f.close()
 return 1
# end def delete_file
def reformat_file(filename, stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS):
 source = open(filename, 'r').read()
 result = reformat_string(source, stepsize, tabsize, expandtabs)
 if source == result: return 0
 # end if
 import os
 try: os.rename(filename, filename + '~')
 except os.error: pass
 # end try
 f = open(filename, 'w')
 f.write(result)
 f.close()
 return 1
# end def reformat_file
# Test program when called as a script
usage = """
usage: pindent (-c|-d|-r) [-s stepsize] [-t tabsize] [-e] [file] ...
-c : complete a correctly indented program (add #end directives)
-d : delete #end directives
-r : reformat a completed program (use #end directives)
-s stepsize: indentation step (default %(STEPSIZE)d)
-t tabsize : the worth in spaces of a tab (default %(TABSIZE)d)
-e : expand TABs into spaces (defailt OFF)
[file] ... : files are changed in place, with backups in file~
If no files are specified or a single - is given,
the program acts as a filter (reads stdin, writes stdout).
""" % vars()
def error_both(op1, op2):
 sys.stderr.write('Error: You can not specify both '+op1+' and -'+op2[0]+' at the same time\n')
 sys.stderr.write(usage)
 sys.exit(2)
# end def error_both
def test():
 import getopt
 try:
 opts, args = getopt.getopt(sys.argv[1:], 'cdrs:t:e')
 except getopt.error, msg:
 sys.stderr.write('Error: %s\n' % msg)
 sys.stderr.write(usage)
 sys.exit(2)
 # end try
 action = None
 stepsize = STEPSIZE
 tabsize = TABSIZE
 expandtabs = EXPANDTABS
 for o, a in opts:
 if o == '-c':
 if action: error_both(o, action)
 # end if
 action = 'complete'
 elif o == '-d':
 if action: error_both(o, action)
 # end if
 action = 'delete'
 elif o == '-r':
 if action: error_both(o, action)
 # end if
 action = 'reformat'
 elif o == '-s':
 stepsize = string.atoi(a)
 elif o == '-t':
 tabsize = string.atoi(a)
 elif o == '-e':
 expandtabs = 1
 # end if
 # end for
 if not action:
 sys.stderr.write(
 'You must specify -c(omplete), -d(elete) or -r(eformat)\n')
 sys.stderr.write(usage)
 sys.exit(2)
 # end if
 if not args or args == ['-']:
 action = eval(action + '_filter')
 action(sys.stdin, sys.stdout, stepsize, tabsize, expandtabs)
 else:
 action = eval(action + '_file')
 for file in args:
 action(file, stepsize, tabsize, expandtabs)
 # end for
 # end if
# end def test
if __name__ == '__main__':
 test()
# end if
--- NEW FILE: ptags.py ---
#! /usr/bin/env python
# ptags
#
# Create a tags file for Python programs, usable with vi.
# Tagged are:
# - functions (even inside other defs or classes)
# - classes
# - filenames
# Warns about files it cannot open.
# No warnings about duplicate tags.
import sys, re, os
tags = [] # Modified global variable!
def main():
 args = sys.argv[1:]
 for file in args: treat_file(file)
 if tags:
 fp = open('tags', 'w')
 tags.sort()
 for s in tags: fp.write(s)
expr = '^[ \t]*(def|class)[ \t]+([a-zA-Z0-9_]+)[ \t]*[:\(]'
matcher = re.compile(expr)
def treat_file(file):
 try:
 fp = open(file, 'r')
 except:
 sys.stderr.write('Cannot open %s\n' % file)
 return
 base = os.path.basename(file)
 if base[-3:] == '.py':
 base = base[:-3]
 s = base + '\t' + file + '\t' + '1\n'
 tags.append(s)
 while 1:
 line = fp.readline()
 if not line:
 break
 m = matcher.match(line)
 if m:
 content = m.group(0)
 name = m.group(2)
 s = name + '\t' + file + '\t/^' + content + '/\n'
 tags.append(s)
main()
--- NEW FILE: pydoc.pyw ---
import pydoc
pydoc.gui()
--- NEW FILE: redemo.py ---
"""Basic regular expression demostration facility (Perl style syntax)."""
from Tkinter import *
import re
class ReDemo:
 def __init__(self, master):
 self.master = master
 self.promptdisplay = Label(self.master, anchor=W,
 text="Enter a Perl-style regular expression:")
 self.promptdisplay.pack(side=TOP, fill=X)
 self.regexdisplay = Entry(self.master)
 self.regexdisplay.pack(fill=X)
 self.regexdisplay.focus_set()
 self.addoptions()
 self.statusdisplay = Label(self.master, text="", anchor=W)
 self.statusdisplay.pack(side=TOP, fill=X)
 self.labeldisplay = Label(self.master, anchor=W,
 text="Enter a string to search:")
 self.labeldisplay.pack(fill=X)
 self.labeldisplay.pack(fill=X)
 self.showframe = Frame(master)
 self.showframe.pack(fill=X, anchor=W)
 self.showvar = StringVar(master)
 self.showvar.set("first")
 self.showfirstradio = Radiobutton(self.showframe,
 text="Highlight first match",
 variable=self.showvar,
 value="first",
 command=self.recompile)
 self.showfirstradio.pack(side=LEFT)
 self.showallradio = Radiobutton(self.showframe,
 text="Highlight all matches",
 variable=self.showvar,
 value="all",
 command=self.recompile)
 self.showallradio.pack(side=LEFT)
 self.stringdisplay = Text(self.master, width=60, height=4)
 self.stringdisplay.pack(fill=BOTH, expand=1)
 self.stringdisplay.tag_configure("hit", background="yellow")
 self.grouplabel = Label(self.master, text="Groups:", anchor=W)
 self.grouplabel.pack(fill=X)
 self.grouplist = Listbox(self.master)
 self.grouplist.pack(expand=1, fill=BOTH)
 self.regexdisplay.bind('<Key>', self.recompile)
 self.stringdisplay.bind('<Key>', self.reevaluate)
 self.compiled = None
 self.recompile()
 btags = self.regexdisplay.bindtags()
 self.regexdisplay.bindtags(btags[1:] + btags[:1])
 btags = self.stringdisplay.bindtags()
 self.stringdisplay.bindtags(btags[1:] + btags[:1])
 def addoptions(self):
 self.frames = []
 self.boxes = []
 self.vars = []
 for name in ('IGNORECASE',
 'LOCALE',
 'MULTILINE',
 'DOTALL',
 'VERBOSE'):
 if len(self.boxes) % 3 == 0:
 frame = Frame(self.master)
 frame.pack(fill=X)
 self.frames.append(frame)
 val = getattr(re, name)
 var = IntVar()
 box = Checkbutton(frame,
 variable=var, text=name,
 offvalue=0, onvalue=val,
 command=self.recompile)
 box.pack(side=LEFT)
 self.boxes.append(box)
 self.vars.append(var)
 def getflags(self):
 flags = 0
 for var in self.vars:
 flags = flags | var.get()
 flags = flags
 return flags
 def recompile(self, event=None):
 try:
 self.compiled = re.compile(self.regexdisplay.get(),
 self.getflags())
 bg = self.promptdisplay['background']
 self.statusdisplay.config(text="", background=bg)
 except re.error, msg:
 self.compiled = None
 self.statusdisplay.config(
 text="re.error: %s" % str(msg),
 background="red")
 self.reevaluate()
 def reevaluate(self, event=None):
 try:
 self.stringdisplay.tag_remove("hit", "1.0", END)
 except TclError:
 pass
 try:
 self.stringdisplay.tag_remove("hit0", "1.0", END)
 except TclError:
 pass
 self.grouplist.delete(0, END)
 if not self.compiled:
 return
 self.stringdisplay.tag_configure("hit", background="yellow")
 self.stringdisplay.tag_configure("hit0", background="orange")
 text = self.stringdisplay.get("1.0", END)
 last = 0
 nmatches = 0
 while last <= len(text):
 m = self.compiled.search(text, last)
 if m is None:
 break
 first, last = m.span()
 if last == first:
 last = first+1
 tag = "hit0"
 else:
 tag = "hit"
 pfirst = "1.0 + %d chars" % first
 plast = "1.0 + %d chars" % last
 self.stringdisplay.tag_add(tag, pfirst, plast)
 if nmatches == 0:
 self.stringdisplay.yview_pickplace(pfirst)
 groups = list(m.groups())
 groups.insert(0, m.group())
 for i in range(len(groups)):
 g = "%2d: %s" % (i, `groups[i]`)
 self.grouplist.insert(END, g)
 nmatches = nmatches + 1
 if self.showvar.get() == "first":
 break
 if nmatches == 0:
 self.statusdisplay.config(text="(no match)",
 background="yellow")
 else:
 self.statusdisplay.config(text="")
# Main function, run when invoked as a stand-alone Python program.
def main():
 root = Tk()
 demo = ReDemo(root)
 root.protocol('WM_DELETE_WINDOW', root.quit)
 root.mainloop()
if __name__ == '__main__':
 main()
--- NEW FILE: reindent.py ---
#! /usr/bin/env python
# Released to the public domain, by Tim Peters, 03 October 2000.
"""reindent [-d][-r][-v] path ...
-d Dry run. Analyze, but don't make any changes to, files.
-r Recurse. Search for all .py files in subdirectories too.
-v Verbose. Print informative msgs; else no output.
Change Python (.py) files to use 4-space indents and no hard tab characters.
Also trim excess whitespace from ends of lines, and empty lines at the ends
of files. Ensure the last line ends with a newline.
Pass one or more file and/or directory paths. When a directory path, all
.py files within the directory will be examined, and, if the -r option is
given, likewise recursively for subdirectories.
Overwrites files in place, renaming the originals with a .bak extension.
If reindent finds nothing to change, the file is left alone. If reindent
does change a file, the changed file is a fixed-point for reindent (i.e.,
running reindent on the resulting .py file won't change it again).
The hard part of reindenting is figuring out what to do with comment
lines. So long as the input files get a clean bill of health from
tabnanny.py, reindent should do a good job.
"""
__version__ = "1"
import tokenize
import os
import sys
verbose = 0
recurse = 0
dryrun = 0
def errprint(*args):
 sep = ""
 for arg in args:
 sys.stderr.write(sep + str(arg))
 sep = " "
 sys.stderr.write("\n")
def main():
 import getopt
 global verbose, recurse, dryrun
 try:
 opts, args = getopt.getopt(sys.argv[1:], "drv")
 except getopt.error, msg:
 errprint(msg)
 return
 for o, a in opts:
 if o == '-d':
 dryrun += 1
 elif o == '-r':
 recurse += 1
 elif o == '-v':
 verbose += 1
 if not args:
 errprint("Usage:", __doc__)
 return
 for arg in args:
 check(arg)
def check(file):
 if os.path.isdir(file) and not os.path.islink(file):
 if verbose:
 print "listing directory", file
 names = os.listdir(file)
 for name in names:
 fullname = os.path.join(file, name)
 if ((recurse and os.path.isdir(fullname) and
 not os.path.islink(fullname))
 or name.lower().endswith(".py")):
 check(fullname)
 return
 if verbose:
 print "checking", file, "...",
 try:
 f = open(file)
 except IOError, msg:
 errprint("%s: I/O Error: %s" % (file, str(msg)))
 return
 r = Reindenter(f)
 f.close()
 if r.run():
 if verbose:
 print "changed."
 if dryrun:
 print "But this is a dry run, so leaving it alone."
 if not dryrun:
 bak = file + ".bak"
 if os.path.exists(bak):
 os.remove(bak)
 os.rename(file, bak)
 if verbose:
 print "renamed", file, "to", bak
 f = open(file, "w")
 r.write(f)
 f.close()
 if verbose:
 print "wrote new", file
 else:
 if verbose:
 print "unchanged."
class Reindenter:
 def __init__(self, f):
 self.find_stmt = 1 # next token begins a fresh stmt?
 self.level = 0 # current indent level
 # Raw file lines.
 self.raw = f.readlines()
 # File lines, rstripped & tab-expanded. Dummy at start is so
 # that we can use tokenize's 1-based line numbering easily.
 # Note that a line is all-blank iff it's "\n".
 self.lines = [line.rstrip().expandtabs() + "\n"
 for line in self.raw]
 self.lines.insert(0, None)
 self.index = 1 # index into self.lines of next line
 # List of (lineno, indentlevel) pairs, one for each stmt and
 # comment line. indentlevel is -1 for comment lines, as a
 # signal that tokenize doesn't know what to do about them;
 # indeed, they're our headache!
 self.stats = []
 def run(self):
 tokenize.tokenize(self.getline, self.tokeneater)
 # Remove trailing empty lines.
 lines = self.lines
 while lines and lines[-1] == "\n":
 lines.pop()
 # Sentinel.
 stats = self.stats
 stats.append((len(lines), 0))
 # Map count of leading spaces to # we want.
 have2want = {}
 # Program after transformation.
 after = self.after = []
 for i in range(len(stats)-1):
 thisstmt, thislevel = stats[i]
 nextstmt = stats[i+1][0]
 have = getlspace(lines[thisstmt])
 want = thislevel * 4
 if want < 0:
 # A comment line.
 if have:
 # An indented comment line. If we saw the same
 # indentation before, reuse what it most recently
 # mapped to.
 want = have2want.get(have, -1)
 if want < 0:
 # Then it probably belongs to the next real stmt.
 for j in xrange(i+1, len(stats)-1):
 jline, jlevel = stats[j]
 if jlevel >= 0:
 if have == getlspace(lines[jline]):
 want = jlevel * 4
 break
 if want < 0: # Maybe it's a hanging
 # comment like this one,
 # in which case we should shift it like its base
 # line got shifted.
 for j in xrange(i-1, -1, -1):
 jline, jlevel = stats[j]
 if jlevel >= 0:
 want = have + getlspace(after[jline-1]) - \
 getlspace(lines[jline])
 break
 if want < 0:
 # Still no luck -- leave it alone.
 want = have
 else:
 want = 0
 assert want >= 0
 have2want[have] = want
 diff = want - have
 if diff == 0 or have == 0:
 after.extend(lines[thisstmt:nextstmt])
 else:
 for line in lines[thisstmt:nextstmt]:
 if diff > 0:
 if line == "\n":
 after.append(line)
 else:
 after.append(" " * diff + line)
 else:
 remove = min(getlspace(line), -diff)
 after.append(line[remove:])
 return self.raw != self.after
 def write(self, f):
 f.writelines(self.after)
 # Line-getter for tokenize.
 def getline(self):
 if self.index >= len(self.lines):
 line = ""
 else:
 line = self.lines[self.index]
 self.index += 1
 return line
 # Line-eater for tokenize.
 def tokeneater(self, type, token, (sline, scol), end, line,
 INDENT=tokenize.INDENT,
 DEDENT=tokenize.DEDENT,
 NEWLINE=tokenize.NEWLINE,
 COMMENT=tokenize.COMMENT,
 NL=tokenize.NL):
 if type == NEWLINE:
 # A program statement, or ENDMARKER, will eventually follow,
 # after some (possibly empty) run of tokens of the form
 # (NL | COMMENT)* (INDENT | DEDENT+)?
 self.find_stmt = 1
 elif type == INDENT:
 self.find_stmt = 1
 self.level += 1
 elif type == DEDENT:
 self.find_stmt = 1
 self.level -= 1
 elif type == COMMENT:
 if self.find_stmt:
 self.stats.append((sline, -1))
 # but we're still looking for a new stmt, so leave
 # find_stmt alone
 elif type == NL:
 pass
 elif self.find_stmt:
 # This is the first "real token" following a NEWLINE, so it
 # must be the first token of the next program statement, or an
 # ENDMARKER.
 self.find_stmt = 0
 if line: # not endmarker
 self.stats.append((sline, self.level))
# Count number of leading blanks.
def getlspace(line):
 i, n = 0, len(line)
 while i < n and line[i] == " ":
 i += 1
 return i
if __name__ == '__main__':
 main()
--- NEW FILE: rgrep.py ---
#! /usr/bin/env python
"""Reverse grep.
Usage: rgrep [-i] pattern file
"""
import sys
import re
import string
import getopt
def main():
 bufsize = 64*1024
 reflags = 0
 opts, args = getopt.getopt(sys.argv[1:], "i")
 for o, a in opts:
 if o == '-i':
 reflags = reflags | re.IGNORECASE
 if len(args) < 2:
 usage("not enough arguments")
 if len(args) > 2:
 usage("exactly one file argument required")
 pattern, filename = args
 try:
 prog = re.compile(pattern, reflags)
 except re.error, msg:
 usage("error in regular expression: %s" % str(msg))
 try:
 f = open(filename)
 except IOError, msg:
 usage("can't open %s: %s" % (repr(filename), str(msg)), 1)
 f.seek(0, 2)
 pos = f.tell()
 leftover = None
 while pos > 0:
 size = min(pos, bufsize)
 pos = pos - size
 f.seek(pos)
 buffer = f.read(size)
 lines = string.split(buffer, "\n")
 del buffer
 if leftover is None:
 if not lines[-1]:
 del lines[-1]
 else:
 lines[-1] = lines[-1] + leftover
 if pos > 0:
 leftover = lines[0]
 del lines[0]
 else:
 leftover = None
 lines.reverse()
 for line in lines:
 if prog.search(line):
 print line
def usage(msg, code=2):
 sys.stdout = sys.stderr
 print msg
 print __doc__
 sys.exit(code)
if __name__ == '__main__':
 main()
--- NEW FILE: suff.py ---
#! /usr/bin/env python
# suff
#
# show different suffixes amongst arguments
import sys
def main():
 files = sys.argv[1:]
 suffixes = {}
 for file in files:
 suff = getsuffix(file)
 if not suffixes.has_key(suff):
 suffixes[suff] = []
 suffixes[suff].append(file)
 keys = suffixes.keys()
 keys.sort()
 for suff in keys:
 print `suff`, len(suffixes[suff])
def getsuffix(file):
 suff = ''
 for i in range(len(file)):
 if file[i] == '.':
 suff = file[i:]
 return suff
main()
--- NEW FILE: sum5.py ---
#! /usr/bin/env python
# print md5 checksum for files
bufsize = 8096
fnfilter = None
rmode = 'r'
usage = """
usage: sum5 [-b] [-t] [-l] [-s bufsize] [file ...]
-b : read files in binary mode
-t : read files in text mode (default)
-l : print last pathname component only
-s bufsize: read buffer size (default %d)
file ... : files to sum; '-' or no files means stdin
""" % bufsize
import sys
import string
import os
import md5
import regsub
StringType = type('')
FileType = type(sys.stdin)
def sum(*files):
 sts = 0
 if files and type(files[-1]) == FileType:
 out, files = files[-1], files[:-1]
 else:
 out = sys.stdout
 if len(files) == 1 and type(files[0]) != StringType:
 files = files[0]
 for f in files:
 if type(f) == StringType:
 if f == '-':
 sts = printsumfp(sys.stdin, '<stdin>', out) or sts
 else:
 sts = printsum(f, out) or sts
 else:
 sts = sum(f, out) or sts
 return sts
def printsum(file, out = sys.stdout):
 try:
 fp = open(file, rmode)
 except IOError, msg:
 sys.stderr.write('%s: Can\'t open: %s\n' % (file, msg))
 return 1
 if fnfilter:
 file = fnfilter(file)
 sts = printsumfp(fp, file, out)
 fp.close()
 return sts
def printsumfp(fp, file, out = sys.stdout):
 m = md5.md5()
 try:
 while 1:
 data = fp.read(bufsize)
 if not data: break
 m.update(data)
 except IOError, msg:
 sys.stderr.write('%s: I/O error: %s\n' % (file, msg))
 return 1
 out.write('%s %s\n' % (hexify(m.digest()), file))
 return 0
def hexify(s):
 res = ''
 for c in s:
 res = res + '%02x' % ord(c)
 return res
def main(args = sys.argv[1:], out = sys.stdout):
 global fnfilter, rmode, bufsize
 import getopt
 try:
 opts, args = getopt.getopt(args, 'blts:')
 except getopt.error, msg:
 sys.stderr.write('%s: %s\n%s' % (sys.argv[0], msg, usage))
 return 2
 for o, a in opts:
 if o == '-l':
 fnfilter = os.path.basename
 if o == '-b':
 rmode = 'rb'
 if o == '-t':
 rmode = 'r'
 if o == '-s':
 bufsize = string.atoi(a)
 if not args: args = ['-']
 return sum(args, out)
if __name__ == '__main__' or __name__ == sys.argv[0]:
 sys.exit(main(sys.argv[1:], sys.stdout))
--- NEW FILE: texi2html.py ---
#! /usr/bin/env python
# Convert GNU texinfo files into HTML, one file per node.
# Based on Texinfo 2.14.
# Usage: texi2html [-d] [-d] [-c] inputfile outputdirectory
# The input file must be a complete texinfo file, e.g. emacs.texi.
# This creates many files (one per info node) in the output directory,
# overwriting existing files of the same name. All files created have
# ".html" as their extension.
# XXX To do:
# - handle @comment*** correctly
# - handle @xref {some words} correctly
# - handle @ftable correctly (items aren't indexed?)
# - handle @itemx properly
# - handle @exdent properly
# - add links directly to the proper line from indices
# - check against the definitive list of @-cmds; we still miss (among others):
[...1574 lines suppressed...]
 parser.print_headers = print_headers
 file = sys.argv[1]
 parser.setdirname(sys.argv[2])
 if file == '-':
 fp = sys.stdin
 else:
 parser.setincludedir(os.path.dirname(file))
 try:
 fp = open(file, 'r')
 except IOError, msg:
 print file, ':', msg
 sys.exit(1)
 parser.parse(fp)
 fp.close()
 parser.report()
if __name__ == "__main__":
 test()
--- NEW FILE: trace.py ---
#!/usr/bin/env python
# Copyright 2000, Mojam Media, Inc., all rights reserved.
# Author: Skip Montanaro
#
# Copyright 1999, Bioreason, Inc., all rights reserved.
# Author: Andrew Dalke
#
# Copyright 1995-1997, Automatrix, Inc., all rights reserved.
# Author: Skip Montanaro
#
# Copyright 1991-1995, Stichting Mathematisch Centrum, all rights reserved.
#
#
# Permission to use, copy, modify, and distribute this Python software and
# its associated documentation for any purpose without fee is hereby
# granted, provided that the above copyright notice appears in all copies,
# and that both that copyright notice and this permission notice appear in
# supporting documentation, and that the name of neither Automatrix,
# Bioreason or Mojam Media be used in advertising or publicity pertaining to
# distribution of the software without specific, written prior permission.
#
#
# Summary of recent changes:
# Support for files with the same basename (submodules in packages)
# Expanded the idea of how to ignore files or modules
# Split tracing and counting into different classes
# Extracted count information and reporting from the count class
# Added some ability to detect which missing lines could be executed
# Added pseudo-pragma to prohibit complaining about unexecuted lines
# Rewrote the main program
# Summary of older changes:
# Added run-time display of statements being executed
# Incorporated portability and performance fixes from Greg Stein
# Incorporated main program from Michael Scharf
"""
program/module to trace Python program or function execution
Sample use, command line:
 trace.py -c -f counts --ignore-dir '$prefix' spam.py eggs
 trace.py -t --ignore-dir '$prefix' spam.py eggs
Sample use, programmatically (still more complicated than it should be)
 # create an Ignore option, telling it what you want to ignore
 ignore = trace.Ignore(dirs = [sys.prefix, sys.exec_prefix])
 # create a Coverage object, telling it what to ignore
 coverage = trace.Coverage(ignore)
 # run the new command using the given trace
 trace.run(coverage.trace, 'main()')
 # make a report, telling it where you want output
 t = trace.create_results_log(coverage.results(),
 '/usr/local/Automatrix/concerts/coverage')
 show_missing = 1)
 The Trace class can be instantited instead of the Coverage class if
 runtime display of executable lines is desired instead of statement
 converage measurement.
"""
import sys, os, string, marshal, tempfile, copy, operator
def usage(outfile):
 outfile.write("""Usage: %s [OPTIONS] <file> [ARGS]
Execution:
 --help Display this help then exit.
 --version Output version information then exit.
 -t,--trace Print the line to be executed to sys.stdout.
 -c,--count Count the number of times a line is executed.
 Results are written in the results file, if given.
 -r,--report Generate a report from a results file; do not
 execute any code.
 (One of `-t', `-c' or `-r' must be specified)
 -s,--summary Generate a brief summary for each file. (Can only
 be used with -c or -r.)
I/O:
 -f,--file= File name for accumulating results over several runs.
 (No file name means do not archive results)
 -d,--logdir= Directory to use when writing annotated log files.
 Log files are the module __name__ with `.` replaced
 by os.sep and with '.pyl' added.
 -m,--missing Annotate all executable lines which were not executed
 with a '>>>>>> '.
 -R,--no-report Do not generate the annotated reports. Useful if
 you want to accumulate several over tests.
 -C,--coverdir= Generate .cover files in this directory
Selection: Do not trace or log lines from ...
 --ignore-module=[string] modules with the given __name__, and submodules
 of that module
 --ignore-dir=[string] files in the stated directory (multiple
 directories can be joined by os.pathsep)
 The selection options can be listed multiple times to ignore different
modules.
""" % sys.argv[0])
class Ignore:
 def __init__(self, modules = None, dirs = None):
 self._mods = modules or []
 self._dirs = dirs or []
 self._ignore = { '<string>': 1 }
 def names(self, filename, modulename):
 if self._ignore.has_key(modulename):
 return self._ignore[modulename]
 # haven't seen this one before, so see if the module name is
 # on the ignore list. Need to take some care since ignoring
 # "cmp" musn't mean ignoring "cmpcache" but ignoring
 # "Spam" must also mean ignoring "Spam.Eggs".
 for mod in self._mods:
 if mod == modulename: # Identical names, so ignore
 self._ignore[modulename] = 1
 return 1
 # check if the module is a proper submodule of something on
 # the ignore list
 n = len(mod)
 # (will not overflow since if the first n characters are the
 # same and the name has not already occured, then the size
 # of "name" is greater than that of "mod")
 if mod == modulename[:n] and modulename[n] == '.':
 self._ignore[modulename] = 1
 return 1
 # Now check that __file__ isn't in one of the directories
 if filename is None:
 # must be a built-in, so we must ignore
 self._ignore[modulename] = 1
 return 1
 # Ignore a file when it contains one of the ignorable paths
 for d in self._dirs:
 # The '+ os.sep' is to ensure that d is a parent directory,
 # as compared to cases like:
 # d = "/usr/local"
 # filename = "/usr/local.py"
 # or
 # d = "/usr/local.py"
 # filename = "/usr/local.py"
 if string.find(filename, d + os.sep) == 0:
 self._ignore[modulename] = 1
 return 1
 # Tried the different ways, so we don't ignore this module
 self._ignore[modulename] = 0
 return 0
def run(trace, cmd):
 import __main__
 dict = __main__.__dict__
 sys.settrace(trace)
 try:
 exec cmd in dict, dict
 finally:
 sys.settrace(None)
def runctx(trace, cmd, globals=None, locals=None):
 if globals is None: globals = {}
 if locals is None: locals = {}
 sys.settrace(trace)
 try:
 exec cmd in dict, dict
 finally:
 sys.settrace(None)
def runfunc(trace, func, *args, **kw):
 result = None
 sys.settrace(trace)
 try:
 result = apply(func, args, kw)
 finally:
 sys.settrace(None)
 return result
class CoverageResults:
 def __init__(self, counts = {}, modules = {}):
 self.counts = counts.copy() # map (filename, lineno) to count
 self.modules = modules.copy() # map filenames to modules
 def update(self, other):
 """Merge in the data from another CoverageResults"""
 counts = self.counts
 other_counts = other.counts
 modules = self.modules
 other_modules = other.modules
 for key in other_counts.keys():
 counts[key] = counts.get(key, 0) + other_counts[key]
 for key in other_modules.keys():
 if modules.has_key(key):
 # make sure they point to the same file
 assert modules[key] == other_modules[key], \
 "Strange! filename %s has two different module " \
 "names: %s and %s" % \
 (key, modules[key], other_modules[key])
 else:
 modules[key] = other_modules[key]
# Given a code string, return the SET_LINENO information
def _find_LINENO_from_string(co_code):
 """return all of the SET_LINENO information from a code string"""
 import dis
 linenos = {}
 # This code was filched from the `dis' module then modified
 n = len(co_code)
 i = 0
 prev_op = None
 prev_lineno = 0
 while i < n:
 c = co_code[i]
 op = ord(c)
 if op == dis.SET_LINENO:
 if prev_op == op:
 # two SET_LINENO in a row, so the previous didn't
 # indicate anything. This occurs with triple
 # quoted strings (?). Remove the old one.
 del linenos[prev_lineno]
 prev_lineno = ord(co_code[i+1]) + ord(co_code[i+2])*256
 linenos[prev_lineno] = 1
 if op >= dis.HAVE_ARGUMENT:
 i = i + 3
 else:
 i = i + 1
 prev_op = op
 return linenos
def _find_LINENO(code):
 """return all of the SET_LINENO information from a code object"""
 import types
 # get all of the lineno information from the code of this scope level
 linenos = _find_LINENO_from_string(code.co_code)
 # and check the constants for references to other code objects
 for c in code.co_consts:
 if type(c) == types.CodeType:
 # find another code object, so recurse into it
 linenos.update(_find_LINENO(c))
 return linenos
def find_executable_linenos(filename):
 """return a dict of the line numbers from executable statements in a file
 Works by finding all of the code-like objects in the module then searching
 the byte code for 'SET_LINENO' terms (so this won't work one -O files).
 """
 import parser
 assert filename.endswith('.py')
 prog = open(filename).read()
 ast = parser.suite(prog)
 code = parser.compileast(ast, filename)
 # The only way I know to find line numbers is to look for the
 # SET_LINENO instructions. Isn't there some way to get it from
 # the AST?
 return _find_LINENO(code)
### XXX because os.path.commonprefix seems broken by my way of thinking...
def commonprefix(dirs):
 "Given a list of pathnames, returns the longest common leading component"
 if not dirs: return ''
 n = copy.copy(dirs)
 for i in range(len(n)):
 n[i] = n[i].split(os.sep)
 prefix = n[0]
 for item in n:
 for i in range(len(prefix)):
 if prefix[:i+1] <> item[:i+1]:
 prefix = prefix[:i]
 if i == 0: return ''
 break
 return os.sep.join(prefix)
def create_results_log(results, dirname = ".", show_missing = 1,
 save_counts = 0, summary = 0, coverdir = None):
 import re
 # turn the counts data ("(filename, lineno) = count") into something
 # accessible on a per-file basis
 per_file = {}
 for filename, lineno in results.counts.keys():
 lines_hit = per_file[filename] = per_file.get(filename, {})
 lines_hit[lineno] = results.counts[(filename, lineno)]
 # try and merge existing counts and modules file from dirname
 try:
 counts = marshal.load(open(os.path.join(dirname, "counts")))
 modules = marshal.load(open(os.path.join(dirname, "modules")))
 results.update(results.__class__(counts, modules))
 except IOError:
 pass
 # there are many places where this is insufficient, like a blank
 # line embedded in a multiline string.
 blank = re.compile(r'^\s*(#.*)?$')
 # accumulate summary info, if needed
 sums = {}
 # generate file paths for the coverage files we are going to write...
 fnlist = []
 tfdir = tempfile.gettempdir()
 for key in per_file.keys():
 filename = key
 # skip some "files" we don't care about...
 if filename == "<string>":
 continue
 # are these caused by code compiled using exec or something?
 if filename.startswith(tfdir):
 continue
 modulename = os.path.split(results.modules[key])[1]
 if filename.endswith(".pyc") or filename.endswith(".pyo"):
 filename = filename[:-1]
 if coverdir:
 listfilename = os.path.join(coverdir, modulename + ".cover")
 else:
 # XXX this is almost certainly not portable!!!
 fndir = os.path.dirname(filename)
 if os.path.isabs(filename):
 coverpath = fndir
 else:
 coverpath = os.path.join(dirname, fndir)
 # build list file name by appending a ".cover" to the module name
 # and sticking it into the specified directory
 if "." in modulename:
 # A module in a package
 finalname = modulename.split(".")[-1]
 listfilename = os.path.join(coverpath, finalname + ".cover")
 else:
 listfilename = os.path.join(coverpath, modulename + ".cover")
 # Get the original lines from the .py file
 try:
 lines = open(filename, 'r').readlines()
 except IOError, err:
 print >> sys.stderr, "trace: Could not open %s for reading " \
 "because: %s - skipping" % (`filename`, err.strerror)
 continue
 try:
 outfile = open(listfilename, 'w')
 except IOError, err:
 sys.stderr.write(
 '%s: Could not open %s for writing because: %s" \
 "- skipping\n' % ("trace", `listfilename`, err.strerror))
 continue
 # If desired, get a list of the line numbers which represent
 # executable content (returned as a dict for better lookup speed)
 if show_missing:
 executable_linenos = find_executable_linenos(filename)
 else:
 executable_linenos = {}
 n_lines = 0
 n_hits = 0
 lines_hit = per_file[key]
 for i in range(len(lines)):
 line = lines[i]
 # do the blank/comment match to try to mark more lines
 # (help the reader find stuff that hasn't been covered)
 if lines_hit.has_key(i+1):
 # count precedes the lines that we captured
 outfile.write('%5d: ' % lines_hit[i+1])
 n_hits = n_hits + 1
 n_lines = n_lines + 1
 elif blank.match(line):
 # blank lines and comments are preceded by dots
 outfile.write(' . ')
 else:
 # lines preceded by no marks weren't hit
 # Highlight them if so indicated, unless the line contains
 # '#pragma: NO COVER' (it is possible to embed this into
 # the text as a non-comment; no easy fix)
 if executable_linenos.has_key(i+1) and \
 string.find(lines[i],
 string.join(['#pragma', 'NO COVER'])) == -1:
 outfile.write('>>>>>> ')
 else:
 outfile.write(' '*7)
 n_lines = n_lines + 1
 outfile.write(string.expandtabs(lines[i], 8))
 outfile.close()
 if summary and n_lines:
 percent = int(100 * n_hits / n_lines)
 sums[modulename] = n_lines, percent, modulename, filename
 if save_counts:
 # try and store counts and module info into dirname
 try:
 marshal.dump(results.counts,
 open(os.path.join(dirname, "counts"), "w"))
 marshal.dump(results.modules,
 open(os.path.join(dirname, "modules"), "w"))
 except IOError, err:
 sys.stderr.write("cannot save counts/modules " \
 "files because %s" % err.strerror)
 if summary and sums:
 mods = sums.keys()
 mods.sort()
 print "lines cov% module (path)"
 for m in mods:
 n_lines, percent, modulename, filename = sums[m]
 print "%5d %3d%% %s (%s)" % sums[m]
# There is a lot of code shared between these two classes even though
# it is straightforward to make a super class to share code. However,
# for performance reasons (remember, this is called at every step) I
# wanted to keep everything to a single function call. Also, by
# staying within a single scope, I don't have to temporarily nullify
# sys.settrace, which would slow things down even more.
class Coverage:
 def __init__(self, ignore = Ignore()):
 self.ignore = ignore
 self.ignore_names = ignore._ignore # access ignore's cache (speed hack)
 self.counts = {} # keys are (filename, linenumber)
 self.modules = {} # maps filename -> module name
 def trace(self, frame, why, arg):
 if why == 'line':
 # something is fishy about getting the file name
 filename = frame.f_globals.get("__file__", None)
 if filename is None:
 filename = frame.f_code.co_filename
 try:
 modulename = frame.f_globals["__name__"]
 except KeyError:
 # PyRun_String() for example
 # XXX what to do?
 modulename = None
 # We do this next block to keep from having to make methods
 # calls, which also requires resetting the trace
 ignore_it = self.ignore_names.get(modulename, -1)
 if ignore_it == -1: # unknown filename
 sys.settrace(None)
 ignore_it = self.ignore.names(filename, modulename)
 sys.settrace(self.trace)
 # record the module name for every file
 self.modules[filename] = modulename
 if not ignore_it:
 lineno = frame.f_lineno
 # record the file name and line number of every trace
 key = (filename, lineno)
 self.counts[key] = self.counts.get(key, 0) + 1
 return self.trace
 def results(self):
 return CoverageResults(self.counts, self.modules)
class Trace:
 def __init__(self, ignore = Ignore()):
 self.ignore = ignore
 self.ignore_names = ignore._ignore # access ignore's cache (speed hack)
 self.files = {'<string>': None} # stores lines from the .py file,
 # or None
 def trace(self, frame, why, arg):
 if why == 'line':
 filename = frame.f_code.co_filename
 try:
 modulename = frame.f_globals["__name__"]
 except KeyError:
 # PyRun_String() for example
 # XXX what to do?
 modulename = None
 # We do this next block to keep from having to make methods
 # calls, which also requires resetting the trace
 ignore_it = self.ignore_names.get(modulename, -1)
 if ignore_it == -1: # unknown filename
 sys.settrace(None)
 ignore_it = self.ignore.names(filename, modulename)
 sys.settrace(self.trace)
 if not ignore_it:
 lineno = frame.f_lineno
 files = self.files
 if filename != '<string>' and not files.has_key(filename):
 files[filename] = map(string.rstrip,
 open(filename).readlines())
 # If you want to see filenames (the original behaviour), try:
 # modulename = filename
 # or, prettier but confusing when several files have the
 # same name
 # modulename = os.path.basename(filename)
 if files[filename] != None:
 print '%s(%d): %s' % (os.path.basename(filename), lineno,
 files[filename][lineno-1])
 else:
 print '%s(%d): ??' % (modulename, lineno)
 return self.trace
def _err_exit(msg):
 print >> sys.stderr, "%s: %s" % (sys.argv[0], msg)
 sys.exit(1)
def main(argv = None):
 import getopt
 if argv is None:
 argv = sys.argv
 try:
 opts, prog_argv = getopt.getopt(argv[1:], "tcrRf:d:msC:",
 ["help", "version", "trace", "count",
 "report", "no-report",
 "file=", "logdir=", "missing",
 "ignore-module=", "ignore-dir=",
 "coverdir="])
 except getopt.error, msg:
 print >> sys.stderr, "%s: %s" % (sys.argv[0], msg)
 print >> sys.stderr, "Try `%s --help' for more information" \
 % sys.argv[0]
 sys.exit(1)
 trace = 0
 count = 0
 report = 0
 no_report = 0
 counts_file = None
 logdir = "."
 missing = 0
 ignore_modules = []
 ignore_dirs = []
 coverdir = None
 summary = 0
 for opt, val in opts:
 if opt == "--help":
 usage(sys.stdout)
 sys.exit(0)
 if opt == "--version":
 sys.stdout.write("trace 2.0\n")
 sys.exit(0)
 if opt == "-t" or opt == "--trace":
 trace = 1
 continue
 if opt == "-c" or opt == "--count":
 count = 1
 continue
 if opt == "-r" or opt == "--report":
 report = 1
 continue
 if opt == "-R" or opt == "--no-report":
 no_report = 1
 continue
 if opt == "-f" or opt == "--file":
 counts_file = val
 continue
 if opt == "-d" or opt == "--logdir":
 logdir = val
 continue
 if opt == "-m" or opt == "--missing":
 missing = 1
 continue
 if opt == "-C" or opt == "--coverdir":
 coverdir = val
 continue
 if opt == "-s" or opt == "--summary":
 summary = 1
 continue
 if opt == "--ignore-module":
 ignore_modules.append(val)
 continue
 if opt == "--ignore-dir":
 for s in string.split(val, os.pathsep):
 s = os.path.expandvars(s)
 # should I also call expanduser? (after all, could use $HOME)
 s = string.replace(s, "$prefix",
 os.path.join(sys.prefix, "lib",
 "python" + sys.version[:3]))
 s = string.replace(s, "$exec_prefix",
 os.path.join(sys.exec_prefix, "lib",
 "python" + sys.version[:3]))
 s = os.path.normpath(s)
 ignore_dirs.append(s)
 continue
 assert 0, "Should never get here"
 if len(prog_argv) == 0:
 _err_exit("missing name of file to run")
 if count + trace + report > 1:
 _err_exit("can only specify one of --trace, --count or --report")
 if count + trace + report == 0:
 _err_exit("must specify one of --trace, --count or --report")
 if report and counts_file is None:
 _err_exit("--report requires a --file")
 if report and no_report:
 _err_exit("cannot specify both --report and --no-report")
 if logdir is not None:
 # warn if the directory doesn't exist, but keep on going
 # (is this the correct behaviour?)
 if not os.path.isdir(logdir):
 sys.stderr.write(
 "trace: WARNING, --logdir directory %s is not available\n" %
 `logdir`)
 sys.argv = prog_argv
 progname = prog_argv[0]
 if eval(sys.version[:3])>1.3:
 sys.path[0] = os.path.split(progname)[0] # ???
 # everything is ready
 ignore = Ignore(ignore_modules, ignore_dirs)
 if trace:
 t = Trace(ignore)
 try:
 run(t.trace, 'execfile(' + `progname` + ')')
 except IOError, err:
 _err_exit("Cannot run file %s because: %s" % \
 (`sys.argv[0]`, err.strerror))
 elif count:
 t = Coverage(ignore)
 try:
 run(t.trace, 'execfile(' + `progname` + ')')
 except IOError, err:
 _err_exit("Cannot run file %s because: %s" % \
 (`sys.argv[0]`, err.strerror))
 except SystemExit:
 pass
 results = t.results()
 # Add another lookup from the program's file name to its import name
 # This give the right results, but I'm not sure why ...
 results.modules[progname] = os.path.splitext(progname)[0]
 if counts_file:
 # add in archived data, if available
 try:
 old_counts, old_modules = marshal.load(open(counts_file, 'rb'))
 except IOError:
 pass
 else:
 results.update(CoverageResults(old_counts, old_modules))
 if not no_report:
 create_results_log(results, logdir, missing,
 summary=summary, coverdir=coverdir)
 if counts_file:
 try:
 marshal.dump( (results.counts, results.modules),
 open(counts_file, 'wb'))
 except IOError, err:
 _err_exit("Cannot save counts file %s because: %s" % \
 (`counts_file`, err.strerror))
 elif report:
 old_counts, old_modules = marshal.load(open(counts_file, 'rb'))
 results = CoverageResults(old_counts, old_modules)
 create_results_log(results, logdir, missing,
 summary=summary, coverdir=coverdir)
 else:
 assert 0, "Should never get here"
if __name__=='__main__':
 main()
--- NEW FILE: treesync.py ---
#! /usr/bin/env python
"""Script to synchronize two source trees.
Invoke with two arguments:
python treesync.py slave master
The assumption is that "master" contains CVS administration while
slave doesn't. All files in the slave tree that have a CVS/Entries
entry in the master tree are synchronized. This means:
 If the files differ:
 if the slave file is newer:
 normalize the slave file
 if the files still differ:
 copy the slave to the master
 else (the master is newer):
 copy the master to the slave
 normalizing the slave means replacing CRLF with LF when the master
 doesn't use CRLF
"""
import os, sys, stat, string, getopt
# Interactivity options
default_answer = "ask"
create_files = "yes"
create_directories = "no"
write_slave = "ask"
write_master = "ask"
def main():
 global always_no, always_yes
 global create_directories, write_master, write_slave
 opts, args = getopt.getopt(sys.argv[1:], "nym:s:d:f:a:")
 for o, a in opts:
 if o == '-y':
 default_answer = "yes"
 if o == '-n':
 default_answer = "no"
 if o == '-s':
 write_slave = a
 if o == '-m':
 write_master = a
 if o == '-d':
 create_directories = a
 if o == '-f':
 create_files = a
 if o == '-a':
 create_files = create_directories = write_slave = write_master = a
 try:
 [slave, master] = args
 except ValueError:
 print "usage: python", sys.argv[0] or "treesync.py",
 print "[-n] [-y] [-m y|n|a] [-s y|n|a] [-d y|n|a] [-f n|y|a]",
 print "slavedir masterdir"
 return
 process(slave, master)
def process(slave, master):
 cvsdir = os.path.join(master, "CVS")
 if not os.path.isdir(cvsdir):
 print "skipping master subdirectory", master
 print "-- not under CVS"
 return
 print "-"*40
 print "slave ", slave
 print "master", master
 if not os.path.isdir(slave):
 if not okay("create slave directory %s?" % slave,
 answer=create_directories):
 print "skipping master subdirectory", master
 print "-- no corresponding slave", slave
 return
 print "creating slave directory", slave
 try:
 os.mkdir(slave)
 except os.error, msg:
 print "can't make slave directory", slave, ":", msg
 return
 else:
 print "made slave directory", slave
 cvsdir = None
 subdirs = []
 names = os.listdir(master)
 for name in names:
 mastername = os.path.join(master, name)
 slavename = os.path.join(slave, name)
 if name == "CVS":
 cvsdir = mastername
 else:
 if os.path.isdir(mastername) and not os.path.islink(mastername):
 subdirs.append((slavename, mastername))
 if cvsdir:
 entries = os.path.join(cvsdir, "Entries")
 for e in open(entries).readlines():
 words = string.split(e, '/')
 if words[0] == '' and words[1:]:
 name = words[1]
 s = os.path.join(slave, name)
 m = os.path.join(master, name)
 compare(s, m)
 for (s, m) in subdirs:
 process(s, m)
def compare(slave, master):
 try:
 sf = open(slave, 'r')
 except IOError:
 sf = None
 try:
 mf = open(master, 'rb')
 except IOError:
 mf = None
 if not sf:
 if not mf:
 print "Neither master nor slave exists", master
 return
 print "Creating missing slave", slave
 copy(master, slave, answer=create_files)
 return
 if not mf:
 print "Not updating missing master", master
 return
 if sf and mf:
 if identical(sf, mf):
 return
 sft = mtime(sf)
 mft = mtime(mf)
 if mft > sft:
 # Master is newer -- copy master to slave
 sf.close()
 mf.close()
 print "Master ", master
 print "is newer than slave", slave
 copy(master, slave, answer=write_slave)
 return
 # Slave is newer -- copy slave to master
 print "Slave is", sft-mft, "seconds newer than master"
 # But first check what to do about CRLF
 mf.seek(0)
 fun = funnychars(mf)
 mf.close()
 sf.close()
 if fun:
 print "***UPDATING MASTER (BINARY COPY)***"
 copy(slave, master, "rb", answer=write_master)
 else:
 print "***UPDATING MASTER***"
 copy(slave, master, "r", answer=write_master)
BUFSIZE = 16*1024
def identical(sf, mf):
 while 1:
 sd = sf.read(BUFSIZE)
 md = mf.read(BUFSIZE)
 if sd != md: return 0
 if not sd: break
 return 1
def mtime(f):
 st = os.fstat(f.fileno())
 return st[stat.ST_MTIME]
def funnychars(f):
 while 1:
 buf = f.read(BUFSIZE)
 if not buf: break
 if '\r' in buf or '0円' in buf: return 1
 return 0
def copy(src, dst, rmode="rb", wmode="wb", answer='ask'):
 print "copying", src
 print " to", dst
 if not okay("okay to copy? ", answer):
 return
 f = open(src, rmode)
 g = open(dst, wmode)
 while 1:
 buf = f.read(BUFSIZE)
 if not buf: break
 g.write(buf)
 f.close()
 g.close()
def okay(prompt, answer='ask'):
 answer = string.lower(string.strip(answer))
 if not answer or answer[0] not in 'ny':
 answer = raw_input(prompt)
 answer = string.lower(string.strip(answer))
 if not answer:
 answer = default_answer
 if answer[:1] == 'y':
 return 1
 if answer[:1] == 'n':
 return 0
 print "Yes or No please -- try again:"
 return okay(prompt)
main()
--- NEW FILE: untabify.py ---
#! /usr/bin/env python
"Replace tabs with spaces in argument files. Print names of changed files."
import os
import sys
import string
import getopt
def main():
 tabsize = 8
 try:
 opts, args = getopt.getopt(sys.argv[1:], "t:")
 if not args:
 raise getopt.error, "At least one file argument required"
 except getopt.error, msg:
 print msg
 print "usage:", sys.argv[0], "[-t tabwidth] file ..."
 return
 for optname, optvalue in opts:
 if optname == '-t':
 tabsize = int(optvalue)
 for file in args:
 process(file, tabsize)
def process(file, tabsize):
 try:
 f = open(file)
 text = f.read()
 f.close()
 except IOError, msg:
 print "%s: I/O error: %s" % (`file`, str(msg))
 return
 newtext = string.expandtabs(text, tabsize)
 if newtext == text:
 return
 backup = file + "~"
 try:
 os.unlink(backup)
 except os.error:
 pass
 try:
 os.rename(file, backup)
 except os.error:
 pass
 f = open(file, "w")
 f.write(newtext)
 f.close()
 print file
if __name__ == '__main__':
 main()
--- NEW FILE: which.py ---
#! /usr/bin/env python
# Variant of "which".
# On stderr, near and total misses are reported.
# '-l<flags>' argument adds ls -l<flags> of each file found.
import sys
if sys.path[0] in (".", ""): del sys.path[0]
import sys, os, string
from stat import *
def msg(str):
 sys.stderr.write(str + '\n')
pathlist = string.splitfields(os.environ['PATH'], ':')
sts = 0
longlist = ''
if sys.argv[1:] and sys.argv[1][:2] == '-l':
 longlist = sys.argv[1]
 del sys.argv[1]
for prog in sys.argv[1:]:
 ident = ()
 for dir in pathlist:
 file = os.path.join(dir, prog)
 try:
 st = os.stat(file)
 except os.error:
 continue
 if not S_ISREG(st[ST_MODE]):
 msg(file + ': not a disk file')
 else:
 mode = S_IMODE(st[ST_MODE])
 if mode & 0111:
 if not ident:
 print file
 ident = st[:3]
 else:
 if st[:3] == ident:
 s = 'same as: '
 else:
 s = 'also: '
 msg(s + file)
 else:
 msg(file + ': not executable')
 if longlist:
 sts = os.system('ls ' + longlist + ' ' + file)
 if sts: msg('"ls -l" exit status: ' + `sts`)
 if not ident:
 msg(prog + ': not found')
 sts = 1
sys.exit(sts)
--- NEW FILE: xxci.py ---
#! /usr/bin/env python
# xxci
#
# check in files for which rcsdiff returns nonzero exit status
import sys
import os
from stat import *
import commands
import fnmatch
import string
EXECMAGIC = '001円140円000円010円'
MAXSIZE = 200*1024 # Files this big must be binaries and are skipped.
def getargs():
 args = sys.argv[1:]
 if args:
 return args
 print 'No arguments, checking almost *, in "ls -t" order'
 list = []
 for file in os.listdir(os.curdir):
 if not skipfile(file):
 list.append((getmtime(file), file))
 list.sort()
 if not list:
 print 'Nothing to do -- exit 1'
 sys.exit(1)
 list.sort()
 list.reverse()
 for mtime, file in list: args.append(file)
 return args
def getmtime(file):
 try:
 st = os.stat(file)
 return st[ST_MTIME]
 except os.error:
 return -1
badnames = ['tags', 'TAGS', 'xyzzy', 'nohup.out', 'core']
badprefixes = ['.', ',', '@', '#', 'o.']
badsuffixes = \
 ['~', '.a', '.o', '.old', '.bak', '.orig', '.new', '.prev', '.not', \
 '.pyc', '.fdc', '.rgb', '.elc', ',v']
ignore = []
def setup():
 ignore[:] = badnames
 for p in badprefixes:
 ignore.append(p + '*')
 for p in badsuffixes:
 ignore.append('*' + p)
 try:
 f = open('.xxcign', 'r')
 except IOError:
 return
 ignore[:] = ignore + string.split(f.read())
def skipfile(file):
 for p in ignore:
 if fnmatch.fnmatch(file, p): return 1
 try:
 st = os.lstat(file)
 except os.error:
 return 1 # Doesn't exist -- skip it
 # Skip non-plain files.
 if not S_ISREG(st[ST_MODE]): return 1
 # Skip huge files -- probably binaries.
 if st[ST_SIZE] >= MAXSIZE: return 1
 # Skip executables
 try:
 data = open(file, 'r').read(len(EXECMAGIC))
 if data == EXECMAGIC: return 1
 except:
 pass
 return 0
def badprefix(file):
 for bad in badprefixes:
 if file[:len(bad)] == bad: return 1
 return 0
def badsuffix(file):
 for bad in badsuffixes:
 if file[-len(bad):] == bad: return 1
 return 0
def go(args):
 for file in args:
 print file + ':'
 if differing(file):
 showdiffs(file)
 if askyesno('Check in ' + file + ' ? '):
 sts = os.system('rcs -l ' + file) # ignored
 sts = os.system('ci -l ' + file)
def differing(file):
 cmd = 'co -p ' + file + ' 2>/dev/null | cmp -s - ' + file
 sts = os.system(cmd)
 return sts != 0
def showdiffs(file):
 cmd = 'rcsdiff ' + file + ' 2>&1 | ${PAGER-more}'
 sts = os.system(cmd)
def askyesno(prompt):
 s = raw_input(prompt)
 return s in ['y', 'yes']
try:
 setup()
 go(getargs())
except KeyboardInterrupt:
 print '[Intr]'

AltStyle によって変換されたページ (->オリジナル) /