1 # pmccabe2html - AWK script to convert pmccabe output to html -*- awk -*-
3 # Copyright (C) 2007-2020 Free Software Foundation, Inc.
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <https://www.gnu.org/licenses/>.
18 # Written by Jose E. Marchesi <jemarch@gnu.org>.
19 # Adapted for gnulib by Simon Josefsson <simon@josefsson.org>.
20 # Added support for C++ by Giuseppe Scrivano <gscrivano@gnu.org>.
22 # Typical Invocation is from a Makefile.am:
24 # CYCLO_SOURCES = ${top_srcdir}/src/*.[ch]
26 # cyclo-$(PACKAGE).html: $(CYCLO_SOURCES)
27 # $(PMCCABE) $(CYCLO_SOURCES) \
29 # | $(AWK) -f ${top_srcdir}/build-aux/pmccabe2html \
30 # -v lang=html -v name="$(PACKAGE_NAME)" \
31 # -v vcurl="https://git.savannah.gnu.org/gitweb/?p=$(PACKAGE).git;a=blob;f=%FILENAME%;hb=HEAD" \
32 # -v url="https://www.gnu.org/software/$(PACKAGE)/" \
33 # -v css=${top_srcdir}/build-aux/pmccabe.css \
34 # -v cut_dir=${top_srcdir}/ \
38 # The variables available are:
39 # lang output language, either 'html' or 'wiki'
41 # url link to project's home page
42 # vcurl URL to version controlled source code browser,
43 # a %FILENAME% in the string is replaced with the relative
45 # css CSS stylesheet filename, included verbatim in HTML output
46 # css_url link to CSS stylesheet, an URL
48 # Prologue & configuration
50 # Portable lookup of present time.
51 "date +%s" | getline epoch_time
52 "date" | getline chronos_time
54 section_global_stats_p = 1
55 section_function_cyclo_p = 1
63 cyclo_moderate_max = 20
65 source_file_link_tmpl = vcurl
70 html_prolog = "<a href=\"" url "\">Back to " package_name " Homepage</a><br/><br/>"
72 html_epilog = "<hr color=\"black\" size=\"2\"/> \
73 Copyright (c) 2007, 2008 Free Software Foundation, Inc."
74 html_doctype = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \
75 \"http://www.w3.org/TR/html401/loose.dtd\">"
76 html_comment = "<!-- Generated by gnulib's pmccabe2html at " epoch_time " -->"
77 html_title = "Cyclomatic Complexity report for " package_name
80 wiki_prolog = "{{Note|This page has been automatically generated}}"
89 function build_stats()
91 # Maximum modified cyclo
95 if (mcyclo[fcn] > max_mcyclo)
97 max_mcyclo = mcyclo[fcn]
100 if (mcyclo[fcn] > cyclo_high_max)
102 num_of_untestable_functions++
104 else if (mcyclo[fcn] > cyclo_moderate_max)
106 num_of_high_functions++
108 else if (mcyclo[fcn] > cyclo_simple_max)
110 num_of_moderate_functions++
114 num_of_simple_functions++
119 function html_fnc_table_complete (caption)
121 html_fnc_table(caption, 1, 1, 0, 1, 1, 0, 1)
124 function html_fnc_table_abbrev (caption)
126 html_fnc_table(caption, 1, 1, 0, 0, 1, 0, 0)
130 function html_fnc_table (caption,
139 print "<table width=\"90%\" class=\"function_table\" cellpadding=\"0\" cellspacing=\"0\">"
142 print "<caption class=\"function_table_caption\">" caption "</caption>"
144 html_fnc_header(fname_p,
151 for (nfnc = 1; nfnc <= nfuncs; nfnc++)
165 function html_header ()
171 print "<title>" html_title "</title>"
173 print "<meta name=\"description\" content=\"" html_title "\">"
174 print "<meta name=\"keywords\" content=\"" html_title "\">"
175 print "<meta name=\"resource-type\" content=\"document\">"
176 print "<meta name=\"distribution\" content=\"global\">"
177 print "<meta name=\"Generator\" content=\"pmccabe2html\">"
178 print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">"
179 print "<script language=\"javascript\" type=\"text/javascript\">"
180 print "function show_hide(idCapa, idButton, fuerzaVisibilidad)\
182 var button = document.getElementById(idButton);\
183 var capa = document.getElementById(idCapa);\
186 if (fuerzaVisibilidad && fuerzaVisibilidad!=\"\") {\
187 if (fuerzaVisibilidad==\"visible\") capa.style.display=\"\";\
188 else capa.style.display=\"none\";\
192 if (capa.style.display == \"none\") {\
193 capa.style.display = \"\";\
194 button.innerHTML = \"↑\";\
196 capa.style.display = \"none\";\
197 button.innerHTML = \"↓\"; \
207 print "<link rel=\"stylesheet\" href=\"" css_url "\" type =\"text/css\" media=\"screen\"/>"
211 print "<style type =\"text/css\" media=\"screen\">"
213 while ((getline cssline < css) > 0)
222 print "<body lang=\"en\" bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\" \
223 vlink=\"#800080\" alink=\"#FF0000\">"
226 function html_footer ()
232 function html_fnc_header (fname_p,
240 print "<tr class=\"function_table_header\">"
244 print "<td class=\"function_table_header_entry\">"
248 print "<td class=\"function_table_header_entry\">"
249 print "Function Name"
255 print "<td class=\"function_table_header_entry\">"
256 print "Modified Cyclo"
262 print "<td class=\"function_table_header_entry\">"
268 if (num_statements_p)
270 print "<td class=\"function_table_header_entry\">"
278 print "<td class=\"function_table_header_entry\">"
286 print "<td class=\"function_table_header_entry\">"
292 print "<td class=\"function_table_header_entry\">"
300 function html_fnc (nfun,
312 trclass = "function_entry_simple"
313 if (mcyclo[nfun] > cyclo_high_max)
315 trclass="function_entry_untestable"
317 else if (mcyclo[nfun] > cyclo_moderate_max)
319 trclass="function_entry_high"
321 else if (mcyclo[nfun] > cyclo_simple_max)
323 trclass="function_entry_moderate"
326 print "<tr class=\"" trclass "\">"
329 print "<td class=\"function_entry_filename\">"
330 if (file_p && mcyclo[nfun] > cyclo_simple_max)
332 print "<a href=\"javascript:void(0);\" title=\"show/hide function source\" onClick=\"javascript:show_hide('" fname "_src', '" fname "_button')\">\
333 <span id=\"" fname "_button\">↓</span></a>"
341 print "<td class=\"function_entry_name\">"
348 print "<td class=\"function_entry_cyclo\">"
355 print "<td class=\"function_entry_cyclo\">"
359 if (num_statements_p)
361 # Number of statements
362 print "<td class=\"function_entry_number\">"
363 print num_statements[nfun]
369 print "<td class=\"function_entry_number\">"
370 print num_lines[nfun]
376 print "<td class=\"function_entry_number\">"
377 print first_line[nfun]
383 if (source_file_link_tmpl != "")
386 href = source_file_link_tmpl
387 sub(/%FILENAME%/, file[nfun], href)
391 print "<td class=\"function_entry_filename\">"
394 print "<a href=\"" href "\">" file[nfun] "</a>"
406 if (mcyclo[nfun] > cyclo_simple_max)
411 if (fname_p) { num_columns++ }
412 if (mcyclo_p) { num_columns++ }
413 if (cyclo_p) { num_columns++ }
414 if (num_statements_p) { num_columns++ }
415 if (num_lines_p) { num_columns++ }
416 if (first_line_p) { num_columns++ }
417 if (file_p) { num_columns++ }
419 print "<td colspan=\"" num_columns "\" height=\"0\">"
420 print "<div id=\"" fname "_src\" class=\"function_src\" style=\"position: relative; display: none;\">"
421 print "<pre class=\"function_src\">"
423 while ((getline codeline < (fname nfun "_fn.txt")) > 0)
425 gsub(/&/, "\\&", codeline) # Must come first.
426 gsub(/</, "\\<", codeline)
427 gsub(/>/, "\\>", codeline)
431 close(fname nfun "_fn.txt")
432 system("rm " "'" fname "'" nfun "_fn.txt")
442 function html_global_stats ()
444 print "<div class=\"section_title\">Summary</div>"
446 print "<table class=\"summary_table\">"
447 # Total number of functions
449 print "<td class=\"summary_header_entry\">"
450 print "Total number of functions"
452 print "<td class=\"summary_number_entry\">"
453 print num_of_functions
456 # Number of simple functions
458 print "<td class=\"summary_header_entry\">"
459 print "Number of low risk functions"
461 print "<td class=\"summary_number_entry\">"
462 print num_of_simple_functions
465 # Number of moderate functions
467 print "<td class=\"summary_header_entry\">"
468 print "Number of moderate risk functions"
470 print "<td class=\"summary_number_entry\">"
471 print num_of_moderate_functions
474 # Number of high functions
476 print "<td class=\"summary_header_entry\">"
477 print "Number of high risk functions"
479 print "<td class=\"summary_number_entry\">"
480 print num_of_high_functions
483 # Number of untestable functions
485 print "<td class=\"summary_header_entry\">"
486 print "Number of untestable functions"
488 print "<td class=\"summary_number_entry\">"
489 print num_of_untestable_functions
496 function html_function_cyclo ()
498 print "<div class=\"section_title\">Details for all functions</div>"
500 print "<table class=\"ranges_table\">"
502 print "<td class=\"ranges_header_entry\">"
505 print "<td class=\"ranges_header_entry\">"
506 print "Cyclomatic Complexity"
508 print "<td class=\"ranges_header_entry\">"
509 print "Risk Evaluation"
514 print "<td class=\"ranges_entry_simple\">"
517 print "<td class=\"ranges_entry\">"
518 print "0 - " cyclo_simple_max
520 print "<td class=\"ranges_entry\">"
521 print "Simple module, without much risk"
526 print "<td class=\"ranges_entry_moderate\">"
529 print "<td class=\"ranges_entry\">"
530 print cyclo_simple_max + 1 " - " cyclo_moderate_max
532 print "<td class=\"ranges_entry\">"
533 print "More complex module, moderate risk"
538 print "<td class=\"ranges_entry_high\">"
541 print "<td class=\"ranges_entry\">"
542 print cyclo_moderate_max + 1 " - " cyclo_high_max
544 print "<td class=\"ranges_entry\">"
545 print "Complex module, high risk"
550 print "<td class=\"ranges_entry_untestable\">"
553 print "<td class=\"ranges_entry\">"
554 print "greater than " cyclo_high_max
556 print "<td class=\"ranges_entry\">"
557 print "Untestable module, very high risk"
562 html_fnc_table_complete("")
565 function wiki_global_stats ()
567 print "{| class=\"cyclo_summary_table\""
568 # Total number of functions
570 print "| class=\"cyclo_summary_header_entry\" | Total number of functions"
571 print "| class=\"cyclo_summary_number_entry\" |" num_of_functions
572 # Number of simple functions
574 print "| class=\"cyclo_summary_header_entry\" | Number of low risk functions"
575 print "| class=\"cyclo_summary_number_entry\" |" num_of_simple_functions
576 # Number of moderate functions
578 print "| class=\"cyclo_summary_header_entry\" | Number of moderate risk functions"
579 print "| class=\"cyclo_summary_number_entry\" |" num_of_moderate_functions
580 # Number of high functions
582 print "| class=\"cyclo_summary_header_entry\" | Number of high risk functions"
583 print "| class=\"cyclo_summary_number_entry\" |" num_of_high_functions
584 # Number of untestable functions
586 print "| class=\"cyclo_summary_header_entry\" | Number of untestable functions"
587 print "| class=\"cyclo_summary_number_entry\" |" num_of_untestable_functions
591 function wiki_function_cyclo ()
593 print "==Details for all functions=="
597 print "{| class =\"cyclo_ranges_table\""
599 print "| class=\"cyclo_ranges_header_entry\" | "
600 print "| class=\"cyclo_ranges_header_entry\" | Cyclomatic Complexity"
601 print "| class=\"cyclo_ranges_header_entry\" | Risk Evaluation"
604 print "| class=\"cyclo_ranges_entry_simple\" | "
605 print "| class=\"cyclo_ranges_entry\" | 0 - " cyclo_simple_max
606 print "| class=\"cyclo_ranges_entry\" | Simple module, without much risk"
609 print "| class=\"cyclo_ranges_entry_moderate\" | "
610 print "| class=\"cyclo_ranges_entry\" |" cyclo_simple_max + 1 " - " cyclo_moderate_max
611 print "| class=\"cyclo_ranges_entry\" | More complex module, moderate risk"
614 print "| class=\"cyclo_ranges_entry_high\" | "
615 print "| class=\"cyclo_ranges_entry\" |" cyclo_moderate_max + 1 " - " cyclo_high_max
616 print "| class=\"cyclo_ranges_entry\" | Complex module, high risk"
619 print "| class=\"cyclo_ranges_entry_untestable\" | "
620 print "| class=\"cyclo_ranges_entry\" | greater than " cyclo_high_max
621 print "| class=\"cyclo_ranges_entry\" | Untestable module, very high risk"
626 wiki_fnc_table_complete("")
629 function wiki_fnc_table_complete (caption)
631 wiki_fnc_table(caption, 1, 1, 0, 1, 1, 0, 1)
634 function wiki_fnc_table_abbrev (caption)
636 wiki_fnc_table(caption, 1, 0, 0, 0, 0, 0, 0)
639 function wiki_fnc_table (caption,
648 print "{| width=\"90%\" class=\"cyclo_function_table\" cellpadding=\"0\" cellspacing=\"0\">"
653 wiki_fnc_header(fname_p,
660 for (nfnc = 1; nfnc <= nfuncs; nfnc++)
674 function wiki_fnc_header (fname_p,
685 print "! class=\"cyclo_function_table_header_entry\" | Function Name"
690 print "! class=\"cyclo_function_table_header_entry\" | Modified Cyclo"
695 print "! class=\"cyclo_function_table_header_entry\" | Cyclomatic Complexity"
697 if (num_statements_p)
699 print "! class=\"cyclo_function_table_header_entry\" | Number of Statements"
703 print "! class=\"cyclo_function_table_header_entry\" | Number of Lines"
707 print "! class=\"cyclo_function_table_header_entry\" | First Line"
711 print "! class=\"cyclo_function_table_header_entry\" | Source File"
715 function wiki_fnc (nfnc,
727 trclass = "cyclo_function_entry_simple"
728 if (mcyclo[nfnc] > cyclo_high_max)
730 trclass="cyclo_function_entry_untestable"
732 else if (mcyclo[nfnc] > cyclo_moderate_max)
734 trclass="cyclo_function_entry_high"
736 else if (mcyclo[nfnc] > cyclo_simple_max)
738 trclass="cyclo_function_entry_moderate"
741 print "|- class=\"" trclass "\""
744 print "| class=\"cyclo_function_entry_name\" |" fname
749 print "| class=\"cyclo_function_entry_cyclo\" |" mcyclo[nfnc]
754 print "| class=\"cyclo_function_entry_cyclo\" |" cyclo[nfnc]
756 if (num_statements_p)
758 # Number of statements
759 print "| class=\"cyclo_function_entry_number\" |" num_statements[nfnc]
764 print "| class=\"cyclo_function_entry_number\" |" num_lines[nfnc]
769 print "| class=\"cyclo_function_entry_number\" |" first_line[nfnc]
774 if (source_file_link_tmpl != "")
777 href = source_file_link_tmpl
778 sub(/%FILENAME%/, file[nfnc], href)
782 print "| class=\"cyclo_function_entry_filename\" |" \
783 ((href != "") ? "[" href " " file[nfnc] "]" : "[" file[nfnc] "]")
787 # Scan data from a line
792 fnames[nfuncs] = function_name
795 num_statements[nfuncs] = $3
796 first_line[nfuncs] = $4
797 num_lines[nfuncs] = $5
799 # Build the filename from the file_spec ($6)
800 begin_util_path = index($6, cut_dir)
801 tmpfilename = substr($6, begin_util_path + length(cut_dir))
802 sub(/\([0-9]+\):/, "", tmpfilename)
803 file[nfuncs] = tmpfilename
805 if (mcyclo[nfuncs] > cyclo_simple_max)
807 # Extract function contents to a fn_txt file
810 sub(/\([0-9]+\):/, "", filepath)
813 while ((getline codeline < filepath) > 0)
816 if ((num_line >= first_line[nfuncs]) &&
817 (num_line < first_line[nfuncs] + num_lines[nfuncs]))
819 print codeline > (function_name nfuncs "_fn.txt")
822 close (function_name nfuncs "_fn.txt")
826 # Initial values for statistics variables
829 max_function_length = 0
830 num_of_simple_functions = 0
831 num_of_moderate_functions = 0
832 num_of_high_functions = 0
833 num_of_untestable_functions = 0
838 # Print header (only for html)
839 if (output_lang == "html")
845 if ((output_lang == "html") &&
850 if ((output_lang == "wiki") &&
856 if (output_lang == "html")
858 print "<div class=\"page_title\">" package_name " Cyclomatic Complexity Report</div>"
859 print "<p>Report generated at: <span class=\"report_timestamp\">" chronos_time "</span></p>"
861 if (output_lang == "wiki")
863 print "==" package_name " Cyclomatic Complexity Report=="
864 print "Report generated at: '''" chronos_time "'''"
867 if (section_global_stats_p)
871 if (output_lang == "html")
875 if (output_lang == "wiki")
880 if (section_function_cyclo_p)
882 if (output_lang == "html")
884 html_function_cyclo()
886 if (output_lang == "wiki")
888 wiki_function_cyclo()
893 if ((output_lang == "html") &&
898 if ((output_lang == "wiki") &&
904 # Print footer (html only)
905 if (output_lang == "html")
911 # End of pmccabe2html