From ec758ead391daa2ce0e5697aa0e67ec3ba0f37af Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 4 Jun 1991 20:36:54 +0000 Subject: Initial revision --- Demo/scripts/README | 18 ++++ Demo/scripts/fact.py | 45 +++++++++ Demo/scripts/from.py | 25 +++++ Demo/scripts/lpwatch.py | 111 ++++++++++++++++++++++ Demo/scripts/pi.py | 30 ++++++ Demo/scripts/primes.py | 26 ++++++ Tools/scripts/byteyears.py | 29 ++++++ Tools/scripts/eptags.py | 50 ++++++++++ Tools/scripts/findlinksto.py | 29 ++++++ Tools/scripts/mkreal.py | 65 +++++++++++++ Tools/scripts/objgraph.py | 213 +++++++++++++++++++++++++++++++++++++++++++ Tools/scripts/pdeps.py | 167 +++++++++++++++++++++++++++++++++ Tools/scripts/ptags.py | 49 ++++++++++ Tools/scripts/suff.py | 29 ++++++ Tools/scripts/which.py | 44 +++++++++ Tools/scripts/xxci.py | 77 ++++++++++++++++ 16 files changed, 1007 insertions(+) create mode 100644 Demo/scripts/README create mode 100755 Demo/scripts/fact.py create mode 100755 Demo/scripts/from.py create mode 100755 Demo/scripts/lpwatch.py create mode 100755 Demo/scripts/pi.py create mode 100755 Demo/scripts/primes.py create mode 100755 Tools/scripts/byteyears.py create mode 100755 Tools/scripts/eptags.py create mode 100755 Tools/scripts/findlinksto.py create mode 100755 Tools/scripts/mkreal.py create mode 100755 Tools/scripts/objgraph.py create mode 100755 Tools/scripts/pdeps.py create mode 100755 Tools/scripts/ptags.py create mode 100755 Tools/scripts/suff.py create mode 100755 Tools/scripts/which.py create mode 100755 Tools/scripts/xxci.py diff --git a/Demo/scripts/README b/Demo/scripts/README new file mode 100644 index 0000000..7a2b837 --- /dev/null +++ b/Demo/scripts/README @@ -0,0 +1,18 @@ +Contents of this directory: + +byteyears.py Print product of a file's size and age +eptags.py Create Emacs TAGS file for Python modules +fact.py Factorize numbers +findlinksto.py Find symbolic links to a given path (prefix) +from.py Summarize mailbox +lfact.py Factorize long numbers +lpwatch.py Watch BSD line printer queues +mkreal.py Turn a symbolic link into a real file or directory +objgraph.py Print object graph from nm output on a library +pdeps.py Print dependencies between Python modules +pi.py Print digits of pi (uses arbitrary precision integers) +primes.py Print prime numbers +ptags.py Create vi tags file for Python modules +suff.py Sort a list of files by suffix +which.py Find a program in $PATH +xxci.py Wrapper for rcsdiff and ci diff --git a/Demo/scripts/fact.py b/Demo/scripts/fact.py new file mode 100755 index 0000000..ba75a04 --- /dev/null +++ b/Demo/scripts/fact.py @@ -0,0 +1,45 @@ +#! /usr/local/python + +# Factorize numbers, slowly. +# This version uses plain integers and is thus limited to 2**31-1. + +import sys +from math import sqrt + +error = 'fact.error' # exception + +def fact(n): + if n < 1: raise error # fact() argument should be >= 1 + if n = 1: return [] # special case + res = [] + # Treat even factors special, so we can use i = i+2 later + while n%2 = 0: + res.append(2) + n = n/2 + # Try odd numbers up to sqrt(n) + limit = int(sqrt(float(n+1))) + i = 3 + while i <= limit: + if n%i = 0: + res.append(i) + n = n/i + limit = int(sqrt(float(n+1))) + else: + i = i+2 + res.append(n) + return res + +def main(): + if len(sys.argv) > 1: + for arg in sys.argv[1:]: + n = int(eval(arg)) + print n, fact(n) + else: + try: + while 1: + n = int(input()) + print n, fact(n) + except EOFError: + pass + +main() diff --git a/Demo/scripts/from.py b/Demo/scripts/from.py new file mode 100755 index 0000000..20771a0 --- /dev/null +++ b/Demo/scripts/from.py @@ -0,0 +1,25 @@ +#! /usr/local/python + +# Print From and Subject of messages in $MAIL. +# Extension to multiple mailboxes and other bells & whistles are left +# as exercises for the reader. + +import posix + +# Open mailbox file. Exits with exception when this fails. + +mail = open(posix.environ['MAIL'], 'r') + +while 1: + line = mail.readline() + if not line: break # EOF + if line[:5] = 'From ': + # Start of message found + print line[:-1], + while 1: + line = mail.readline() + if not line: break # EOF + if line = '\n': break # Blank line ends headers + if line[:8] = 'Subject:': + print `line[9:-1]`, + print diff --git a/Demo/scripts/lpwatch.py b/Demo/scripts/lpwatch.py new file mode 100755 index 0000000..294028f --- /dev/null +++ b/Demo/scripts/lpwatch.py @@ -0,0 +1,111 @@ +#! /ufs/guido/bin/sgi/python +#! /usr/local/python + +# Watch line printer queue(s). +# Intended for BSD 4.3 lpq. + +import posix +import sys +import time +import string + +DEF_PRINTER = 'psc' +DEF_DELAY = 10 + +def main(): + delay = DEF_DELAY # XXX Use getopt() later + try: + thisuser = posix.environ['LOGNAME'] + except: + thisuser = posix.environ['USER'] + printers = sys.argv[1:] + if not printers: + if posix.environ.has_key('PRINTER'): + printers = [posix.environ['PRINTER']] + else: + printers = [DEF_PRINTER] + # + clearhome = posix.popen('clear', 'r').read() + # + while 1: + # Pipe output through cat for extra buffering, + # so the output (which overwrites the previous) + # appears instantaneous. + sys.stdout = posix.popen('exec cat', 'w') + sys.stdout.write(clearhome) + for name in printers: + pipe = posix.popen('lpq -P' + name + ' 2>&1', 'r') + showstatus(name, pipe, thisuser) + sts = pipe.close() + if sts: + print name + ': *** lpq exit status', sts + sts = sys.stdout.close() + time.sleep(delay) + +def showstatus(name, pipe, thisuser): + lines = 0 + users = {} + aheadbytes = 0 + aheadjobs = 0 + userseen = 0 + totalbytes = 0 + totaljobs = 0 + while 1: + line = pipe.readline() + if not line: break + fields = string.split(line) + n = len(fields) + if len(fields) >= 6 and fields[n-1] = 'bytes': + rank = fields[0] + user = fields[1] + job = fields[2] + files = fields[3:-2] + bytes = eval(fields[n-2]) + if user = thisuser: + userseen = 1 + elif not userseen: + aheadbytes = aheadbytes + bytes + aheadjobs = aheadjobs + 1 + totalbytes = totalbytes + bytes + totaljobs = totaljobs + 1 + if users.has_key(user): + ujobs, ubytes = users[user] + else: + ujobs, ubytes = 0, 0 + ujobs = ujobs + 1 + ubytes = ubytes + bytes + users[user] = ujobs, ubytes + else: + if fields and fields[0] <> 'Rank': + if line[-1:] = '\n': + line = line[:-1] + if not lines: + print name + ':', + else: + print + print line, + lines = lines + 1 + if totaljobs: + if lines > 1: + print + lines = lines+1 + print (totalbytes+1023)/1024, 'K', + if totaljobs <> len(users): + print '(' + `totaljobs` + ' jobs)', + if len(users) = 1: + print 'for', users.keys()[0], + else: + print 'for', len(users), 'users', + if userseen: + if aheadjobs = 0: + print '(' + thisuser + ' first)', + else: + print '(' + `(aheadbytes+1023)/1024`, + print 'K before', thisuser + ')' + if lines: + print + +try: + main() +except KeyboardInterrupt: + pass diff --git a/Demo/scripts/pi.py b/Demo/scripts/pi.py new file mode 100755 index 0000000..5e19db6 --- /dev/null +++ b/Demo/scripts/pi.py @@ -0,0 +1,30 @@ +#! /usr/local/python + +# Print digits of pi forever. +# +# The algorithm, using Python's 'long' integers ("bignums"), works +# with continued fractions, and was conceived by Lambert Meertens. +# +# See also the ABC Programmer's Handbook, by Geurts, Meertens & Pemberton, +# published by Prentice-Hall (UK) Ltd., 1990. + +import sys + +def main(): + k, a, b, a1, b1 = 2l, 4l, 1l, 12l, 4l + while 1: + # Next approximation + p, q, k = k*k, 2l*k+1l, k+1l + a, b, a1, b1 = a1, b1, p*a+q*a1, p*b+q*b1 + # Print common digits + d, d1 = a/b, a1/b1 + #print a, b, a1, b1 + while d = d1: + # Use write() to avoid spaces between the digits + sys.stdout.write(`int(d)`) + # Flush so the output is seen immediately + sys.stdout.flush() + a, a1 = 10l*(a%b), 10l*(a1%b1) + d, d1 = a/b, a1/b1 + +main() diff --git a/Demo/scripts/primes.py b/Demo/scripts/primes.py new file mode 100755 index 0000000..487acef --- /dev/null +++ b/Demo/scripts/primes.py @@ -0,0 +1,26 @@ +#! /usr/local/python + +# Print prime numbers in a given range + +def main(): + import sys + min, max = 2, 0x7fffffff + if sys.argv[1:]: + min = int(eval(sys.argv[1])) + if sys.argv[2:]: + max = int(eval(sys.argv[2])) + primes(min, max) + +def primes(min, max): + if 2 >= min: print 2 + primes = [2] + i = 3 + while i <= max: + for p in primes: + if i%p = 0 or p*p > i: break + if i%p <> 0: + primes.append(i) + if i >= min: print i + i = i+2 + +main() diff --git a/Tools/scripts/byteyears.py b/Tools/scripts/byteyears.py new file mode 100755 index 0000000..8c5ec69 --- /dev/null +++ b/Tools/scripts/byteyears.py @@ -0,0 +1,29 @@ +#! /usr/local/python + +# byteyears file ... +# +# Print a number representing the product of age and size of each file, +# in suitable units. + +import sys, posix, time +from stat import * + +secs_per_year = 365.0 * 24.0 * 3600.0 +now = time.time() +status = 0 + +for file in sys.argv[1:]: + try: + st = posix.stat(file) + except posix.error, msg: + sys.stderr.write('can\'t stat ' + `file` + ': ' + `msg` + '\n') + status = 1 + st = () + if st: + mtime = st[ST_MTIME] + size = st[ST_SIZE] + age = now - mtime + byteyears = float(size) * float(age) / secs_per_year + print file + '\t\t' + `int(byteyears)` + +sys.exit(status) diff --git a/Tools/scripts/eptags.py b/Tools/scripts/eptags.py new file mode 100755 index 0000000..1c682d3 --- /dev/null +++ b/Tools/scripts/eptags.py @@ -0,0 +1,50 @@ +#! /usr/local/python + +# eptags +# +# Create a TAGS file for Python programs, usable with GNU Emacs (version 18). +# Tagged are: +# - functions (even inside other defs or classes) +# - classes +# Warns about files it cannot open. +# No warnings about duplicate tags. + +import sys +import regexp + +def main(): + outfp = open('TAGS', 'w') + args = sys.argv[1:] + for file in args: + treat_file(file, outfp) + +matcher = regexp.compile('^[ \t]*(def|class)[ \t]+([a-zA-Z0-9_]+)[ \t]*\(') + +def treat_file(file, outfp): + try: + fp = open(file, 'r') + except: + print 'Cannot open', file + return + charno = 0 + lineno = 0 + tags = [] + size = 0 + while 1: + line = fp.readline() + if not line: break + lineno = lineno + 1 + res = matcher.exec(line) + if res: + (a, b), (a1, b1), (a2, b2) = res + name = line[a2:b2] + pat = line[a:b] + tag = pat + '\177' + `lineno` + ',' + `charno` + '\n' + tags.append(name, tag) + size = size + len(tag) + charno = charno + len(line) + outfp.write('\f\n' + file + ',' + `size` + '\n') + for name, tag in tags: + outfp.write(tag) + +main() diff --git a/Tools/scripts/findlinksto.py b/Tools/scripts/findlinksto.py new file mode 100755 index 0000000..6a2a75b --- /dev/null +++ b/Tools/scripts/findlinksto.py @@ -0,0 +1,29 @@ +#! /usr/local/python + +# findlinksto +# +# find symbolic links to a given path + +import posix, path, sys + +def visit(pattern, dirname, names): + if path.islink(dirname): + names[:] = [] + return + if path.ismount(dirname): + print 'descend into', dirname + n = len(pattern) + for name in names: + name = path.cat(dirname, name) + try: + linkto = posix.readlink(name) + if linkto[:n] = pattern: + print name, '->', linkto + except posix.error: + pass + +def main(pattern, args): + for dirname in args: + path.walk(dirname, visit, pattern) + +main(sys.argv[1], sys.argv[2:]) diff --git a/Tools/scripts/mkreal.py b/Tools/scripts/mkreal.py new file mode 100755 index 0000000..3fd4b03 --- /dev/null +++ b/Tools/scripts/mkreal.py @@ -0,0 +1,65 @@ +#! /usr/local/python + +# mkreal +# +# turn a symlink to a directory into a real directory + +import sys +import posix +import path +from stat import * + +cat = path.cat + +error = 'mkreal error' + +BUFSIZE = 32*1024 + +def mkrealfile(name): + st = posix.stat(name) # Get the mode + mode = S_IMODE(st[ST_MODE]) + linkto = posix.readlink(name) # Make sure again it's a symlink + f_in = open(name, 'r') # This ensures it's a file + posix.unlink(name) + f_out = open(name, 'w') + while 1: + buf = f_in.read(BUFSIZE) + if not buf: break + f_out.write(buf) + del f_out # Flush data to disk before changing mode + posix.chmod(name, mode) + +def mkrealdir(name): + st = posix.stat(name) # Get the mode + mode = S_IMODE(st[ST_MODE]) + linkto = posix.readlink(name) + files = posix.listdir(name) + posix.unlink(name) + posix.mkdir(name, mode) + posix.chmod(name, mode) + linkto = cat('..', linkto) + # + for file in files: + if file not in ('.', '..'): + posix.symlink(cat(linkto, file), cat(name, file)) + +def main(): + sys.stdout = sys.stderr + progname = path.basename(sys.argv[0]) + args = sys.argv[1:] + if not args: + print 'usage:', progname, 'path ...' + sys.exit(2) + status = 0 + for name in args: + if not path.islink(name): + print progname+':', name+':', 'not a symlink' + status = 1 + else: + if path.isdir(name): + mkrealdir(name) + else: + mkrealfile(name) + sys.exit(status) + +main() diff --git a/Tools/scripts/objgraph.py b/Tools/scripts/objgraph.py new file mode 100755 index 0000000..b45bba2 --- /dev/null +++ b/Tools/scripts/objgraph.py @@ -0,0 +1,213 @@ +#!/usr/local/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 path +import getopt +import regexp + +# Types of symbols. +# +definitions = 'TRGDSBAEC' +externals = 'UV' +ignore = 'Nntrgdsbavuc' + +# Regular expression to parse "nm -o" output. +# +matcher = regexp.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(200) # Arbitrary, but reasonable limit + if not s: + break + # If you get an exception on this line, + # it is probably caused by an unexpected input line: + (ra, rb), (r1a, r1b), (r2a, r2b), (r3a, r3b) = matcher.exec(s) + 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:', path.basename(sys.argv[0]), '[-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) diff --git a/Tools/scripts/pdeps.py b/Tools/scripts/pdeps.py new file mode 100755 index 0000000..2533015 --- /dev/null +++ b/Tools/scripts/pdeps.py @@ -0,0 +1,167 @@ +#! /usr/local/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 regexp +import path +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 = regexp.compile('^[ \t]*from[ \t]+([^ \t]+)[ \t]+') +m_from = regexp.compile('^[ \t]*import[ \t]+([^#]+)') + + +# Collect data from one file +# +def process(filename, table): + fp = open(filename, 'r') + mod = 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 + result = m_import.exec(line) + if not result: + result = m_from.exec(line) + if result: + (a, b), (a1, b1) = result + 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) diff --git a/Tools/scripts/ptags.py b/Tools/scripts/ptags.py new file mode 100755 index 0000000..b3a693e --- /dev/null +++ b/Tools/scripts/ptags.py @@ -0,0 +1,49 @@ +#! /usr/local/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 +import regexp +import path + +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) + +matcher = regexp.compile('^[ \t]*(def|class)[ \t]+([a-zA-Z0-9_]+)[ \t]*\(') + +def treat_file(file): + try: + fp = open(file, 'r') + except: + print 'Cannot open', file + return + base = path.basename(file) + if base[-3:] = '.py': base = base[:-3] + s = base + '\t' + file + '\t' + '1\n' + tags.append(s) + while 1: + line = fp.readline() + if not line: break + res = matcher.exec(line) + if res: + (a, b), (a1, b1), (a2, b2) = res + name = line[a2:b2] + s = name + '\t' + file + '\t/^' + line[a:b] + '/\n' + tags.append(s) + +main() diff --git a/Tools/scripts/suff.py b/Tools/scripts/suff.py new file mode 100755 index 0000000..7fda113 --- /dev/null +++ b/Tools/scripts/suff.py @@ -0,0 +1,29 @@ +#! /usr/local/python + +# suff +# +# show different suffixes amongst arguments + +import sys + +def main(): + files = sys.argv[1:] + suffixes = {} + for file in files: + suff = getsuffix(file) + if not suffixes.has_key(suff): + suffixes[suff] = [] + suffixes[suff].append(file) + keys = suffixes.keys() + keys.sort() + for suff in keys: + print `suff`, len(suffixes[suff]) + +def getsuffix(file): + suff = '' + for i in range(len(file)): + if file[i] = '.': + suff = file[i:] + return suff + +main() diff --git a/Tools/scripts/which.py b/Tools/scripts/which.py new file mode 100755 index 0000000..b9b888b --- /dev/null +++ b/Tools/scripts/which.py @@ -0,0 +1,44 @@ +#! /usr/local/python + +# Variant of "which". +# On stderr, near and total misses are reported. + +import sys, posix, string, path +from stat import * + +def msg(str): + sys.stderr.write(str + '\n') + +pathlist = string.splitfields(posix.environ['PATH'], ':') + +sts = 0 + +for prog in sys.argv[1:]: + ident = () + for dir in pathlist: + file = path.cat(dir, prog) + try: + st = posix.stat(file) + if S_ISREG(st[ST_MODE]): + mode = S_IMODE(st[ST_MODE]) + if mode % 2 or mode/8 % 2 or mode/64 % 2: + if ident: + if st[:3] = ident: + s = ': same as ' + else: + s = ': also ' + msg(prog + s + file) + else: + print file + ident = st[:3] + else: + msg(file + ': not executable') + else: + msg(file + ': not a disk file') + except posix.error: + pass + if not ident: + msg(prog + ': not found') + sts = 1 + +sys.exit(sts) diff --git a/Tools/scripts/xxci.py b/Tools/scripts/xxci.py new file mode 100755 index 0000000..e747c8d --- /dev/null +++ b/Tools/scripts/xxci.py @@ -0,0 +1,77 @@ +#! /usr/local/python + +# xxci +# +# check in files for which rcsdiff returns nonzero exit status + +import sys +import posix +import stat +import path +import commands + +MAXSIZE = 200*1024 # Files this big must be binaries and are skipped. + +def getargs(): + args = sys.argv[1:] + if args: + return args + print 'No arguments, checking almost *' + for file in posix.listdir('.'): + if not skipfile(file): + args.append(file) + if not args: + print 'Nothing to do -- exit 1' + sys.exit(1) + args.sort() + return args + +badnames = ['tags', 'xyzzy'] +badprefixes = ['.', ',', '@', '#', 'o.'] +badsuffixes = \ + ['~', '.a', '.o', '.old', '.bak', '.orig', '.new', '.prev', '.not'] +# XXX Should generalize even more to use fnmatch! + +def skipfile(file): + if file in badnames or \ + badprefix(file) or badsuffix(file) or \ + path.islink(file) or path.isdir(file): + return 1 + # Skip huge files -- probably binaries. + try: + st = posix.stat(file) + except posix.error: + return 1 # Doesn't exist -- skip it + return st[stat.ST_SIZE] >= MAXSIZE + +def badprefix(file): + for bad in badprefixes: + if file[:len(bad)] = bad: return 1 + return 0 + +def badsuffix(file): + for bad in badsuffixes: + if file[-len(bad):] = bad: return 1 + return 0 + +def go(args): + for file in args: + print file + ':' + if run('rcsdiff -c', file): + if askyesno('Check in ' + file + ' ? '): + sts = run('rcs -l', file) # ignored + # can't use run() here because it's interactive + sts = posix.system('ci -l ' + file) + +def run(cmd, file): + sts, output = commands.getstatusoutput(cmd + commands.mkarg(file)) + if sts: + print output + print 'Exit status', sts + return sts + +def askyesno(prompt): + s = raw_input(prompt) + return s in ['y', 'yes'] + +go(getargs()) -- cgit v0.12