1#! /usr/bin/env python3 2 3"""finddiv - a grep-like tool that looks for division operators. 4 5Usage: finddiv [-l] file_or_directory ... 6 7For directory arguments, all files in the directory whose name ends in 8.py are processed, and subdirectories are processed recursively. 9 10This actually tokenizes the files to avoid false hits in comments or 11strings literals. 12 13By default, this prints all lines containing a / or /= operator, in 14grep -n style. With the -l option specified, it prints the filename 15of files that contain at least one / or /= operator. 16""" 17 18import os 19import sys 20import getopt 21import tokenize 22 23def main(): 24 try: 25 opts, args = getopt.getopt(sys.argv[1:], "lh") 26 except getopt.error as msg: 27 usage(msg) 28 return 2 29 if not args: 30 usage("at least one file argument is required") 31 return 2 32 listnames = 0 33 for o, a in opts: 34 if o == "-h": 35 print(__doc__) 36 return 37 if o == "-l": 38 listnames = 1 39 exit = None 40 for filename in args: 41 x = process(filename, listnames) 42 exit = exit or x 43 return exit 44 45def usage(msg): 46 sys.stderr.write("%s: %s\n" % (sys.argv[0], msg)) 47 sys.stderr.write("Usage: %s [-l] file ...\n" % sys.argv[0]) 48 sys.stderr.write("Try `%s -h' for more information.\n" % sys.argv[0]) 49 50def process(filename, listnames): 51 if os.path.isdir(filename): 52 return processdir(filename, listnames) 53 try: 54 fp = open(filename) 55 except IOError as msg: 56 sys.stderr.write("Can't open: %s\n" % msg) 57 return 1 58 g = tokenize.generate_tokens(fp.readline) 59 lastrow = None 60 for type, token, (row, col), end, line in g: 61 if token in ("/", "/="): 62 if listnames: 63 print(filename) 64 break 65 if row != lastrow: 66 lastrow = row 67 print("%s:%d:%s" % (filename, row, line), end=' ') 68 fp.close() 69 70def processdir(dir, listnames): 71 try: 72 names = os.listdir(dir) 73 except OSError as msg: 74 sys.stderr.write("Can't list directory: %s\n" % dir) 75 return 1 76 files = [] 77 for name in names: 78 fn = os.path.join(dir, name) 79 if os.path.normcase(fn).endswith(".py") or os.path.isdir(fn): 80 files.append(fn) 81 files.sort(key=os.path.normcase) 82 exit = None 83 for fn in files: 84 x = process(fn, listnames) 85 exit = exit or x 86 return exit 87 88if __name__ == "__main__": 89 sys.exit(main()) 90