diff options
Diffstat (limited to 'Tools')
-rwxr-xr-x | Tools/scripts/byteyears.py | 29 | ||||
-rwxr-xr-x | Tools/scripts/eptags.py | 50 | ||||
-rwxr-xr-x | Tools/scripts/findlinksto.py | 29 | ||||
-rwxr-xr-x | Tools/scripts/mkreal.py | 65 | ||||
-rwxr-xr-x | Tools/scripts/objgraph.py | 213 | ||||
-rwxr-xr-x | Tools/scripts/pdeps.py | 167 | ||||
-rwxr-xr-x | Tools/scripts/ptags.py | 49 | ||||
-rwxr-xr-x | Tools/scripts/suff.py | 29 | ||||
-rwxr-xr-x | Tools/scripts/which.py | 44 | ||||
-rwxr-xr-x | Tools/scripts/xxci.py | 77 |
10 files changed, 752 insertions, 0 deletions
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()) |