diff options
author | Guillaume Knispel <gknispel@proformatique.com> | 2012-02-18 01:06:13 +0100 |
---|---|---|
committer | Guillaume Knispel <gknispel@proformatique.com> | 2012-02-18 01:06:13 +0100 |
commit | 988a70325443162da997608a0764b3b978b825fe (patch) | |
tree | 39749296edd7f989d5a77095c97612ed6c99428d | |
parent | 65e7157cfddadc6d2d673fb5b3bd01e023225622 (diff) |
script to view a C includes tree (or list)
-rwxr-xr-x | includes | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/includes b/includes new file mode 100755 index 0000000..a17c088 --- /dev/null +++ b/includes @@ -0,0 +1,139 @@ +#!/usr/bin/python + +import re +import os +import os.path +from optparse import OptionParser + + +# note: I should have used the append() action +def opt_include(option, opt, value, parser): + # print "hasattr?", ("yes" if hasattr(parser.values, "idirs") else "no") + if not hasattr(parser.values, "idirs"): + parser.values.idirs = [] + parser.values.idirs.append(value) + + +def option_parse(): + parser = OptionParser() + parser.add_option("-I", type="string", + action="callback", callback=opt_include, + help="add an include path", metavar="PATH") + parser.add_option("--ddl", type="int", action="store", dest="ddl", + help="dots for duplicate leaves") + parser.add_option("--tree", action="store_true", dest="tree", + help="display a tree of includes (default)") + parser.add_option("--list", action="store_false", dest="tree", + help="display a list of includes") + parser.add_option("--list-mix", action="store_true", dest="list_mix", + help="when displaying a list, mix with the entries " + "that were not found") + + parser.set_defaults(idirs=[]) + parser.set_defaults(ddl=1) + parser.set_defaults(tree=True) + parser.set_defaults(list_mix=False) + + (options, args) = parser.parse_args() + + if not (0 <= options.ddl <= 3): + parser.error("ddl must be between 0 and 3") + + return (options, args) + + +class Context(object): + def __init__(self, options): + self.options = options + # already_seen: + # key: filename + # value: number of children + self.already_seen = {} + # nf_list: + # "not found" list + # only filled if not options.tree and not options.list_mix + self.nf_list = [] + self.nf_set = set() + def mode(self, indent): + return indent if self.options.tree else "" + + +# @own_dir can be None or the directory containing the file trying to +# do this include if it uses "" delimiters +def search(subpath, gcontext, own_dir): + if own_dir: + filepath = os.path.join(own_dir, subpath) + if os.path.isfile(filepath): + return filepath + for idir in gcontext.options.idirs: + filepath = os.path.join(idir, subpath) + if os.path.isfile(filepath): + return filepath + + +def inc_indent(indent): + return indent + " " + + +def print_already_seen(indent, filepath, ddl, cn): + if not cn: + print ("%s%s " % (indent, filepath)) + ("." * ddl) + elif cn > 0: + print ("%s%s ... (%d children)" % (indent, filepath, cn)) + else: + print ("%s%s ..." % (indent, filepath)) + + +def doinc(filepath, gcontext, indent=""): + if filepath in gcontext.already_seen: + if gcontext.options.tree: + print_already_seen(indent, + filepath, + gcontext.options.ddl, + gcontext.already_seen[filepath]) + return + else: + print "%s%s" % (gcontext.mode(indent), filepath) + # avoid indirect recursion: + gcontext.already_seen[filepath] = -1 + cn = 0 + for line in file(filepath): + line = line.strip() + mo_sys = re.match(r'\#\s*include\s*\<([^>]+)\>', line) + mo_own = re.match(r'\#\s*include\s*\"([^>]+)\"', line) + if mo_sys: + include_name = mo_sys.group(1) + found_path = search(include_name, gcontext, None) + elif mo_own: + own_dir = os.path.dirname(filepath) + include_name = mo_own.group(1) + found_path = search(include_name, gcontext, own_dir) + else: + continue + cn += 1 + if found_path is None: + if gcontext.options.tree: + print "%s@@@ %s .." % (inc_indent(indent), include_name) + elif include_name not in gcontext.nf_set: + gcontext.nf_set.add(include_name) + if gcontext.options.list_mix: + print "@@@", include_name + else: + gcontext.nf_list.append(include_name) + else: + doinc(found_path, gcontext, inc_indent(indent)) + gcontext.already_seen[filepath] = cn + + +def main(): + (options, args) = option_parse() + gcontext = Context(options) + for each in args: + doinc(each, gcontext) + if gcontext.nf_list: + print + for include_name in gcontext.nf_list: + print "@@@", include_name + + +main() |