1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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()
|