Apply maemo2 patch
[opencv] / utils / check_doc.py
1 #!/usr/bin/env python
2 """
3 Usage: check_doc.py > log.txt
4 The script parses different opencv modules
5 (that are described by instances of class Comp below) and
6 checks for typical errors in headers and docs, for consistence and for completeness.
7 Due to its simplicity, it falsely reports some bugs, that should be
8 just ignored.
9 """
10
11 import sys, os, re, glob
12
13 comps = []
14
15 class Comp:
16     def __init__(self,comp_name):
17         self.name = comp_name
18
19 cxcore = Comp('cxcore')
20 cxcore.header_path = '../cxcore/include'
21 cxcore.headers = ['cxcore.h','cxtypes.h']
22 cxcore.ext_macro = 'CVAPI'
23 cxcore.inline_macro = 'CV_INLINE'
24 cxcore.func_prefix = 'cv'
25 cxcore.doc_path = '../docs/ref'
26 cxcore.docs = ['opencvref_cxcore.htm']
27 comps.append(cxcore)
28
29 cv = Comp('cv')
30 cv.header_path = '../cv/include'
31 cv.headers = ['cv.h','cvtypes.h']
32 cv.ext_macro = 'CVAPI'
33 cv.inline_macro = 'CV_INLINE'
34 cv.func_prefix = 'cv'
35 cv.doc_path = '../docs/ref'
36 cv.docs = ['opencvref_cv.htm']
37 comps.append(cv)
38
39
40 highgui = Comp('highgui')
41 highgui.header_path = '../otherlibs/highgui'
42 highgui.headers = ['highgui.h']
43 highgui.ext_macro = 'CVAPI'
44 highgui.inline_macro = 'CV_INLINE'
45 highgui.func_prefix = 'cv'
46 highgui.doc_path = '../docs/ref'
47 highgui.docs = ['opencvref_highgui.htm']
48 comps.append(highgui)
49
50
51 def normalize_decl(decl):
52     decl = re.sub( r'^\((.+?)\)', r'\1', decl)
53     decl = re.sub( r' CV_DEFAULT\((.+?)\)(,|( *\);))', r'=\1\2', decl)
54     decl = re.sub( r'\);', r' );', decl )
55     decl = re.sub( r'\(', r'( ', decl )
56     decl = re.sub( r'/\*.+?\*/', r'', decl )
57     decl = re.sub( r'\binline\b', r'', decl )
58     decl = re.sub( r' +', r' ', decl )
59     decl = re.sub( r' ?= ?', r'=', decl )
60     return decl.strip()
61
62 def print_report(filename, line_no, msg):
63     print '%s(%d): %s' % (filename,line_no,msg)
64
65 for comp in comps:
66     print "==================================================="
67     print 'Checking %s...' % (comp.name,)
68     header_path = comp.header_path
69     func_list = {}
70
71     if not header_path.endswith('/') and not header_path.endswith('\\'):
72         header_path += '/'
73     for header_glob in comp.headers:
74         glob_expr = header_path + header_glob
75         for header in glob.glob(glob_expr):
76             f = open(header,'r')
77             func_name = ""
78             mode = line_no = 0 # mode - outside func declaration (0) or inside (1)
79             for l in f.xreadlines():
80                 line_no += 1
81                 ll = ""
82                 
83                 #if re.findall(r'\b([abd-z]|([c][a-uw-z]))[a-z]*[A-Z]', l):
84                 #    print_report(header,line_no,"Bad-style identifier:\n\t"+l) 
85                 
86                 if mode == 0:
87                     if l.startswith(comp.ext_macro):
88                         ll = l[len(comp.ext_macro):]
89                         decl = ""
90                         mode = 1
91                     elif l.startswith(comp.inline_macro):
92                         temp_func_name = re.findall( r'^.+?\b(' + comp.func_prefix + '\w+)', l )
93                         if temp_func_name and temp_func_name[0] != func_name:
94                             ll = l[len(comp.inline_macro):]
95                             decl = ""
96                             mode = 1
97                 else:
98                     ll = l
99
100                 if ll:
101                     decl += ll.rstrip('\n') + ' '
102                     if ll.find(';') >= 0:
103                         mode = 0
104                         decl = normalize_decl(decl)
105                         func_name = re.findall( r'^.+?\b(' + comp.func_prefix + '\w+)', decl )[0]
106                         if func_list.get(func_name,[]):
107                             print_report(header,line_no,"Duplicated declaration of " + \
108                                          func_name + "... ignored") 
109                         else:
110                             func_list[func_name] = [decl,header,line_no,0]
111                     else:
112                         mode = 1
113             f.close()
114     
115     doc_path = comp.doc_path
116     if not doc_path.endswith('/') and not doc_path.endswith('\\'):
117         doc_path += '/'
118
119     blurb_re = re.compile( r'^<p class="Blurb"' )
120
121     for doc_glob in comp.docs:
122         glob_expr = doc_path + doc_glob
123         for doc in glob.glob(glob_expr):
124             f = open(doc, 'r')
125             mode = line_no = 0 # mode - 0 outside function declaration, 2 - inside,
126                                # 1 transitional state ('cause <pre> is used not only
127                                # for declaring functions)
128             for l in f.xreadlines():
129                 line_no += 1
130                 #if re.findall(r'\b([abd-z]|([c][a-uw-z]))[a-z]*[A-Z]', l):
131                 #    print_report(doc,line_no,"Bad-style identifier:\n\t" + l) 
132                 if mode == 0:
133                     if blurb_re.match(l):
134                         mode = 1
135                 elif mode == 1:
136                     if l.endswith('<pre>\n'):
137                         mode = 2
138                         decl = ""
139                 elif mode == 2:
140                     if l.startswith('</pre>'):
141                         mode = 0
142                         if decl.find('CV_DEFAULT') >= 0:
143                             print_report(doc,line_no,'CV_DEFAULT is used in documentation')
144                         decl = normalize_decl(decl)
145                         decl_list = decl.split(';')
146                         for decl in decl_list:
147                             decl = decl.strip()
148                             if decl:
149                                 decl = decl + ';'
150
151                                 #print '***', decl
152                                 func_name = re.findall( r'^.+?\b(' + comp.func_prefix + '\w+)\(', decl )
153                                 if not func_name: continue
154
155                                 func_name = func_name[0]
156                                 decl_info = func_list.get(func_name,[])
157                                 if decl_info:
158                                     if decl_info[3] == 0:
159                                         if decl_info[0] != decl:
160                                             print_report(doc,line_no,'Incorrect documentation on ' + func_name + ':')
161                                             print '  hdr: ' + decl_info[0]
162                                             print '  doc: ' + decl
163                                         decl_info[3] = 1
164                                     else:
165                                         print_report(doc,line_no,'Duplicated documentation on ' + func_name)
166                                 else:
167                                     print_report(doc,line_no,'The function '+func_name+' is not declared')
168                     elif not l.startswith('#define'):
169                         decl += l.rstrip('\n')
170             f.close()
171
172     print "---------------------------------------------------"
173     keys = func_list.keys()
174     undocumented_funcs = []
175     for k in keys:
176         decl_info = func_list[k]
177         if decl_info[3] == 0:
178             undocumented_funcs.append((decl_info[1],decl_info[2],k))
179
180     undocumented_funcs.sort()
181             
182     for decl_info in undocumented_funcs:
183         print_report(decl_info[0],decl_info[1],'Undocumented function '+decl_info[2])
184