Guido van Rossum | 43db62e | 2001-09-02 04:43:30 +0000 | [diff] [blame] | 1 | #! /usr/bin/env python |
| 2 | |
| 3 | """finddiv - a grep-like tool that looks for division operators. |
| 4 | |
| 5 | Usage: finddiv [-l] file_or_directory ... |
| 6 | |
| 7 | For directory arguments, all files in the directory whose name ends in |
| 8 | .py are processed, and subdirectories are processed recursively. |
| 9 | |
| 10 | This actually tokenizes the files to avoid false hits in comments or |
| 11 | strings literals. |
| 12 | |
| 13 | By default, this prints all lines containing a / or /= operator, in |
| 14 | grep -n style. With the -l option specified, it prints the filename |
| 15 | of files that contain at least one / or /= operator. |
| 16 | """ |
| 17 | |
| 18 | import os |
| 19 | import sys |
| 20 | import getopt |
| 21 | import tokenize |
| 22 | |
| 23 | def main(): |
| 24 | try: |
| 25 | opts, args = getopt.getopt(sys.argv[1:], "lh") |
Guido van Rossum | b940e11 | 2007-01-10 16:19:56 +0000 | [diff] [blame] | 26 | except getopt.error as msg: |
Guido van Rossum | 43db62e | 2001-09-02 04:43:30 +0000 | [diff] [blame] | 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": |
Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 35 | print(__doc__) |
Guido van Rossum | 43db62e | 2001-09-02 04:43:30 +0000 | [diff] [blame] | 36 | return |
| 37 | if o == "-l": |
| 38 | listnames = 1 |
| 39 | exit = None |
Andrew M. Kuchling | ac6df95 | 2003-05-13 18:14:25 +0000 | [diff] [blame] | 40 | for filename in args: |
| 41 | x = process(filename, listnames) |
Guido van Rossum | 43db62e | 2001-09-02 04:43:30 +0000 | [diff] [blame] | 42 | exit = exit or x |
| 43 | return exit |
| 44 | |
| 45 | def 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 | |
Andrew M. Kuchling | ac6df95 | 2003-05-13 18:14:25 +0000 | [diff] [blame] | 50 | def process(filename, listnames): |
| 51 | if os.path.isdir(filename): |
| 52 | return processdir(filename, listnames) |
Guido van Rossum | 43db62e | 2001-09-02 04:43:30 +0000 | [diff] [blame] | 53 | try: |
Andrew M. Kuchling | ac6df95 | 2003-05-13 18:14:25 +0000 | [diff] [blame] | 54 | fp = open(filename) |
Guido van Rossum | b940e11 | 2007-01-10 16:19:56 +0000 | [diff] [blame] | 55 | except IOError as msg: |
Guido van Rossum | 43db62e | 2001-09-02 04:43:30 +0000 | [diff] [blame] | 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: |
Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 63 | print(filename) |
Guido van Rossum | 43db62e | 2001-09-02 04:43:30 +0000 | [diff] [blame] | 64 | break |
| 65 | if row != lastrow: |
| 66 | lastrow = row |
Collin Winter | 6afaeb7 | 2007-08-03 17:06:41 +0000 | [diff] [blame] | 67 | print("%s:%d:%s" % (filename, row, line), end=' ') |
Guido van Rossum | 43db62e | 2001-09-02 04:43:30 +0000 | [diff] [blame] | 68 | fp.close() |
| 69 | |
| 70 | def processdir(dir, listnames): |
| 71 | try: |
| 72 | names = os.listdir(dir) |
Guido van Rossum | b940e11 | 2007-01-10 16:19:56 +0000 | [diff] [blame] | 73 | except os.error as msg: |
Guido van Rossum | 43db62e | 2001-09-02 04:43:30 +0000 | [diff] [blame] | 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) |
Raymond Hettinger | d4cb56d | 2008-01-30 02:55:10 +0000 | [diff] [blame] | 81 | files.sort(key=os.path.normcase) |
Guido van Rossum | 43db62e | 2001-09-02 04:43:30 +0000 | [diff] [blame] | 82 | exit = None |
| 83 | for fn in files: |
| 84 | x = process(fn, listnames) |
| 85 | exit = exit or x |
| 86 | return exit |
| 87 | |
| 88 | if __name__ == "__main__": |
| 89 | sys.exit(main()) |