@@ -14,6 +14,7 @@ from pygments.formatters import HtmlFormatter
1414from xml .sax import parse as xml_parse
1515from xml .sax import SAXParseException as XmlParseException
1616from xml .sax .handler import ContentHandler as XmlContentHandler
17+ from xml .sax .saxutils import escape
1718
1819"""
1920Turns a cppcheck xml file into a browsable html report along
5657 display: inline-block;
5758 margin-left: 4px;
5859}
60+
61+ div.verbose {
62+ display: inline-block;
63+ vertical-align: top;
64+ cursor: help;
65+ }
66+
67+ div.verbose div.content {
68+ display: none;
69+ position: absolute;
70+ padding: 10px;
71+ margin: 4px;
72+ max-width: 40%;
73+ white-space: pre-wrap;
74+ border: 1px solid black;
75+ background-color: #FFFFCC;
76+ cursor: auto;
77+ }
78+
5979.highlight .hll {
6080 padding: 1px;
6181}
@@ -155,9 +175,43 @@ HTML_HEAD = """
155175 <link rel="stylesheet" href="style.css">
156176 <style>
157177%s
158- </style>
178+ </style>
179+ <script language="javascript">
180+ function getStyle(el,styleProp) {
181+ if (el.currentStyle)
182+ var y = el.currentStyle[styleProp];
183+ else if (window.getComputedStyle)
184+ var y = document.defaultView.getComputedStyle(el,null).getPropertyValue(styleProp);
185+ return y;
186+ }
187+ function toggle() {
188+ var el = this.expandable_content;
189+ var mark = this.expandable_marker;
190+ if (el.style.display == "block") {
191+ el.style.display = "none";
192+ mark.innerHTML = "[+]";
193+ } else {
194+ el.style.display = "block";
195+ mark.innerHTML = "[-]";
196+ }
197+ }
198+ function init_expandables() {
199+ var elts = document.getElementsByClassName("expandable");
200+ for (var i = 0; i < elts.length; i++) {
201+ var el = elts[i];
202+ var clickable = el.getElementsByTagName("span")[0];
203+ var marker = clickable.getElementsByClassName("marker")[0];
204+ var content = el.getElementsByClassName("content")[0];
205+ var width = clickable.clientWidth - parseInt(getStyle(content, "padding-left")) - parseInt(getStyle(content, "padding-right"));
206+ content.style.width = width + "px";
207+ clickable.expandable_content = content;
208+ clickable.expandable_marker = marker;
209+ clickable.onclick = toggle;
210+ }
211+ }
212+ </script>
159213 </head>
160- <body>
214+ <body onload="init_expandables()" >
161215 <div id="header">
162216 <h1>Cppcheck report - %s: %s </h1>
163217 </div>
@@ -189,6 +243,18 @@ HTML_FOOTER = """
189243HTML_ERROR = "<span class='error2'><--- %s</span>\n "
190244HTML_INCONCLUSIVE = "<span class='inconclusive2'><--- %s</span>\n "
191245
246+ HTML_EXPANDABLE_ERROR = "<div class='verbose expandable'><span class='error2'><--- %s <span class='marker'>[+]</span></span><div class='content'>%s</div></div>\n " ""
247+ HTML_EXPANDABLE_INCONCLUSIVE = "<div class='verbose expandable'><span class='inconclusive2'><--- %s <span class='marker'>[+]</span></span><div class='content'>%s</div></div>\n " ""
248+
249+ # escape() and unescape() takes care of &, < and >.
250+ html_escape_table = {
251+ '"' : """ ,
252+ "'" : "'"
253+ }
254+ html_unescape_table = {v :k for k , v in html_escape_table .items ()}
255+
256+ def html_escape (text ):
257+ return escape (text , html_escape_table )
192258
193259class AnnotateCodeFormatter (HtmlFormatter ):
194260 errors = []
@@ -203,9 +269,17 @@ class AnnotateCodeFormatter(HtmlFormatter):
203269 if error ['line' ] == line_no :
204270 try :
205271 if error ['inconclusive' ] == 'true' :
206- t = t .replace ('\n ' , HTML_INCONCLUSIVE % error ['msg' ])
272+ if error .get ('verbose' ):
273+ index = t .rfind ('\n ' )
274+ t = t [:index ] + HTML_EXPANDABLE_INCONCLUSIVE % (error ['msg' ], html_escape (error ['verbose' ].replace ("\\ 012" , '\n ' ))) + t [index + 1 :]
275+ else :
276+ t = t .replace ('\n ' , HTML_INCONCLUSIVE % error ['msg' ])
207277 except KeyError :
208- t = t .replace ('\n ' , HTML_ERROR % error ['msg' ])
278+ if error .get ('verbose' ):
279+ index = t .rfind ('\n ' )
280+ t = t [:index ] + HTML_EXPANDABLE_ERROR % (error ['msg' ], html_escape (error ['verbose' ].replace ("\\ 012" , '\n ' ))) + t [index + 1 :]
281+ else :
282+ t = t .replace ('\n ' , HTML_ERROR % error ['msg' ])
209283
210284 line_no = line_no + 1
211285 yield i , t
@@ -253,6 +327,7 @@ class CppCheckHandler(XmlContentHandler):
253327 'id' : attributes ['id' ],
254328 'severity' : attributes ['severity' ],
255329 'msg' : attributes ['msg' ],
330+ 'verbose' : attributes .get ('verbose' ),
256331 'inconclusive' : attributes ['inconclusive' ]
257332 })
258333 except KeyError :
@@ -261,14 +336,14 @@ class CppCheckHandler(XmlContentHandler):
261336 'line' : 0 ,
262337 'id' : attributes ['id' ],
263338 'severity' : attributes ['severity' ],
264- 'msg' : attributes ['msg' ]
339+ 'msg' : attributes ['msg' ],
340+ 'verbose' : attributes .get ('verbose' )
265341 })
266342 elif name == 'location' :
267343 assert self .errors
268344 self .errors [- 1 ]['file' ] = attributes ['file' ]
269345 self .errors [- 1 ]['line' ] = int (attributes ['line' ])
270346
271-
272347if __name__ == '__main__' :
273348 # Configure all the options this little utility is using.
274349 parser = optparse .OptionParser ()
@@ -374,6 +449,7 @@ if __name__ == '__main__':
374449 lineanchors = 'line' ,
375450 encoding = options .source_encoding )
376451 htmlFormatter .errors = errors
452+
377453 with io .open (os .path .join (options .report_dir , htmlfile ),
378454 'w' ) as output_file :
379455 output_file .write (HTML_HEAD %
0 commit comments