summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Knispel <gknispel@proformatique.com>2012-02-18 01:06:13 +0100
committerGuillaume Knispel <gknispel@proformatique.com>2012-02-18 01:06:13 +0100
commit988a70325443162da997608a0764b3b978b825fe (patch)
tree39749296edd7f989d5a77095c97612ed6c99428d
parent65e7157cfddadc6d2d673fb5b3bd01e023225622 (diff)
script to view a C includes tree (or list)
-rwxr-xr-xincludes139
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()