#!/usr/bin/perl
########################################################################
#
#                  CTC++ System, ctc2html (v9.1.4.1)
#                  CTC++ to HTML converter
#
#               Copyright (c) 1997-2013 Testwell Oy
#               Copyright (c) 2013-2020 Verifysoft Technology GmbH
##########################################################################
# Additional notice to users:
# Verifysoft Technology provides support for this ctc2html component of
# the CTC++ System in the same way as Verifysoft Technology provides support
# for the other components of the CTC++ System. Because this component is
# provided in a source file form, you are able to modify this file.
# However, if you do any such modifications, Verifysoft Technology may not
# be capable of providing you support, and Verifysoft Technology reserves
# the right not to support you with this component, if you have done your
# own modifications to this file.
##########################################################################
#use strict;
#use warnings;

##########################################################################
# subroutines
##########################################################################
sub parse_cmdline;
sub profile_list;
sub directory_summary;
sub files_summary;
sub functions_summary;
sub histogram;
sub setTimeStamp;
sub setInfo;
sub setStyleInfo;
sub setFilenames;
sub unlinkReportFiles;
sub openReportFiles;
sub create_gif;
sub create_stylesheet;
sub create_script;
sub create_javascript;
sub create_sorttable;
sub create_own_javascript;
sub create_own_javascript_NA;
sub process_source_file;
sub find_file;
sub exp_format;
sub warning;
sub dirname;
sub basename;
sub same_file;
sub get_full_path_name;
sub copyProfileListing;
sub sortProfileListing;
sub compare_pathnames;
sub launch_browser;
sub launch_browser_macos;
sub launch_browser_xdg;
sub isWindows;
sub isMacOS;
sub relname;
sub which;
sub printHTMLHeader;
sub printHTMLHeader_NSF;
sub printHeaderInfo;
sub printSummary;
sub printEllipsis;
sub printFuncsFooter;
sub printProfileFooter;
sub printHTMLFooter;
sub calculateDirectoryTer;
sub start_browsing;
sub getNormalized;
sub utf8;
sub utf8it;
sub uriit;
sub setReducedTo;
sub setFileTer;
sub appendSymDir;
sub parse_conffile;
sub get_enable_hash;
sub set_enable_help;
sub set_conffiles;
sub checkValues;
sub getAlarmCh;
sub nbspit;
sub fixEscape;
sub syntaxHighLight;
sub setOrigSourceLine;
sub paintLine;
sub getLine;
sub getColor;
sub setDirData;
sub replaceEntity;
sub getSyntaxHighlight;
sub getPreprocLines;
sub getStopper;
sub getStyle;
sub getCondStyle;
sub setMacroDefinitions;
sub setSyntaxMode;
sub getClosingLine;
sub getHandle;
sub cp1252;
sub cp1252it;
sub unicode2utf8;
sub shortit;
sub openName;
sub toArrow;
sub toArrowShort;
sub toArrowSingle;
sub updown;
sub tooltip;
sub cleandiff;
sub chooseArrow;
sub stripSecondCopySuffix;

##########################################################################
# global "constants"
##########################################################################
$version            = "ctc2html v9.1.4.1";

# Set charset UTF-8 for HTML content, (was ISO-8859-1)
$charset            = "UTF-8";      # --enable-charset=shift_JIS or --enable-charset=
# Do not convert absolute filenames relative to current working directory
$relativepath       = 0;            # --enable-relativepath=1
# Enable highlighting of evaluation pairs when pointing MC/DC lines
$mcdc_highlight     = 1;            # --enable-mcdc_highlight=0
# Zooms the font sizes. Parameter should be in range 0.5-10
$zoom               = 1;            # --enable-zoom=0.9
# Set statement threshold percent 0-100
$stmtthreshold      = 100;          # --enable-stmtthreshold=75
# Show all untested profile info (do not show only files) at Untested Code page
$light_untested     = 0;            # --enable-light_untested=1
# Reduce Symbol/Data/(Un)chosen files in Files Summary
$files_reduction    = 1;            # --enable-files_reduction=0
# File links from Files Summary to Execution Profile, not in ctc2html.ini
$fis2pro            = 1;            # --enable-fis2pro=0
# This would pull "Droid" fonts from the web, don't enable per default, don't document that.
# Font tester for experiments http://www.lalit.org/lab/javascript-css-font-detect/
$webfonts           = 0;            # --enable-webfonts=1
# To replace '-' warning sign in html output
$alarmch            = "-";          # --enable-alarmch=!, --enable-alarmch="&#9760;"
# Enable syntax highlighting of source code
$syntax_highlight   = 1;            # --enable-syntax_highlight=0
# Enable line coverage background color painting of source code
$line_coverage      = 1;            # --enable-line_coverage=0
# Set user's own stylesheet
$own_stylesheet     = "";           # --enable-own_stylesheet=C:\Testwell\CTC\ctc.css
# Set user's own javascript 
$own_javascript     = "";           # --enable-own_javascript=C:\Testwell\CTC\my.js
# Show only files at Index of Execution Profile page if number of files and functions > limit
$limit_index        = 2000;         # --enable-limit_index=3000
# Enable visibility hidden/visible
$visibility         = 1;            # --enable-visibility=0
# Show statement coverage information
$statement_coverage = 1;            # --enable-statement_coverage=0
# HTML generation uses javascript
$javascript         = 1;            # --enable-javascript=0
# Convert sources to HTML
$sources            = 1;            # --enable-sources=0
# Set user's macro definitions input file
$macro_definitions  = "";           # --enable-macro_definitions=C:\Testwell\CTC\ctc_macro_definitions.txt
# Enable preprocessor conditional background color highlighting
$ppcond_highlight   = 0;            # --enable-ppcond_highlight=1
# Enable prefixed arrows for ctcdiff generated input
$prefix_arrow       = 1;            # --enable-prefix_arrow=1
# Enable verbose mode for ctcdiff  
$ctcdiff_verbose    = 2; # --enable-ctcdiff_verbose=0/1/2
# Enable sub/super representation
#$ctcdiff_sub_super  = 1;
$ctcdiff_arrow      = 2;
$threshold          = 100;
$html_dir           = "CTCHTML";
# File name prefix in HTML files
$prefix             = "index";
$postfix            = ".html";
$tmp_profilefile1   = "ctc_profile1.tmp";
$tmp_profilefile2   = "ctc_profile2.tmp";

# Background color RGB values for rows in Execution Profile columns
# True/False columns no hit
$tcolnhit_background     = "#FFC6C6"; # red
$fcolnhit_background     = "#FFC6C6";
# True/False columns hit/no counter
$profile_background      = "#DFDFE5"; # grey
# Line column line number
$profile_line_background = "#DFDFE5"; # grey
# MC/DC highlight in multicondition line
$mcdc_background         = "#FFFFE0"; # LightYellow
# MC/DC pass/fail in MC/DC line
$mcdc_pass_background    = "#DFDFE5"; # grey
$mcdc_fail_background    = "#FFC6C6"; # red
# Source column line coverage hit/no hit
$linehit_background      = "#DEFADE"; # green
$linehit_border          = "#DEFADE";
$linenhit_background     = "#FFC6C6"; # red
$linenhit_border         = "#FFC6C6";
# Source column no line coverage painting
$lineplain_background    = "#FFFFFF"; # White
$lineplain_border        = "#FFFFFF";
# Disabled code in preprocessor conditional
$disable_code_background = "#FFFFFF"; # White
$disable_code_border     = "#FFFFFF";
# Preprocessor conditional outside of function
$ppcond_background       = "red";#"#FFFFFF"; # White
$ppcond_border           = "red";#"#FFFFFF";
# Preprocessor conditional inside of function
$ppcondin_background     = "yellow";#"#FFFFFF"; # White
$ppcondin_border         = "yellow";#"#FFFFFF";
# #pragma CTC ANNOTATION visibility and font weight
$annotation_background   = "#FFFF00"; # Yellow
$annotation_border       = "#FFFF00";
$annotation_visibility   = "visible"; # hidden
$annotation_weight       = "normal";  # bold
# #pragma CTC COUNT font weight
$count_weight            = "normal";  # bold
# Syntax highlight font weight
$comment_weight          = "normal";  # bold
$string_weight           = "normal";  # bold
$preproc_weight          = "normal";  # bold
$keyword_weight          = "bold";    # normal

# Arrows replacement for ctcdiff usage 
$arrow{'^'} = '^';  # Up arrow
$arrow{'v'} = 'v';  # Down arrow
$arrow{' '} = ' ';        # Space, no-op
$arrow{'|'} = '^v';  # Up-Down arrow, needed for summaries
$arrow{'='} = '=';   # All Equal To

$reptitle = "CTC++ Coverage Report";

$second_copy_suffix = " (other)";
%processed_source_files = ();

$usage = <<"END";
Usage:
  ctc2html [-i inputfile] [-o outputdir] [-t threshold]
           [-s sourcedir[;sourcedir]...]... [-nsb]
  ctc2html [-h] [--enable-help]
END

$help = <<"END";
$version

$usage
Command-line options:
  -i inputfile   Input Execution Profile Listing file. Default stdin
  -o outputdir   Output HTML directory. Default $html_dir
  -t threshold   Set coverage TER% threshold, 0-100. Default $threshold
  -s sourcedir   Source files are searched also from this directory
  -nsb           Do not start HTML browser automatically
  -h             Display this command line help
  --enable-help  Display help of --enable-XXX options
Start browsing from file 'outputdir/$prefix$postfix'
END

$enable_help = "";

$stdin_notice = <<"END";
Profile listing is read from stdin...
END

@gif_header = (71,73,70,56,55,97,10,0,10,0,128,0,0);
@gif_red    = (255,0,0,0,0,0,44,0,0,0,0,10,0,10,0,0,2,8,132,143,169,203,237,15,99,43,0,59);
@gif_blue   = (0,0,255,0,0,0,44,0,0,0,0,10,0,10,0,0,2,8,132,143,169,203,237,15,99,43,0,59);
@gif_white  = (255,255,255,0,0,0,44,0,0,0,0,10,0,10,0,0,2,8,132,143,169,203,237,15,99,43,0,59);
@gif_yellow = (255,255,0,0,0,0,44,0,0,0,0,10,0,10,0,0,2,8,132,143,169,203,237,15,99,43,0,59);

$s{COMMENT}   = '<span class="comment">';
$e{COMMENT}   = '</span>';
$s{STRING}    = '<span class="string">';
$e{STRING}    = '</span>';
$s{KEYW}      = '<span class="keyword">';
$e{KEYW}      = '</span>';
$s{PREP}      = '<span class="preproc">';
$e{PREP}      = '</span>';
#$s{FLOW} = '<span class="flow">';
#$e{FLOW} = '</span>';
#$s{TYPE} = '<span class="type">';
#$e{TYPE} = '</span>';

##########################################################################
# global variables
##########################################################################
*INPUT            = *STDIN;
$input_file       = "<stdin>";
$stdin            = 1; # pipe or redirect=1, file=undef
($sek,$min,$hour,$day,$month,$year,$weekday) = localtime(time); # current time
$gHandle          = "FILEHANDLE000";
$gErr_cmdl        = "ctc2html: Erroneous command line";
$start_browsing   = 1; # start browsing automatically (valid only in MsWindows)
$gFunction_id     = 0;
$gSource_id       = 0;
$numFiles         = 0;
$numDirectories   = 0;
$numUntestedFiles = 0;
$numFunctions     = 0;
$numFunctions2    = 0;
$NextTERs         = 0; # 1=>normal SUMMARY, 2=> ctcdiff's "Fs compared"'s
                       # TERs follow, 3=> "Fs all"'s TERs follow.
$gVerboseIndex    = 1; # 1=show files and functions in Execution Profile Index, undef=show only files in Index
$gFunc_calls      = 0;
$gFunc_line       = 0;
@source_dirs             = ();
# hash for split index (source files)/splitted html profile listing page
%profile_html            = ();
# hash for Execution Profile index/source file basename
%basenames               = ();
# hash for Functions Summary index/directory name
%directories             = ();
# hash for the normalized source file name/file handle
%gSource_handle          = ();
# hash for currently processed source file name/line number
%gProcessing             = ();
# hash for the file name/file is not found
%file_not_found          = ();
# hash for source file name/source ter procent
%source_ter              = ();
# hash for directory name/ordinal number of directory
%directory_ordinal       = ();
%dir_ter_hits            = ();
%dir_ter_all             = ();
%dir_ter_stmt_hits       = ();
%dir_ter_stmt_all        = ();
%dir_ter_up              = ();
%dir_ter_middle          = ();
%dir_ter_down            = ();
# hash for source file name/source ter statement procent
%source_ter_stmt         = ();
# hash for split index (directories)/splitted functions summary html page
%funcs_html              = ();
# hash for directory name/number of files in the directory
%directory_filecount     = ();
# hash for ordinal number of directory/number of files in the directory
%directory_id_filecount  = ();
# hash for directory name/number of files already reported in this directory 
%directory_cur_filecount = ();
# list of conffiles (ctc2html.ini)
@conffiles               = ();
@list                    = ();
# hash for the functions having no line coverage
%no_linecov              = ();
# hash for normalized source/header file name/original source/header file name
%original                = ();
# hash for normalized directory name/original directory name
%original_dir            = ();
# hash for ordinal number of file/original file name
%orig_filenames          = ();
# hash for macro definitions
%defined_macros          = ();
$time_stamp              = "";
$verboseIndexDescr       = "";
$gCoverageView           = "";
$shown_coverage_views    = "";
$file_coverage_view      = "";
$gInstrumentationMode    = "";
$doctype_info            = "";
$doctype_info_frames     = "";
$meta_info               = "";
$script_info             = "";
$style_info              = "";
$copied_style_info       = "";
$onLoad_profile          = "";
$onLoad_funcs            = "";
$onLoad_untested         = "";
$lookahead               = "";
$gParent                 = "";
$gChild                  = "";
$gSource                 = "";
$gCur_directory          = "";
$gPrev_directory         = "";
$index_profile_html      = "";
$files_html              = "";
$frame_profile_html      = "";
$missing_html            = "";
$directory_html          = "";
$overall_html            = "";
$frame_funcs_html        = "";
$index_funcs_html        = "";
$untested_html           = "";
$profile_wild            = "";
$funcs_wild              = "";
$gTer_struct             = "";
$gTer_struct_files       = "";
$gTer_struct_funcs       = "";
$gTer_directory_overall  = "";
$gFunction_link          = "";
$gFile_link_files        = "";
$gFile_link_funcs        = "";
$gOverall_structhits     = "";
$gIndex_dir_id           = 0;
$gFuncs_dir_id           = 0;
$gProfile_untested_id    = 0;
$gUntested_id            = 0;
$gUntested_source_id     = 0;
$gTer_of_source          = 0;
$gTer_of_file            = 0;
$gTer_of_function        = 0;
$gNextTERs               = 1; # at bottom SUMMARY what kind are the two TER
                              # lines to follows: 1=normal ctcpost-generated,
                              # 2=ctcdiff's Fs compared, 3=ctcdiff's Fs all
$gOverall_structter      = 0;
$current_max_multi       = 0;
$min_files               = 3; # if reduced, number of files written to Files Summary
$max_files               = 3; # do not reduce if number of files <= $max_files
$read_input              = 1;
$gExepassed              = 0;
$gPrev_line              = 0;
$explicit_stmtthreshold  = 0;
$gFile_ter_procent        = "";
$gFile_ter_struct_procent = "";
$gFile_ter_stmt_procent   = "";
$reduced_to              = "";
$gTooltip                = "";
$gOrig_source_line       = "";
$gOrig_source_line2      = "";
$current_line            = "";
$next_line               = "";
$gMon_file               = "";
$gMon_function           = "";
$html_options            = "";
$gFooter                 = "";
$gIn_symbol_files           = undef;
$gLine_coverage             = undef;
$gComment_pending           = undef; # multiline C comment pending in syntax highlighting
$gComment_line              = undef; # multiline C comment in line coverage
$gString_lcc                = undef; # multiline string with line-continuation char
$gComment_lcc               = undef; # multiline C++ comment with line-continuation char
$gPreproc_lcc               = undef; # multiline #if macro with line-continuation char
$gDefine_lcc                = undef; # multiline #define macro with line-continuation char
$gPragma_lcc                = undef; # multiline #pragma CTC ANNOTATION with line-continuation char
$gInsert_separator          = undef;
$gTer_100                   = undef;
$gPendingLine               = undef;
$gPending_untested_function = undef;
$version_9_0                = undef;
$listing_type               = undef; # undef=no listing, 1=normal listing
$gOutsideFunction           = undef;
$gSyntaxmode                = undef;
$gOption_s_used             = undef;
$gOption_s_file = "";
$gOption_s_dir  = "";
$gVctcpost     = "";
$gVctcxmlmerge = "";
$gVctc2html    = "";
$gNumUntestedProbes = 0;
$gDir_id     = 0;
$gFileType   = "";
$gFuncs_html = "";
$input_profile1 = undef; # ctcdiff -i1 profile1.txt 
$input_profile2 = undef; # ctcdiff -i2 profile2.txt 

##########################################################################
# execution starts here !
##########################################################################
parse_conffile();
parse_cmdline();
checkValues();
setTimeStamp();
#setMacroDefinitions();
setInfo();
setStyleInfo();

if (-e $html_dir and not -d $html_dir) {
    die "ctc2html: File $html_dir exists and is not a directory\n";
} elsif (not -e $html_dir) {
    mkdir($html_dir, 0755); # 0755 == drwxr-xr-x
}

if (defined $stdin) { # pipe or redirect
    print STDERR $stdin_notice;
}

# open temporary execution profile listing file 1 for output
open(PROFILETMP1, ">$html_dir/$tmp_profilefile1")
    or die "ctc2html: Cannot create file $html_dir/$tmp_profilefile1\n";
# copy original Execution Profile Listing to profile listing 1
# to be used as new input to sorted profile listing 2
while ($current_line = getLine()) {
    $current_line =~ s/\015?\012$//;
    copyProfileListing($current_line);
}
close INPUT;
close PROFILETMP1;

if (not defined $version_9_0) {
    unlink "$html_dir/$tmp_profilefile1";
    die "ctc2html: File $input_file is not a valid version 9.0 Execution Profile Listing\n";
}

if (not defined $listing_type) {
    unlink "$html_dir/$tmp_profilefile1";
    die "ctc2html: File $input_file is not a valid Execution Profile Listing\n";
}
$input_file = replaceEntity($input_file); # <stdin>

print STDERR "Sorting execution profile listing\n";
# sort profile listing 1 to sorted listing 2
if ($numFiles > 0) {
    setDirData();
    # open temporary execution profile listing file 2 for output
    open(PROFILETMP2, ">$html_dir/$tmp_profilefile2")
        or die "ctc2html: Cannot create file $html_dir/$tmp_profilefile2\n";
    print STDERR "Directory ";
    sortProfileListing();
    print STDERR "Done\n";
    close PROFILETMP2;
} else {
    # no monitored source files, copy profile listing 1 to listing 2
    open(PROFILETMP1, "<$html_dir/$tmp_profilefile1")
        or die "ctc2html: Cannot open file $html_dir/$tmp_profilefile1\n";
    open(PROFILETMP2, ">$html_dir/$tmp_profilefile2")
        or die "ctc2html: Cannot create file $html_dir/$tmp_profilefile2\n";
    while (<PROFILETMP1>) {
        print PROFILETMP2 $_;
    }
    close PROFILETMP1;
    close PROFILETMP2;
}

print STDERR "Generating HTML report\n";
# open sorted or empty temporary execution profile listing file 2 for input
open(INPUT, "<$html_dir/$tmp_profilefile2")
    or die "ctc2html: Cannot open file $html_dir/$tmp_profilefile2\n";
setFilenames();
unlinkReportFiles();
create_gif();
create_stylesheet();
create_script();

# build the summaries, profile list, process source etc.
if ($numFiles > 0) {
    openReportFiles();
    calculateDirectoryTer();
    printHTMLHeader();
    while ($current_line = getLine()) {
        $current_line =~ s/\015?\012$//;
        printHeaderInfo($current_line);
    }
    directory_summary();
    profile_list($lookahead);
    files_summary($lookahead);
    functions_summary($lookahead);

    while ($current_line = getLine()) {
        $current_line =~ s/\015?\012$//;
        $current_line = replaceEntity($current_line);
        profile_list($current_line);
        files_summary($current_line);
        functions_summary($current_line);
    }
    printHTMLFooter();
} else {
    # No monitored Source Files
    open(FILES, ">$html_dir/$files_html")
        or die "ctc2html: Cannot create file $html_dir/$files_html\n";
    open(DIRECTORY, ">$html_dir/$directory_html")
        or die "ctc2html: Cannot create file $html_dir/$directory_html\n";
    open(OVERALL, ">$html_dir/$overall_html")
        or die "ctc2html: Cannot create file $html_dir/$overall_html\n";
    printHTMLHeader_NSF();
    while ($current_line = getLine()) {
        $current_line =~ s/\015?\012$//;
        printHeaderInfo($current_line);
    }
}
print STDERR "Done\n";
close INPUT;
unlink "$html_dir/$tmp_profilefile1";  # CTCHTML/ctc_profile1.tmp
unlink "$html_dir/$tmp_profilefile2";  # CTCHTML/ctc_profile2.tmp
foreach $key ( keys %cr ) {  # Macintosh line breaks
    unlink $cr{$key};
}
start_browsing();

1;
##########################################################################
# The program execution ends here.
##########################################################################

##########################################################################
# SUBROUTINES
##########################################################################

##########################################################################
# SUBROUTINE: set_enable_help
# PURPOSE   : constructs help string for cmdline option --enable-help
##########################################################################
sub set_enable_help
{
    $enable_help = <<"END";
$version

Fine-tune the generated HTML. The settings are read from ctc2html.ini,
if found (see User's Guide). The defaults are shown in parentheses.
 --enable-charset=CHARSET        Set charset for HTML content ($charset)
 --enable-stmtthreshold=PERCENT  Set stmt.coverage threshold, 0-100 ($stmtthreshold)
 --enable-line_coverage=0/1      Use line coverage bg.color painting ($line_coverage)
 --enable-mcdc_highlight=0/1     Highlight MC/DC eval pairs by cursor ($mcdc_highlight)
 --enable-syntax_highlight=0/1   Generate syntax highlighting of source ($syntax_highlight)
 --enable-statement_coverage=0/1 Show statement coverage information ($statement_coverage)
 --enable-own_stylesheet=FILE    Specify user's own stylesheet file ($own_stylesheet)  
 --enable-own_javascript=FILE    Specify user's own javascript file ($own_javascript)  
 --enable-zoom=NUMBER            Zoom the generated HTML font, 0.5-10 ($zoom)
 --enable-visibility=0/1         Show '#pragma CTC ANNOTATION/COUNT' part ($visibility)
 --enable-light_untested=0/1     Show only files at Untested Code page ($light_untested)
 --enable-files_reduction=0/1    Reduce shown Symbol/Data/(Un)chosen files ($files_reduction)
 --enable-alarmch=CHARACTER      Set alarm character ($alarmch)
 --enable-limit_index=NUMBER     Reduce Execution Profile Index frame ($limit_index)
 --enable-relativepath=0/1       Convert abspaths of files relative to (.) ($relativepath)
 --enable-sources=0/1            Convert sources to HTML ($sources)
 --enable-javascript=0/1         HTML generation uses javascript ($javascript)
 --enable-help                   Display this help of --enable-XXX options
END

}

##########################################################################
# SUBROUTINE: parse_conffile
# PURPOSE   : 
##########################################################################
sub parse_conffile
{
    my $conffile = "";
    my $key;
    my %enable = get_enable_hash();

    set_conffiles();

    while (@conffiles > 0) {
        $conffile = shift @conffiles;
        # open conffile for input
        open(CONF, "<$conffile")
            or print STDERR "ctc2html: Cannot open file $conffile\n", next;

        while (<CONF>) {
            chop; # remove line end

            if ($_ =~ /^\s*#.*/) { # comment line
                next;
            }
            elsif ($_ =~ /^\s*$/) { # empty line
                next;
            }
            elsif ($_ =~ /^\s*--enable-(.+)=(.*)/) {
                my $var = $1;
                my $val = $2;
                $var =~ s/\s//g;
                $val =~ s/\s//g;

                if ($var eq "stmtthreshold") {
                    $explicit_stmtthreshold = 1;
                }

                foreach $key (keys %enable) {
                    if ($key eq $var) {
                        $$var = $val;
                    }
                }
            }
            else {
                my $unknown = "Unknown option " . $_;
                warning($unknown);
            }
        }
        close CONF;
    }
    set_enable_help();
}

##########################################################################
# SUBROUTINE: get_enable_hash
# PURPOSE   : 
##########################################################################
sub get_enable_hash
{
    # Set allowed key/values of the enable hash
    my %enable = (
        charset => 1,
        relativepath => 2,
        mcdc_highlight => 3,
        zoom => 4,
        stmtthreshold => 5,
        light_untested => 6,
        files_reduction => 7,
        fis2pro => 8,
        webfonts => 9,
        alarmch => 10,
        syntax_highlight => 11,
        line_coverage => 12,
        limit_index => 13,
        own_stylesheet => 14,
        visibility => 15,
        own_javascript => 16,
        statement_coverage => 17,
        ppcond_highlight => 18,
        sources => 19,
        javascript => 20,
	prefix_arrow => 21,
	ctcdiff_verbose => 22,
	ctcdiff_arrow => 23
    );
    return %enable;
}

##########################################################################
# SUBROUTINE: set_conffiles
# PURPOSE   : set specified conffiles
# ARGUMENTS : -
# RETURNS   : 
##########################################################################
sub set_conffiles 
{
    if (isWindows()) { # MsWindows only:
        # if ./ctc2html.ini exists add it to the list of conffiles
        if (-e "./ctc2html.ini") {
            unshift @conffiles, "./ctc2html.ini";
        }
    } else { # UNIX only:
        # if ./.ctc2html.ini exists add it to the list of conffiles
        if (-e "./.ctc2html.ini") {
            unshift @conffiles, "./.ctc2html.ini";
        }
    }

    if (!isWindows()) { # UNIX only:
        # if $HOME/.ctc2html.ini exists add it to the list of conffiles
        if ($ENV{HOME}) {
            if (-e $ENV{HOME} . "/.ctc2html.ini") {
                unshift @conffiles, $ENV{HOME} . "/.ctc2html.ini";
            }
        }
    }

    # if $CTCHOME/ctc2html.ini exists add it to the list of conffiles
    if ($ENV{CTCHOME}) {
        if (-e $ENV{CTCHOME} . "/ctc2html.ini") {
            unshift @conffiles, $ENV{CTCHOME} . "/ctc2html.ini";
        }
    }

    if (!isWindows()) { # UNIX only:
        # if $HOME/lib/ctc/ctc2html.ini exists add it to the list of conffiles
        if ($ENV{HOME}) {
            if (-e  $ENV{HOME} . "/lib/ctc/ctc2html.ini") {
                unshift @conffiles, $ENV{HOME} . "/lib/ctc/ctc2html.ini";
            }
        }

        # if /usr/local/lib/ctc/ctc2html.ini exists add it to the list of conffiles
        if (-e "/usr/local/lib/ctc/ctc2html.ini") {
            unshift @conffiles, "/usr/local/lib/ctc/ctc2html.ini";
        }
    }
}

##########################################################################
# SUBROUTINE: parse_cmdline
# PURPOSE   : This subroutine parses the command line and possibly
#             sets the output file names, the threshold percent
#             and the input file name. The command line switches are:
#               -t n          set the threshold percent to n
#               -i file       set the input file name to 'file'
#               -o html-dir   set the output dir name to 'html-dir'
#               -s sourcedir  specify directory where the original
#                             sources can be found
#               -nsb          do not start browser automatically
#               -h            display a brief help on usage
#               --enable-XXX=YYY advanced options
#     If any or all of the above are missing, default values
#     are used. If something else is given on the command line,
#     error message is issued and the program exits.
#     If no filenames given on command line, or stdin is not piped 
#     like "| ctc2html" or not redirected like "ctc2html < profile.txt"
#     we just print error message and exit
##########################################################################
sub parse_cmdline
{
    my $start_help = "start ctc2html with option -h for help\n";
    my $i = 0;
    my $option = "";
    my $var = "";
    my $val = "";

    # Handle the bare "ctc2html" case
    if (@ARGV == 0) {
        if (-t INPUT) { # no pipe or redirect
            print $help;
            exit 0;
        }
    }

    # options shown in html
    foreach (@ARGV) {
        $option=$_;
        if ($option =~ /\s/) {
            $option = '"' . $option . '"';
        }
        $html_options .= "$option ";
    }
    $html_options =~ s/\s$//;
      
    # doesn't apply to ctc2html.ini, just convenient to help out command line use
    for ($i = 0; $i <= $#ARGV; $i++) {
        if ($ARGV[$i] eq "-h") {
            print $help;
            exit 0;
        }

        elsif ($ARGV[$i] =~ /^--enable-help$/) {
            print $enable_help;
            exit 0;
        }

        elsif ($ARGV[$i] =~ /^(--)(enable-)(help=.*)/ or 
                 $ARGV[$i] =~ /^(--)(disable-)(help.*)/ or
                 $ARGV[$i] =~ /^(--)(disable-)(.+=.*)/ or
                 $ARGV[$i] =~ /^(--)(enable|disable)(-charset)$/ or
                 $ARGV[$i] =~ /^(--)(enable|disable)(-stmtthreshold)$/ or
                 $ARGV[$i] =~ /^(--)(enable|disable)(-own_stylesheet)$/ or
                 $ARGV[$i] =~ /^(--)(enable|disable)(-zoom)$/ or
                 $ARGV[$i] =~ /^(--)(enable|disable)(-alarmch)$/ or
                 $ARGV[$i] =~ /^(--)(enable|disable)(-limit_index)$/)
        {
            die $gErr_cmdl . ", option $1$2$3\n" . $start_help;
        }

        elsif ($ARGV[$i] =~ /^--enable-stmtthreshold=.*/) {
            $explicit_stmtthreshold = 1;
        }

        elsif ($ARGV[$i] =~ /^--enable-.+=.*/) {
            ; # Do nothing
        }

        elsif ($ARGV[$i] =~ /^--enable-(.+)/) {
            $ARGV[$i] = "--enable-$1=1";
        }

        elsif ($ARGV[$i] =~ /^--disable-(.+)/) {
            $ARGV[$i] = "--enable-$1=0";
        }
    }

    for ($i = 0; $i <= $#ARGV; $i++) {
        SWITCH: {
            if ($ARGV[$i] eq "-t") {
                if ($i < $#ARGV and $ARGV[$i + 1] =~ /[0-9]+$/) {
                    $threshold = $ARGV[$i + 1];
                    # only now inherit -t option also to stmt cov.
                    if ($explicit_stmtthreshold == 0) {
                        $stmtthreshold = $threshold;
                    }
                    ++$i;
                } else {
                    die $gErr_cmdl . ", -t requires an argument 0-100\n" . $start_help;
                }
                last SWITCH;
            }

            if ($ARGV[$i] eq "-i") {
                if ($i < $#ARGV) {
                    if ($ARGV[$i + 1] =~ /\s/ and $ARGV[$i + 1] =~ /^".*"$/) {
                        $ARGV[$i + 1] =~ s/^"(.*)"$/$1/;
                    }
                    open(INPUT, "<$ARGV[$i + 1]")
                        or die "ctc2html: Cannot open file $ARGV[$i + 1]\n";
                    $input_file = $ARGV[$i + 1];
                    ++$i;
                    undef $stdin;
                } else {
                    die $gErr_cmdl . ", -i requires an input file name argument\n" . $start_help;
                }
                last SWITCH;
            }

            if ($ARGV[$i] eq "-o") {
                if ($i < $#ARGV) {
                    $html_dir = $ARGV[$i + 1];
                    ++$i;
                } else {
                    die $gErr_cmdl . ", -o requires an output directory name argument\n" . $start_help;
                }
                last SWITCH;
            }

            if ($ARGV[$i] eq "-s" and $i < $#ARGV) {
                push(@source_dirs, split(/;/, $ARGV[++$i]));
                last SWITCH;
            }
          
            if ($ARGV[$i] eq "-nsb") {
                $start_browsing = 0;
                last SWITCH;
            }

            if ($ARGV[$i] =~ /^--enable-/) {
                $_ = $ARGV[$i];
                if (/^--enable-(.+)/) {
                    $_ = $1;
                    /^(.*)=(.*)$/; # zoom=0.9 or charset= or charset=shift_JIS or ...
                    $var = $1;
                    $val = $2;
                    if (not defined $$var) {
                        die $gErr_cmdl . ", unknown option --enable-$var\n" . $start_help;
                    } else {
                        if ($val eq "") {
                            if ($var eq "charset") {
                                $$var = "";
                            } else {
                                die $gErr_cmdl . ", --enable-$var requires a value\n" . $start_help;
                            }
                        } else {
                            $$var = $val;
                        }
                    }
                } else {
                    die $gErr_cmdl . ", unknown option --enable-\n" . $start_help;
                }
                last SWITCH;
            }
            die $gErr_cmdl . "\n" . $start_help;
        } # SWITCH
    }

    if (-t INPUT) { # no filename, pipe or redirect
        die $gErr_cmdl . ", No input\n" . $start_help;
    }
}

##########################################################################
# SUBROUTINE: checkValues
# PURPOSE   : 
##########################################################################
sub checkValues
{
    my $var;
    my $val;
    my $key;
    my %enable = get_enable_hash();

    foreach $key (keys %enable) {
        $var = $key;
        $val = $$var;

        if ($var eq "alarmch") {
            ;
        }
        elsif ($var eq "charset") {
            if ($val eq "") {
                undef $charset;
            }
        }
        elsif ($var eq "stmtthreshold") {
            if ($val !~ /^\d+$/) {
                die $gErr_cmdl . ", --enable-" . $var . " requires value 0-100\n";
            } elsif ($val > 100) {
                die $gErr_cmdl . ", --enable-" . $var . " requires value 0-100\n";
            }
        }
        elsif ($var eq "zoom") {
            if ($val !~ /^[.\d]+$/) {
                die $gErr_cmdl . ", --enable-" . $var . " requires value 0.5-10\n";
            } elsif ($val < 0.5 or $val > 10) {
                die $gErr_cmdl . ", --enable-" . $var . " requires value 0.5-10\n";
            }
        }
        elsif ($var eq "limit_index") {
            if ($val !~ /^\d+$/) {
                die $gErr_cmdl . ", --enable-" . $var . " requires value > 0\n";
            } elsif ($val < 1) {
                die $gErr_cmdl . ", --enable-" . $var . " requires value > 0\n";
            }
        }
        elsif ($var eq "ctcdiff_verbose") {
            if ($val !~ /^\d+$/) {
                die $gErr_cmdl . ", --enable-" . $var . " requires value  0, 1 or 2\n";
            } elsif ($val < 0 && $val >2 ) {
                die $gErr_cmdl . ", --enable-" . $var . " requires value  0, 1 or 2\n";
            }
        }
        elsif ($var eq "ctcdiff_arrow") {
            if ($val !~ /^\d+$/) {
                die $gErr_cmdl . ", --enable-" . $var . " requires value range 0 - 6\n";
            } elsif ($val < 0 && $val >6 ) {
                die $gErr_cmdl . ", --enable-" . $var . " requires value range 0 - 6\n";
            }
	    $ENV{ARROW}=$val;
	    chooseArrow();
        }
        elsif ($var eq "own_stylesheet") {
            if ($val ne "") {
                # open cssfile for input test
                open(CSS, "<$val")
                    or die $gErr_cmdl . ", --enable-" . $var . " requires existing file\n";
                close CSS;
            }
        }
        elsif ($var eq "own_javascript") {
            if ($val ne "") {
                # open jsfile for input test
                open(JS, "<$val")
                    or die $gErr_cmdl . ", --enable-" . $var . " requires existing file\n";
                close JS;
            }
        }
        else {
            if ($val !~ /^0|1$/) {
                die $gErr_cmdl . ", --enable-" . $var . " requires value 0 or 1\n";
            }
        }
    }

    if ($javascript == 0) {
        undef $javascript;
    }

    if ($mcdc_highlight == 0) {
        undef $mcdc_highlight;
    } else {
        if (not defined $javascript) {
            undef $mcdc_highlight;
        }
    }

    if ($line_coverage == 0) {
        undef $line_coverage;
    }

    if ($statement_coverage == 0) {
        undef $statement_coverage;
    }

    if ($syntax_highlight == 0) {
        undef $syntax_highlight;
    }

    if ($sources == 0) {
        undef $sources;
    }

    if ($light_untested == 0) {
        undef $light_untested;
    }

    if ($visibility == 0) {
        undef $visibility;
    }

    if ($relativepath == 0) {
        undef $relativepath;
    }

    if ($fis2pro == 0) {
        undef $fis2pro;
    }

    if ($webfonts == 0) {
        undef $webfonts;
    }

    if ($ppcond_highlight == 0) {
        undef $ppcond_highlight;
    }

    if ($own_stylesheet eq "") {
        undef $own_stylesheet;
    }

    if ($own_javascript eq "") {
        undef $own_javascript;
    }

    if ($macro_definitions eq "") {
        undef $macro_definitions;
    }

    
}

##########################################################################
# SUBROUTINE: getLine
# PURPOSE   : - read current line from input handle or set to next line
# ARGUMENTS : 
# RETURNS   : - current line read from input or next line
##########################################################################
sub getLine
{
    if ($read_input == 1) {
        $current_line = <INPUT>;
    } else {
        $current_line = $next_line;
        $read_input = 1;
    }
    return $current_line;
}

##########################################################################
# SUBROUTINE: profile_list
# PURPOSE   : This subroutine builds an HTMLized version of the original
#             execution profile listing combined with the source files.
##########################################################################
sub profile_list
{
    $_ = $_[0];
    my ($startcolor, $endcolor, $structcolor, $stmtcolor, $sourcestyle);
    my ($path, $pLine, $uLine);
    my $next_untested_id = 0;
    my $exepassed_pending = 0;
    my $current_file = "";
    my $ter_file = "";
    my $notfound = "";
    my $alarm = "";
    my $aLine_coverage = undef;
    my $source_line = undef;

    if (/^MONITORED (.+) FILE : (.+)/) {
        if ($1 eq "SOURCE") {
            $gFileType = "Source file";
        } else {
            $gFileType = "Header file";
        }

        $gParent = $2; # normalized "parent" source file name
        $gSource = $gParent;
        $gChild = "";
        $gSource_id++;
        $gCur_directory = dirname($gParent); # normalized directory name
        $gDir_id = $directory_ordinal{$gCur_directory}; # 1,2...n
        $gFuncs_html = $funcs_html{$gDir_id}; # indexB1/B2.../Bn.html (Functions Summary)
        $gFile_ter_struct_procent = $source_ter{$gParent};
        $gFile_ter_stmt_procent = $source_ter_stmt{$gParent};
        $gTer_100 = $gFile_ter_struct_procent =~ /^TER\s+100\b/ ? 1 : undef;
        $gUntested_source_id++ unless defined $gTer_100;
        $gProfile_untested_id = 1;
        $gUntested_id = 0;
        $gOutsideFunction = 1;
        $gNumUntestedProbes = 0;
        undef $gLine_coverage;
        undef $gInsert_separator;
        undef $gPendingLine;
        undef %gProcessing;
        undef %gSource_handle;

        if (defined $file_not_found{stripSecondCopySuffix($gSource)}) {
            $gSource = $missing_html;
        } else {
            $gProcessing{$gSource} = 0;
        }

        if (defined $sources) { # option --enable-sources
            # open the original source file for reading
            if ($gSource ne $missing_html) {
                open($gHandle, "<" . stripSecondCopySuffix(openName($gSource)))
                    or die "ctc2html: Cannot open file $gSource\n";
                $gSource_handle{$gSource} = $gHandle;
                $gHandle++;
            } else { # not found at ctc2html time => only description
                $notfound = "<span class=\"notfound\">(source not found)</span>";
            }
        }

        open(PROFILE, ">>$html_dir/$profile_html{$gSource_id}")
            or die "ctc2html: Cannot append file $html_dir/$profile_html{$gSource_id}\n";

        if ($gSource_id == 1) {
            print STDERR "File $gSource_id ";
        } else {
            print STDERR "$gSource_id ";
        }

        # convert original absolute filename relative to current working directory if option --enable-relativepath
        $current_file = defined $relativepath ? relname($original{$gParent}) : $original{$gParent};
        $current_file = utf8it($current_file);
        print PROFILE <<"END";
<span class="infob">$gFileType:</span><span class="infob">$current_file</span>$notfound<br>
END
        unless (defined $gTer_100) {
            print UNTESTED <<"END";
<span class="infob">$gFileType:</span><span class="infob"><a href="$profile_html{$gSource_id}" name="ufi$gUntested_source_id" target="_top">$current_file</a></span><br>
END
        }
        # use original absolute filename
        $current_file = $original{$gParent};
        $current_file = utf8it($current_file);
        print INDEX_PROFILE <<"END";
<tr><td><a href="$profile_html{$gSource_id}" name="a$gSource_id" class="underlineb" target="profile" title="#$gSource_id">$current_file</a></td></tr>
END
        unless (defined $gTer_100) {
            print INDEX_UNTESTED <<"END";
<tr><td><a href="$untested_html#ufi$gUntested_source_id" name="ufi$gUntested_source_id" class="underlineb" target="untested" title="#$gUntested_source_id">$current_file</a></td></tr>
END
        }
    }

    elsif (/^INSTRUMENTATION MODE\s+: (.+)/) {
        $gInstrumentationMode = $1;
        setReducedTo();
        setFileTer();

        my $instrumentation_line = <<"END";
<span class="infob">Instrumentation mode:</span><span class="info">$gInstrumentationMode</span>$reduced_to<br>
<span class="infob">TER:</span>$gFile_ter_procent<br><br>
END
        print PROFILE $instrumentation_line;
        print UNTESTED $instrumentation_line unless defined $gTer_100;
    }

    elsif (/^\s+HITS\/TRUE\s+FALSE\s+LINE\s+DESCRIPTION/) {
        print PROFILE <<"END";
<table class="execution">
<thead>
<tr><th>Hits/True</th><th>False</th><th><a href="$profile_html{$gSource_id}#ut$gProfile_untested_id" title="First untested">Line</a></th><th>Source</th></tr>
</thead>
<tbody>
END
        # show untested files and functions at Untested Code page
        unless (defined $light_untested) { # option --enable-light_untested
            unless (defined $gTer_100) {
                print UNTESTED <<"END";
<table class="untested">
<thead>
<tr><th>Hits/True</th><th>False</th><th>-</th><th><a href="$profile_html{$gSource_id}#ut$gProfile_untested_id" target="_top" title="First untested">Line</a></th><th>Source</th></tr>
</thead>
<tbody>
END
            }
        }
    }

    elsif (/^(#include) "(.+)"/) {
        my ($include, $current_header) = ($1, $2);
        my $path_to_header = $current_header;

        if (defined $file_not_found{$path_to_header}) {
            $path_to_header = $missing_html;
        }

        if (defined $sources) { # option --enable-sources
            if ($path_to_header eq $missing_html) { # not found at ctc2html time => only description
                $notfound = "<span class=\"profile_notfound\">(source not found)</span>";
            }
        }

        $current_file = $original{$current_header};
        $current_file = utf8it($current_file);
        $current_file = '"' . $current_file . '"';
        print PROFILE <<"END";
<tr><td colspan="4"><span class="linedir">$include</span><span class="linedir">$current_file</span>$notfound</td></tr>
END
    }

    elsif (/^\s+(\d+)(\s*)(#line )(\d+) "(.+)"/) {
        # change the current source (header) file after a line directive
        my ($line, $indent, $linedir, $linedir_line, $current_header) = ($1, $2, $3, $4, $5);
        my $flag = undef;

        if (defined $gPendingLine) {
            print PROFILE $gPendingLine;
            undef $gPendingLine;
        }

        if ($gChild eq "") {
            $gSource = $gParent;
        } else {
            $gSource = $gChild;
        }

        if (defined $file_not_found{stripSecondCopySuffix($gSource)}) {
            $gSource = $missing_html;
        } else {
            $gProcessing{$gSource} = $line;
        }

        if (defined $gOutsideFunction) { # line directive outside of function, no line coverage
            if (defined $sources) {
                # process source lines up to line-directive description without line coverage
                if ($gSource ne $missing_html) {
                    # set line coverage off
                    $aLine_coverage = $gLine_coverage;
                    undef $gLine_coverage;
                    $source_line = process_source_file($line, $flag);
                    # set line coverage to its original value
                    $gLine_coverage = $aLine_coverage;
                }
            }
        } else { # line directive inside of function, use line coverage
            if (defined $sources) {
                # process source lines up to line-directive description with line coverage
                if ($gSource ne $missing_html) {
                    $source_line = process_source_file($line, $flag);
                }
            }
        }

        # source line with #include header is printed
        if (defined $source_line) {
            if ($source_line =~ /^<span class="preproc">\s*#\s*include.+?<\/span>/) {
                print PROFILE <<"END";
<tr><td class="profile" colspan="2"></td><td class="profile_line">$line</td><td><span class="lineplain">$source_line</span></td></tr>
END
            }
        }

        # initialize because of file change
        $gPrev_line = $linedir_line - 1;
        $gSource = $current_header;

        if (defined $file_not_found{$gSource}) {
            $gSource = $missing_html;
        } else {
            $gProcessing{$gSource} = $linedir_line - 1; # there may be function probe in linedir line
        }

        if (defined $sources) { # option --enable-sources
            if ($gSource ne $missing_html)
            {
                # a new "child" (included) header file begins, open file for reading
                if (not defined $gSource_handle{$gSource}) {
                    open($gHandle, "<" . openName($gSource))
                        or die "ctc2html: Cannot open file $gSource\n";
                    $gSource_handle{$gSource} = $gHandle;
                    $gHandle++;
                }

                # back to "parent" (includer) source file
                if ($gSource eq $gParent) {
                    $gChild = "";
                } else {
                    $gChild = $gSource;
                }
            } else { # not found at ctc2html time => only description
                $notfound = "<span class=\"profile_notfound\">(source not found)</span>";
            }
        }

        # profile listing's line-directive description is printed with proper indentation
        $indent =~ s/\s{1}(\s*)/$1/;
        $indent =~ s/\s/&nbsp;/g;
        $current_file = $original{$current_header};
        $current_file = utf8it($current_file);
        $current_file = '"' . $current_file . '"';

        print PROFILE <<"END";
<tr><td class="profile" colspan="2"></td><td class="profile_line">$line</td><td><span class="profile_descr">$indent$linedir$linedir_line $current_file</span>$notfound</td></tr>
END
        unless (defined $light_untested) {
            my $linedir_untested = <<"END";
<tr><td class="profile" colspan="3"></td><td class="profile_line">$line</td><td><span class="profile_descr">$indent$linedir$linedir_line $current_file</span></td></tr>
END
            if (defined $gOutsideFunction) {
                undef $gPending_untested_function;
                print UNTESTED $linedir_untested unless defined $gTer_100;                
            } else {
                # function has been called, but some probes may be untested
                if (defined $gPending_untested_function) {
                    $gPending_untested_function .= $linedir_untested;
                } else {
                    print UNTESTED $linedir_untested unless defined $gTer_100;
                }
            }
        }
    }

    elsif (/^\s*(\d+)( |\^|v)(           |\(not avail\)|\(different\))(-| ) {0,5}(\d+)\s*(FUNCTION) (.+)/) {
        # a function begins in the profile list.
        # ( no diff-marks ^/v when "(not avail)" or ("different") )
        my ($start, $tdiff, $new_chng, $flag, $line, $descr, $function) = ($1, $2, $3, $4, $5, $6, $7);
        my $function_probe = $_;

        $gFunction_id++;
        undef $gPending_untested_function;

        if ($new_chng eq "           ") {
            $new_chng = "";
        }

        if ($flag eq "-") {
            $gNumUntestedProbes++;
        } else {
            undef $flag;
        }

        # set global line coverage from user setting (--enable-line_coverage)
        if (not defined $no_linecov{$function_probe}) {
            $gLine_coverage = $line_coverage;
        } else {
            # specific function not having line coverage
            undef $gLine_coverage;
        }

        if ($start == 0) {
            $startcolor = "tcolnhit";
            $endcolor = "profile";
        } else {
            $startcolor = "profile";
            $endcolor = "profile";
        }

        $sourcestyle = "lineplain";

        if (defined $gLine_coverage) {
            if ($line == $gPrev_line) { # additional function execution description
                if ($start > 0) {
                    $gExepassed = 1;
                } else {
                    $gExepassed = 0;
                }
            } else { # first function execution description
                if ($start > 0) {
                    $sourcestyle = "linehit";
                    $gExepassed = 1;
                } else {
                    $sourcestyle = "linenhit";
                    $gExepassed = 0;
                }
            }
        }
        elsif (defined $line_coverage) {
            if ($line == $gPrev_line) { # additional function execution description
                ;
            } else { # first function execution description
                if ($start > 0) {
                    $sourcestyle = "linehit";
                } else {
                    $sourcestyle = "linenhit";
                }
            }
            $gExepassed = 0;
        }

        # additional execution description line may follow with same line number
        $gPrev_line = $line;
        $start = exp_format($start, 6);
        $next_untested_id = $gProfile_untested_id + 1;

        if (defined $flag) {
            $pLine = "<a href=\"$profile_html{$gSource_id}#ut$next_untested_id\" id=\"ut$gProfile_untested_id\">$line</a>";
            $gProfile_untested_id = $next_untested_id;
        } else {
            $pLine = $line;
        }

        if (defined $sources) { # option --enable-sources
            if ($gSource ne $missing_html) {
                # process source lines outside of function up to first function description in line without line coverage
                if ($gProcessing{$gSource} < $line) {
                    # set line coverage off
                    $aLine_coverage = $gLine_coverage;
                    undef $gLine_coverage;
                    $source_line = process_source_file($line, $flag);
                    $gProcessing{$gSource} = $line;
                    $gOrig_source_line = "";
                    # set line coverage to its original value
                    $gLine_coverage = $aLine_coverage;
                }
            }
        }

        $current_file = $original{$gParent};
        $current_file = utf8it($current_file);
	my $arrow = toArrowSingle($start,$tdiff);
        my $function_line = <<"END";
<tr><td class="top" colspan="4"><a href="$profile_html{$gSource_id}" title="$current_file">Top</a></td></tr>
END
	
        # function source line is printed
        if (defined $source_line) {
            $function_line .= <<"END";
<tr><td class="$startcolor"><a id="a$gFunction_id"></a>$arrow</td><td class="$endcolor"></td><td class="profile_line">$pLine</td><td><span class="$sourcestyle">$source_line</span></td></tr>
END
        } else { # additional function description or source not found at ctc2html time or
            # option --disable-sources => function description is printed
            $function_line .= <<"END";
<tr><td class="$startcolor"><a id="a$gFunction_id"></a>$arrow</td><td class="$endcolor"></td><td class="profile_line">$pLine</td><td><span class="profile_descr">$descr $function</span></td></tr>
END
        }

        print PROFILE $function_line;
        # show untested files and functions at Untested Code page
        $alarm = getAlarmCh($flag);        
        unless (defined $light_untested) {
            unless (defined $gTer_100) {
                # function has not been called
                if (defined $flag) {
                    $gUntested_id++;
                    $uLine = "<a href=\"$profile_html{$gSource_id}#ut$gUntested_id\" target=\"_top\">$line</a>";
                } else {
                    $uLine = $line;
                }

                $gPending_untested_function = <<"END";
<tr><td class="$startcolor"><a id="a$gFunction_id"></a>$start</td><td class="$endcolor"></td><td class="untested_flag">$alarm</td><td class="profile_line">$uLine</td><td><span class="profile_descr">$descr $function</span></td></tr>
END
                if (defined $gInsert_separator) {
                    my $separator = <<"END";
<tr><td class="separator" colspan="5"></td></tr>
END
                    $gPending_untested_function = $separator . $gPending_untested_function;
                }

                if (defined $flag) {
                    print UNTESTED $gPending_untested_function;
                    undef $gPending_untested_function;
                    $gInsert_separator = 1;
                }
            }
        }

        # There's no '***TER ... of FUNCTION ..." line in the profile listing
        # when function coverage instrumentation. Hence, "simulate" it.
        # Following line directive may be in inside of function except when function coverage.
        if ($gInstrumentationMode eq "function" or
            $gInstrumentationMode eq "function+inclusive_timing" or
            $gInstrumentationMode eq "function+exclusive_timing" or
            $gCoverageView eq "Reduced to function coverage")
        {
            my $ter_tooltip = "";
            if (defined $flag) {
                $ter_tooltip = "TER 0 % (0/1)";
            } else {
                $ter_tooltip = "TER 100 % (1/1)";
            }

            if (defined $gVerboseIndex) {
                print INDEX_PROFILE <<"END";
<tr><td><span class="indent"></span><a href="$profile_html{$gSource_id}#a$gFunction_id" class="underline" target="profile" title="$ter_tooltip">$function</a></td></tr>
END
            }
            $gOutsideFunction = 1;
        } else {
            undef $gOutsideFunction;
        }
    }

    elsif (/^\s+(\d+)(\s+)(User annotation:.*)/) {
        # annotation description begins
        my ($line, $indent, $descr) = ($1, $2, $3);
        my $flag = undef;
        my $annotation_line = "";

        if (defined $gPendingLine) {
            print PROFILE $gPendingLine;
            undef $gPendingLine;
        }

        if ($gSource ne $missing_html) {
            $gProcessing{$gSource} = $line;
        }

        if (defined $sources) {
            # process source up to annotation description
            if ($gSource ne $missing_html) {
                $source_line = process_source_file($line, $flag);
            }
        }

        # source line with annotation description is printed
        if (defined $source_line) {
            $annotation_line = <<"END";
<tr><td class="profile" colspan="2"></td><td class="profile_line">$line</td><td><span class="lineplain">$source_line</span></td></tr>
END
        } else { # source not found at ctc2html time or option --disable-sources
            # => annotation description is printed
            $indent =~ s/\s{1}(\s*)/$1/;
            $indent =~ s/\s/&nbsp;/g;
            $annotation_line = <<"END";
<tr><td class="profile" colspan="2"></td><td class="profile_line">$line</td><td><span class="profile_descr">$indent$descr</span></td></tr>
END
        }
        print PROFILE $annotation_line;
    }

    elsif (/^\s+(\d+)\s*(}[+-])/ or /^\s+(\d+)\s+(\S+:\+*)/) {
        # block end, label, lambda function end nr, function-try end execution description begins
        my ($line, $descr) = ($1, $2);
        my $line2 = 0;
        my $flag = undef;
        my $print_source_line = undef;

        if (defined $gPendingLine) {
            print PROFILE $gPendingLine;
            undef $gPendingLine;
        }

        $sourcestyle = "lineplain";

        if (defined $gLine_coverage) {
            if ($descr =~ /}([+-])/) { # }+ }- block end, lambda function end nr, function-try end
                if ($1 eq "+") {
                    $exepassed_pending = 1;
                }
                if ($gExepassed == 1) {
                    $sourcestyle = "linehit";
                } else {
                    $sourcestyle = "linenhit";
                }
            } else { # label:+ label:
                $descr =~ /\S+:(\+*)/;
                if ($1 eq "+") {
                    $exepassed_pending = 1;
                } else {
                    if ($gExepassed == 1) {
                        $exepassed_pending = 1;
                    }
                }
                if ($exepassed_pending == 1) {
                    $sourcestyle = "linehit";
                } else {
                    $sourcestyle = "linenhit";
                }
            }
        }

        if (defined $sources) {
            if ($gSource ne $missing_html) {
                # process source up to first block end execution description in line with current exepassed state
                if ($gProcessing{$gSource} < $line) {
                    $source_line = process_source_file($line, $flag);
                    $gProcessing{$gSource} = $line;
                    # read next line from input handle
                    $next_line = <INPUT>;
                    $read_input = 0;
                    $next_line =~ /^[\d ]{10} [\d ]{10} (-| ) {0,5}(\d+)\s*.+/;
                    $line2 = $2;
                    # additional execution description (block end/other probe)
                    if ($line == $line2) {
                        $gOrig_source_line = $source_line;
                    } else {
                        # only one block end execution description => source line is printed
                        $gOrig_source_line = "";
                        $print_source_line = 1;
                    }
                } elsif (length $gOrig_source_line > 0) {
                    # additional block end execution description => source line is printed
                    $source_line = $gOrig_source_line;
                    $gOrig_source_line = "";
                    $print_source_line = 1;
                }
            }
        }

        # additional block end execution description or source not found at ctc2html time or
        # option --disable-sources => description not printed,
        # source line containing one or more block end is printed
        if (defined $source_line and defined $print_source_line) {
            $gOrig_source_line2 =~ s/}//g;
            if (length $gOrig_source_line2 == 0) {
                $sourcestyle = "lineplain";
            } else {
                $gOrig_source_line2 = "";
            }
            print PROFILE <<"END";
<tr><td class="profile" colspan="2"></td><td class="profile_line">$line</td><td><span class="$sourcestyle">$source_line</span></td></tr>
END
        }

        # set current execution mode
        if (defined $gLine_coverage) {
            $gExepassed = $exepassed_pending;
        }
    }
    elsif (/^([\d ]{10})([ ^v])([\d ]{10})([ ^v])(-| ) {0,5}(\d+)(\s*)(.+)/) {
        # execution description begins
        my ($start, $tdiff, $end, $fdiff, $flag, $line, $indent, $descr) = ($1, $2, $3, $4, $5, $6, $7, $8);
        my $indent_multi = substr($indent, 1);
        my $mcdc_flag = undef;
        my $omo = undef;
        my $omo_tr = undef;
        my $descrcol = undef;
        my $tfcols = undef;
        my $linecol = undef;
        my $additional_block_end = undef;
        my $indent_untested = "";
        my $descr_untested = "";
        my $function_end = undef;
        my $sourcestyle_hit = undef;
        my @color = ();

        if (defined $gPendingLine) {
            print PROFILE $gPendingLine;
            undef $gPendingLine;
        }

        if ($flag eq "-") {
            $gNumUntestedProbes++;
        } else {
            undef $flag;
        }

        # additional block end line, statement/line coverage not available
        if ($line == $gPrev_line) {
            if ($descr eq "}" && length $indent > 1) {
                $additional_block_end = 1;
            }
        }

        $start =~ s/\s//g; # remove spaces
        $end =~ s/\s//g;
        $indent =~ s/\s{1}(\s*)/$1/;
        $indent =~ s/\s/&nbsp;/g;
        $indent_untested = $indent;
        $descr_untested = $descr;
        # }+ }- case n:+ default:+ Label:+, they are stripped off from the last +-
        $descr_untested =~ s/[+-]$//;
        # get structural coverage background color
        @color = getColor($start, $end, $flag, $descr);
        $startcolor = $color[0];
        $endcolor = $color[1];
        $sourcestyle = "lineplain";

        if (defined $gLine_coverage) {
            if (length $start == 0 && length $end == 0) { # no counters
                # additional execution description
                if ($descr =~ /MC\/DC \(cond \d+\): \d+ [+-] \d+/) { # MC/DC (cond 1): 1 + 2
                    $exepassed_pending = $gExepassed;
                } elsif ($descr eq '}') { # function end non-reachable, last catch end of function-try
                    ;
                } else { # do, else, switch
                    if ($gExepassed == 1) {
                        $sourcestyle = "linehit";
                    } else {
                        $sourcestyle = "linenhit";
                    }
                    $exepassed_pending = $gExepassed;
                }
            } # no counters

            elsif (length $start > 0 && length $end > 0) { # 2 counters
                if ($line == $gPrev_line) { # additional execution description
                    if ($descr =~ /COND \(/ or      # condition true/false
                        $descr =~ /ternary-\?:/ or  # ternary expression
                        $descr =~ /expr-andor:/)    # and/or expression
                    {
                        $exepassed_pending = $gExepassed;
                    } elsif ($start == 0 && $end == 0) {
                        ;
                    } elsif ($start == 0 && $end > 0) {
                        ;
                    } else {
                        $exepassed_pending = 1;
                    }
                } else { # first execution description
                    if ($descr =~ /ternary-\?:/ or  # ternary expression
                        $descr =~ /expr-andor:/)    # and/or expression
                    {
                        if ($gExepassed == 1) {
                            $sourcestyle = "linehit";
                        } else {
                            $sourcestyle = "linenhit";
                        }
                        $exepassed_pending = $gExepassed;
                    } elsif ($start == 0 && $end == 0) {
                        $sourcestyle = "linenhit";
                    } elsif ($start == 0 && $end > 0) {
                        $sourcestyle = "linehit";
                    } else {
                        $sourcestyle = "linehit";
                        $exepassed_pending = 1;
                    }
                }
            } # 2 counters

            elsif (length $start > 0 && length $end == 0) { # 1 counter in first column
                if ($line == $gPrev_line) { # additional execution description
                    if ($descr =~ /\d+: [TF&amp;!|_\s()]+/ or  # multicondition true
                        $descr =~ /const-ternary-\?:/)         # const ternary expression
                    {
                        $exepassed_pending = $gExepassed;
                    } elsif ($descr =~ /(break|return|goto|continue|throw|__leave)/) { # break return
                        ;
                    } elsif ($descr =~ /case .+:(\+*)/ or  # case n:+ default:+
                             $descr =~ /default:(\+*)/)
                    {
                        if ($start > 0) {
                            $exepassed_pending = 1;
                        } else {
                            if ($1 eq "+") {
                                $exepassed_pending = 1;
                            }
                        }
                    } elsif ($descr =~ /}([+-])/) { # lambda function end
                        if ($1 eq "+") {
                            $exepassed_pending = 1;
                        }
                        $descr =~ s/(})[+-]/$1/;
                    } elsif ($descr eq '}') { # function end
                        ;
                    } elsif ($start > 0) {
                        $exepassed_pending = 1;
                    }
                } else { # first execution description
                    $sourcestyle = "linehit";
                    if ($descr =~ /const-ternary-\?:/) { # const ternary expression
                        if ($gExepassed == 0) {
                            $sourcestyle = "linenhit";
                        }
                        $exepassed_pending = $gExepassed;
                    } elsif ($descr =~ /(break|return|goto|continue|throw|__leave)/) { # break return
                        if ($start == 0) {
                            $sourcestyle = "linenhit";
                        }
                    } elsif ($descr =~ /case .+:(\+*)/ or  # case n:+ default:+
                             $descr =~ /default:(\+*)/)
                    {
                        if ($start > 0) {
                            $exepassed_pending = 1;
                        } else {
                            if ($1 eq "+") {
                                $exepassed_pending = 1;
                            } else {
                                $sourcestyle = "linenhit";
                            }
                        }
                    } elsif ($descr =~ /}([+-])/) { # lambda function end
                        if ($start == 0) {
                            $sourcestyle = "linenhit";
                        }
                        if ($1 eq "+") {
                            $exepassed_pending = 1;
                        }
                        $descr =~ s/(})[+-]/$1/;
                    } elsif ($descr eq '}') { # function end
                        $function_end = 1;
                        $sourcestyle = "lineplain";
                        if ($start > 0) {
                            $sourcestyle_hit = "linehit";
                        } else {
                            $sourcestyle_hit = "linenhit";
                        }
                    } elsif ($start > 0) {
                        $exepassed_pending = 1;
                    } else {
                        $sourcestyle = "linenhit";
                    }
                }
            } # 1 counter in first column

            else { # 1 counter in second column, multicondition false or const-if (0)
                $sourcestyle = "linehit";
                if ($line == $gPrev_line) { # additional execution description
                    $sourcestyle = "lineplain";
                    if ($descr =~ /\d+: [TF&amp;!|_\s()]+/) { # multicondition false
                        $exepassed_pending = $gExepassed;
                    }
                }
            } # 1 counter in second column
        }

        # additional execution description line may follow with same line number
        $gPrev_line = $line;
        $start = exp_format($start, 6);
        $end = exp_format($end, 6);
        $next_untested_id = $gProfile_untested_id + 1;

        if (defined $flag) {
            $pLine = "<a href=\"$profile_html{$gSource_id}#ut$next_untested_id\" id=\"ut$gProfile_untested_id\">$line</a>";
            $gProfile_untested_id = $next_untested_id;
        } else {
            $pLine = $line;
        }

        if (defined $sources) {
            if ($gSource ne $missing_html) {
                # process source up to first execution description in line with current $gExepassed state
                if ($gProcessing{$gSource} < $line) {
                    $source_line = process_source_file($line, $flag);
                    $gProcessing{$gSource} = $line;
                    if (defined $function_end and length $gOrig_source_line > 1) { # {;}
                        $sourcestyle = $sourcestyle_hit;
                    }
                    $gOrig_source_line = "";
                } elsif (length $gOrig_source_line > 0) {
                    # additional execution description after block end => original source line is printed
                    $source_line = $gOrig_source_line;
                    $gOrig_source_line = "";
                }
            }
        }

        if ($descr =~ /^(\d+): [TF&amp;!|_\s()]+$/) {
            $current_max_multi = $1;
        } elsif ($descr =~ /^MC\/DC \(cond \d+\): \d+ ([+-]) \d+/) {
            $mcdc_flag = $1;
        } else {
            $current_max_multi = 0;
        }

        if (defined $mcdc_flag && defined $mcdc_highlight) { # MC/DC line with highlight
            # MC/DC (cond 1): 1 - 3
            # MC/DC (cond 1): 1 - 4, 2 - 4
            $descr =~ /^MC\/DC \(cond (\d+)\): (\d+) [+-] (\d+)/;
            my $cond_nr = $1;
            my $first = $current_max_multi - ($2 - $cond_nr);
            my $second = $current_max_multi - ($3 - $cond_nr);
            my @multi_pairs = split(/,/, $descr);
            my $multi_pair = "";
            my $omo_multi = "";
            my $idx = 0;
            $omo = "onmouseover=\"highlight(this, $first, $second)\" ".
                   "onmouseout=\"unhighlight(this, $first, $second)\"";
            if (not $#multi_pairs) { # one MC/DC pair
                $omo_tr = $omo;
            } else { # multiple MC/DC pairs
                $omo_multi = $omo;
                $indent_multi =~ s/\s/&nbsp;/g;
                $multi_pair = $indent_multi . $multi_pairs[0];
                $descrcol = "<td><span class=\"profile_descr\" $omo_multi>$multi_pair";
                $descrcol .= ",</span>";

                for ($idx = 1; $idx <= $#multi_pairs; $idx++) {
                    $multi_pairs[$idx] =~ /\s*(\d+) [+-] (\d+)/;
                    $first = $current_max_multi - ($1 - $cond_nr);
                    $second = $current_max_multi - ($2 - $cond_nr);
                    $omo_multi = "onmouseover=\"highlight(this, $first, $second)\" ".
                                 "onmouseout=\"unhighlight(this, $first, $second)\"";
                    $multi_pair = $multi_pairs[$idx];
                    $descrcol .= "<span class=\"profile_descr\" $omo_multi>$multi_pair";
                    $descrcol .= "," unless $idx == $#multi_pairs;
                    $descrcol .= "</span>";
                }
                $descrcol .= "</td>";
            }
        }

        if (not defined $descrcol) {
            $descrcol = "<td><span class=\"profile_descr\">$indent$descr</span></td>";
        }

        if (length $start == 0 && length $end == 0) { # no counters
            if (defined $mcdc_flag && defined $mcdc_highlight) { # MC/DC line with highlight
                # In input profile.txt the MC/DC passed info ( |-) was in
                # FALSE column. When input is ctcdiff-generated, the diff
                # info ( |^|v) is also at FALSE column. To HTML the passed
                # info is shown as ( |^|v)(+|-) roughly at Hits/True column
                # end, and the ^/v are converted to up/down arrows.
                if (defined $omo_tr) { # one MC/DC pair
                    $tfcols = "<td class=\"$startcolor\" colspan=\"2\">".toArrowSingle($mcdc_flag,$fdiff)."</td>"; # -+
                } else { # multiple MC/DC pairs
                    $tfcols = "<td class=\"$startcolor\" colspan=\"2\" $omo>$fdiff$mcdc_flag</td>";
                }
            }
            elsif (defined $mcdc_flag && not defined $mcdc_highlight) { # MC/DC line without highlight
                $tfcols = "<td class=\"$startcolor\" colspan=\"2\">".toArrowSingle($mcdc_flag,$fdiff)."</td>"; # -+
            }
            else { # no MC/DC line
                $tfcols = "<td class=\"$startcolor\" colspan=\"2\"></td>";
            }
        }

        elsif (length $start > 0 && length $end > 0) { # 2 counters
            $tfcols = "<td class=\"$startcolor\">".toArrowSingle($start,$tdiff)."</td><td class=\"$endcolor\">".toArrowSingle($end,$fdiff)."</td>";
        }

        elsif (length $start > 0 && length $end == 0) { # 1 counter in first column
            $tfcols = "<td class=\"$startcolor\">".toArrowSingle($start,$tdiff)."</td><td class=\"$endcolor\"></td>";
        }

        else { # 1 counter in second column, multicondition false or const-if (0)
            $tfcols = "<td class=\"$startcolor\"></td><td class=\"$endcolor\">".toArrowSingle($end,$fdiff)."</td>";
        }

        if (defined $mcdc_flag && defined $mcdc_highligh) { # MC/DC line with highlight
            if (defined $omo_tr) { # one MC/DC pair
                $linecol = "<td class=\"profile_line\">$pLine</td>";
            } else { # multiple MC/DC pairs
                $linecol = "<td class=\"profile_line\" $omo>$pLine</td>";
            }
        } else {
            $linecol = "<td class=\"profile_line\">$pLine</td>";
        }

        # source line is printed
        if (defined $source_line) {
            $gPendingLine = <<"END";
<tr>$tfcols$linecol<td><span class="$sourcestyle">$source_line</span></td></tr>
END
        } else { # additional execution description or
            # source not found at ctc2html time or option --disable-sources
            # => description is printed
            if (defined $mcdc_flag && defined $mcdc_highlight) { # MC/DC line with highlight
                if (defined $omo_tr) { # one MC/DC pair
                    $gPendingLine = <<"END";
<tr $omo_tr>$tfcols$linecol$descrcol</tr>
END
                } else { # multiple MC/DC pairs
                    $gPendingLine = <<"END";
<tr>$tfcols$linecol$descrcol</tr>
END
                }
            } else {
                $gPendingLine = <<"END";
<tr>$tfcols$linecol$descrcol</tr>
END
            }
        }

        # additional block end not printed
        if (defined $additional_block_end) {
            undef $additional_block_end;
            undef $gPendingLine;
        }

        # show untested files and functions at Untested Code page
        $alarm = getAlarmCh($flag);
        unless (defined $light_untested) {
            if (defined $flag) {
                $gUntested_id++;
                $uLine = "<a href=\"$profile_html{$gSource_id}#ut$gUntested_id\" target=\"_top\">$line</a>";
                # function has been called, but some probes are untested
                if (defined $gPending_untested_function) {
                    print UNTESTED $gPending_untested_function;
                    undef $gPending_untested_function;
                    $gInsert_separator = 1;
                }
                print UNTESTED <<"END";
<tr>$tfcols<td class="untested_flag">$alarm</td><td class="profile_line">$uLine</td><td><span class="profile_descr">$indent_untested$descr_untested</span></td></tr>
END
            }
        }

        # set current execution mode
        if (defined $gLine_coverage) {
            $gExepassed = $exepassed_pending;
        }
    }

    elsif (/^\*\*\*TER\s+(\d+) % \((\[.+\]|)\s+(\d+)\/\s*(\d+)\) of FUNCTION (.+)/ 
	) { # MASTER regex
	#( 96[3^ + 93=; 0v]/138)
	#        my $ter_tooltip = "TER $1 % ".toArrow($2,$3,$4);
	my $ter_tooltip = "TER $1 % ($2 $3/$4)";
        my $function = $5;
        my $profile_link = $profile_html{$gSource_id} . "#a$gFunction_id";

        $gTooltip = "<a title=\"" . "Function " . $function . "\n" . $ter_tooltip . " structural, ";

        if (defined $gVerboseIndex) {
            print INDEX_PROFILE <<"END";
<tr><td><span class="indent"></span><a href="$profile_link" class="underline" target="profile" title="$ter_tooltip">$function</a></td></tr>
END
        }

        undef $gPending_untested_function;
        # following line directive may be in outside of function
        $gOutsideFunction = 1;
    }

    elsif (/^\s+(N\.A\. statement)/) { # N.A. statement  (of function)
        $gTooltip .= $1 . "\">";
        $gPendingLine =~ s/(<span .+)(<\/td><\/tr>)/$gTooltip$1<\/a>$2/;
        # print pending probe line other than function probe
        print PROFILE $gPendingLine;
        undef $gPendingLine;
    }
 
    elsif (/^\*\*\*TER\s+(\d+) % \(\s*(\[.+\]|)\s*(\d+)\/\s*(\d+)\) (of FILE) .+/ )
    {
        my ($ter, $one, $two, $diff, $three, $four) = ($1, $1, $3, $2, $4, $5);
        my $flag = undef;
        my $base_name = "";

        if ($gSource ne $missing_html) {
            $gProcessing{$gSource} = 0;
        }

        if (defined $sources) {
            # process the remaining lines outside of function of the source file without line coverage
            if ($gSource ne $missing_html) {
                # set line coverage off
                undef $gLine_coverage;
                process_source_file(-1, $flag);
            }

            # close opened source and header files
            foreach $key (keys %gSource_handle) {
                close $gSource_handle{$key};
            }
        }

        if ($ter < $threshold) {
            $structcolor = "belowb";
        } else {
            $structcolor = "aboveb";
        }
        $base_name = basename($original{$gParent});
        $base_name = utf8it($base_name);
        $ter_file = "$one % ".toArrow($two,$diff,$three)." $four $base_name";
        print PROFILE <<"END";
</tbody>
</table>
<a id="ut$gProfile_untested_id"></a>
<span class="$structcolor">***TER</span><span class="$structcolor">$ter_file</span><br>
END
        unless (defined $light_untested) {
            if ($gNumUntestedProbes > 0) {
                print UNTESTED <<"END";
</tbody>
</table>
<span class="$structcolor">***TER</span><span class="$structcolor">$ter_file</span><br>
END
            }
        }
    }

    elsif (/^\s+(\d+) % \(\s*(\d+)\/\s*(\d+)\) (statement)(.*)/) {
        # 100 % (  0/  0) statement[ (N.A. for 2 functions)]  (of function or file)
        my ($ter, $one, $two, $three, $four, $five) = ($1, $1, $2, $3, $4, $5);
        my $file_ter_stmt = "";
        my $key = "";

        if (defined $gPendingLine) { # statement of function
            $gTooltip .= "$one % ($two/$three) $four" . "\">";
            $gPendingLine =~ s/(<span .+)(<\/td><\/tr>)/$gTooltip$1<\/a>$2/;
            # print pending probe line other than function probe
            print PROFILE $gPendingLine;
            undef $gPendingLine;
        } else { # statement of file
            if (defined $statement_coverage) {
                if ($ter < $stmtthreshold) {
                    $stmtcolor = "belowb";
                } else {
                    $stmtcolor = "aboveb";
                }
                $file_ter_stmt = <<"END";
<span class="terindent"></span><span class="$stmtcolor">$one % ($two/$three) $four$five</span><br><br>
END
            } else {
                $file_ter_stmt = <<"END";
<br>
END
            }
            # print file ter statement line
            print PROFILE $file_ter_stmt;
            unless (defined $light_untested) {
                if ($gNumUntestedProbes > 0) {
                    print UNTESTED $file_ter_stmt;
                }
            }
            printProfileFooter();
            print PROFILE <<"END";
</body>
</html>
END
            close PROFILE;
        }
    }
} # profile_list

##########################################################################
# SUBROUTINE: files_summary
# PURPOSE   : This subroutine builds the files summary and 
#             directory summary of the report.
#             Looks like lines of a full recostructed and sorted
#             temp-profile.txt are inputted here one line at a time.
#             Here the interesting FILE and SUMMARY lines are
#             matched and the mentioned various summary-html page
#             infos are collected.
##########################################################################
sub files_summary
{
    $_ = $_[0];
    my ($structhits, $structhist, $structcolor);
    my ($stmthits, $stmthist, $stmtcolor);
    my ($structter, $stmtter);
    my $ter_stmt = "";
    my $current_dir = "";
    my $previous_dir = "";
    my ($structcolorb, $stmtcolorb);
    my ($structalarm, $stmtalarm);
    my $flag = undef;
    my $colspan = "";
    my $directory_overall = "";

    if (defined $statement_coverage) {
        $colspan = "9";
    } else {
        $colspan = "5";
    }

    if (/^MONITORED .+ FILE : .+/) {
        $current_dir = $original_dir{$gCur_directory};
        $current_dir = utf8it($current_dir);
        # print first directory start
        if ($gPrev_directory eq "") {
            print FILES <<"END";
<tr><td class="dirb" colspan="$colspan"><a id="a$gDir_id"></a>Directory: $current_dir</td></tr>
END
        } elsif ($gPrev_directory ne $gCur_directory) {
            if ($dir_ter_all{$gPrev_directory} > 0) { 
                $structter = $dir_ter_hits{$gPrev_directory}*100/$dir_ter_all{$gPrev_directory};
                $structter = int($structter);
		if (1 || $dir_ter_up{$gPrev_directory} || $dir_ter_down{$gPrev_directory}) {
		    $diff = "[$dir_ter_middle{$gPrev_directory} + $dir_ter_up{$gPrev_directory} - $dir_ter_down{$gPrev_directory}]";
		    $structhits = toArrow($dir_ter_hits{$gPrev_directory},$diff,$dir_ter_all{$gPrev_directory}); 
		} else {
		    $structhits = "($dir_ter_hits{$gPrev_directory}/$dir_ter_all{$gPrev_directory})";
		}
            } else {
                $structter = 100;
                $structhits = "(0/0)";
            }

            if ($structter < $threshold) {
                $flag = "-";
                $structcolor = "below";
                $structcolorb = "belowb";
            } else {
                undef $flag;
                $structcolor = "above";
                $structcolorb = "aboveb";
            }
            $structhist = histogram($structter, 0);
            $structalarm = getAlarmCh($flag);
            # previous directory end
            $previous_dir = $original_dir{$gPrev_directory};
            $previous_dir = utf8it($previous_dir);
            # print previous DIRECTORY OVERALL (in Files Summary)
            if (defined $statement_coverage) {
                if ($dir_ter_stmt_all{$gPrev_directory} > 0) {
                    $stmtter = $dir_ter_stmt_hits{$gPrev_directory}*100/$dir_ter_stmt_all{$gPrev_directory};
                    $stmtter = int($stmtter);
                    $stmthits = "($dir_ter_stmt_hits{$gPrev_directory}/$dir_ter_stmt_all{$gPrev_directory})";
                } else {
                    $stmtter = 100;
                    $stmthits = "(0/0)";
                }

                if ($stmtter < $stmtthreshold) {
                    $flag = "-";
                    $stmtcolor = "below";
                    $stmtcolorb = "belowb";
                } else {
                    undef $flag;
                    $stmtcolor = "above";
                    $stmtcolorb = "aboveb";
                }
                $stmthist = histogram($stmtter, 1);
                $stmtalarm = getAlarmCh($flag);
                $directory_overall = <<"END";
<tr><td class="$structcolorb">$structter %</td><td class="$structcolor">$structalarm</td><td class="$structcolor">$structhits</td><td class="histogram">$structhist</td><td class="$stmtcolorb">$stmtter %</td><td class="$stmtcolor">$stmtalarm</td><td class="$stmtcolor">$stmthits</td><td class="histogram">$stmthist</td><td class="dirb" title="$previous_dir">DIRECTORY OVERALL</td></tr>
END
            } else {
                $directory_overall = <<"END";
<tr><td class="$structcolorb">$structter %</td><td class="$structcolor">$structalarm</td><td class="$structcolor">$structhits</td><td class="histogram">$structhist</td><td class="dirb" title="$previous_dir">DIRECTORY OVERALL</td></tr>
END
            }
            print FILES $directory_overall;
            # print new directory start
            print FILES <<"END";
<tr><td class="separator" colspan="$colspan"></td></tr>
<tr><td class="dirb" colspan="$colspan"><a id="a$gDir_id"></a>Directory: $current_dir</td></tr>
END
        }

        $gPrev_directory = $gCur_directory;
    }


    elsif (/^\*\*\*TER\s+(\d+) % \(\s*(\[.+\]|)\s*(\d+)\/\s*(\d+)\) of FILE (\(compared Fs\) |).+/)
    {
        # ***TER ... of FILE ...
        $gTer_of_file = 1; # state flag, next stm-summary line is for FILE!
        $structter  = $1;
	$structhits = toArrowShort($3,$2,$4);
        my $source_id_link = "";
        my $base_name = "";

        if (defined $fis2pro) {
            # default link to execution profile ($fis2pro=1, --enable-fis2pro=1)
            $source_id_link = $profile_html{$gSource_id};
        } else {
            # --enable-fis2pro=0 (link to functions summary)
            $source_id_link = $gFuncs_html . "#a$gSource_id";
        }

        if ($structter < $threshold) {
            $flag = "-";
            $structcolor = "below";
        } else {
            undef $flag;
            $structcolor = "above";
        }
        $structhist = histogram($structter, 0);
        $structalarm = getAlarmCh($flag);
        $base_name = basename($original{$gParent});
        $base_name = utf8it($base_name);
        $gTer_struct_files = "<td class=\"$structcolor\">$structter %</td>".
                             "<td class=\"$structcolor\">$structalarm</td>".
                             "<td class=\"$structcolor\">$structhits</td>".
                             "<td class=\"histogram\">$structhist</td>";
        $gFile_link_files = "<td><a href=\"$source_id_link\" class=\"underline\">$base_name</a></td>";
    }

    elsif (/^\s+(\d+) % \(\s*(\d+)\/\s*(\d+)\) statement.*/) { # 100 % (  0/  0) statement (N.A. for 2 functions)
        # statement ter-line... FUNCTION or FILE
        if ($gTer_of_file == 1) {
            # similar looking FUNCTION's stm ter line not processed here!
            $gTer_of_file = 0;
            $stmtter  = $1;
            $stmthits = "($2/$3)";

            if (defined $statement_coverage) {
                if ($stmtter < $stmtthreshold) {
                    $flag = "-";
                    $stmtcolor = "below";
                } else {
                    undef $flag;
                    $stmtcolor = "above";
                }
                $stmthist = histogram($stmtter, 1);
                $stmtalarm = getAlarmCh($flag);
                $ter_stmt = "<td class=\"$stmtcolor\">$stmtter %</td>".
                            "<td class=\"$stmtcolor\">$stmtalarm</td>".
                            "<td class=\"$stmtcolor\">$stmthits</td>".
                            "<td class=\"histogram\">$stmthist</td>";
            } else {
                $ter_stmt = "";
            }
            print FILES <<"END";
<tr>$gTer_struct_files$ter_stmt$gFile_link_files</tr>
END
        }
    }

    elsif (/^SUMMARY/) {
        if ($dir_ter_all{$gCur_directory} > 0) { 
            $structter = $dir_ter_hits{$gCur_directory}*100/$dir_ter_all{$gCur_directory};
            $structter = int($structter);
	    if (1 || $dir_ter_up{$gCur_directory} || $dir_ter_up{$gCur_directory}) {
		$diff = "[$dir_ter_middle{$gCur_directory} + $dir_ter_up{$gCur_directory} -$dir_ter_down{$gCur_directory}]";
		$structhits = toArrow($dir_ter_hits{$gCur_directory},$diff,$dir_ter_all{$gCur_directory}); 
	    } else {
		$structhits = "($dir_ter_hits{$gCur_directory}/$dir_ter_all{$gCur_directory})";
	    }	    
        } else {
            $structter = 100;
            $structhits = "(0/0)";
        }

        if ($structter < $threshold) {
            $flag = "-";
            $structcolor = "below";
            $structcolorb = "belowb";
        } else {
            undef $flag;
            $structcolor = "above";
            $structcolorb = "aboveb";
        }
        $structhist = histogram($structter, 0);
        $structalarm = getAlarmCh($flag);
        # last (previous/current) directory end
        $previous_dir = $original_dir{$gCur_directory};
        $previous_dir = utf8it($previous_dir);
        # print last DIRECTORY OVERALL (in Files Summary)
        if (defined $statement_coverage) {
            if ($dir_ter_stmt_all{$gCur_directory} > 0) {
                $stmtter = $dir_ter_stmt_hits{$gCur_directory}*100/$dir_ter_stmt_all{$gCur_directory};
                $stmtter = int($stmtter);
                $stmthits = "($dir_ter_stmt_hits{$gCur_directory}/$dir_ter_stmt_all{$gCur_directory})";
            } else {
                $stmtter = 100;
                $stmthits = "(0/0)";
            }

            if ($stmtter < $stmtthreshold) {
                $flag = "-";
                $stmtcolor = "below";
                $stmtcolorb = "belowb";
            } else {
                undef $flag;
                $stmtcolor = "above";
                $stmtcolorb = "aboveb";
            }
            $stmthist = histogram($stmtter, 1);
            $stmtalarm = getAlarmCh($flag);
            $directory_overall = <<"END";
<tr><td class="$structcolorb">$structter %</td><td class="$structcolor">$structalarm</td><td class="$structcolor">$structhits</td><td class="histogram">$structhist</td><td class="$stmtcolorb">$stmtter %</td><td class="$stmtcolor">$stmtalarm</td><td class="$stmtcolor">$stmthits</td><td class="histogram">$stmthist</td><td class="dirb" title="$previous_dir">DIRECTORY OVERALL</td></tr>
END
        } else {
            $directory_overall = <<"END";
<tr><td class="$structcolorb">$structter %</td><td class="$structcolor">$structalarm</td><td class="$structcolor">$structhits</td><td class="histogram">$structhist</td><td class="dirb" title="$previous_dir">DIRECTORY OVERALL</td></tr>
END
        }
        print FILES $directory_overall;
        # print OVERALL start (in Files Summary)
        print FILES <<"END";
<tr><td class="ruler" colspan="$colspan">&nbsp;</td></tr>
END
    }

    elsif (/^Source files\s+: (.+)/) {
        # start collecting the html-stuff that comes to the end of
        # various directory-summary-html pages
        $gFooter = <<"END";
<table>
<tr><td class="info">Directories</td><td class="info">:</td><td class="info">$numDirectories</td></tr>
<tr><td class="info">Source files</td><td class="info">:</td><td class="info">$1</td></tr>
END
    }

    elsif (/^Headers extracted\s+: (.+)/) {
        $gFooter .= <<"END";
<tr><td class="info">Headers extracted</td><td class="info">:</td><td class="info">$1</td></tr>
END
    }
    
#new in future (what future? 3/2020/op)
    #elsif (/^Functions\s+: (.+)/) {
    #    $gFooter .= <<"END";
#<tr><td class="info">Functions</td><td class="info">:</td><td class="info">$1</td></tr>
#END
    #}
#end in future
    elsif (/^Functions\s+: (.+)/) {
        # Was for some reason in v6.0 masked out! Now need to catch this.
        # Now we know that this is a ctcpost-generated report and the 2
        # TER lines that follow in SUMMARY are of that type.

        $gNextTERs = 1; # normal ctcpost-generated bottom SUMMARY
        
        # Now writing of this info $gFooter here, was few lines below
        # (now commented out). Still don't understand the function
        # counting algorithm...
        if ($numFunctions > 0) {
            $gFooter .= <<"END";
<tr><td class="info">Functions</td><td class="info">:</td><td class="info">$numFunctions</td></tr>
END
        } else {
            $gFooter .= <<"END";
<tr><td class="info">Functions</td><td class="info">:</td><td class="info">$numFunctions2</td></tr>
END
        }
    }
    
    elsif (/^Functions compared\s+: (.+)/) {
        $gNextTERs = 2; # ctcdiff-generated, those TERs follow
        $gFooter .= <<"END";
<tr><td class="info">Functions compared</td><td class="info">:</td><td class="info">$1</td></tr>
END
    }
    
    elsif (/^Functions all\s+: (.+)/) {
        $gNextTERs = 3; # ctcdiff-generated, those TERs follow
        $gFooter .= <<"END";
<tr><td class="info">Functions all</td><td class="info">:</td><td class="info">$1</td></tr>
END
    }
    
    elsif (/^Source lines\s+: (.+)/) {

# old logic triggered "Function : n" writing here??
# In ctcdiff-generated report the Functions info is changed.
#        if ($numFunctions > 0) {
#            $gFooter .= <<"END";
#<tr><td class="info">Functions</td><td class="info">:</td><td class="info">$numFunctions</td></tr>
#END
#        } else {
#            $gFooter .= <<"END";
#<tr><td class="info">Functions</td><td class="info">:</td><td class="info">$numFunctions2</td></tr>
#END
#        }
        $gFooter .= <<"END";
<tr><td class="info">Source lines</td><td class="info">:</td><td class="info">$1</td></tr>
END
    }

    #elsif (/^Measurement points\s+: (.+)/) { # was sometimes...
    #    $gFooter .= <<"END";
#<tr><td class="info">Measurement points</td><td class="info">:</td><td class="info">$1</td></tr>
#END
    #}

    elsif (/^TER\s+: (\d+) % \((\d+)\/(\d+)\) statement(.*)/) { # 100 % (10/10) statement (N.A. for 3 functions)
        # We have a statement TER line in SUMMARY block.
        if ($gNextTERs == 1 || $gNextTERs == 2)
        {
        # 1=>normal profile.txt or 2=> diffed-profile.txt. Take these
        # stm TER numbers to various directory summaries (+colors).

        # using old code, sorry, indentation should be 1 step deeper...
        $stmtter    = $1;
        $stmthits   = "($2/$3)";
        my $overall = "";

        if ($gOverall_structter < $threshold) {
            $flag = "-";
            $structcolor = "below";
            $structcolorb = "belowb";
        } else {
            undef $flag;
            $structcolor = "above";
            $structcolorb = "aboveb";
        }
        $structhist = histogram($gOverall_structter, 0);
        $structalarm = getAlarmCh($flag);

        if (defined $statement_coverage) {
            if ($stmtter < $stmtthreshold) {
                $flag = "-";
                $stmtcolor = "below";
                $stmtcolorb = "belowb";
            } else {
                undef $flag;
                $stmtcolor = "above";
                $stmtcolorb = "aboveb";
            }
            $stmthist = histogram($stmtter, 1);
            $stmtalarm = getAlarmCh($flag);
        }
        # print OVERALL (in Files Summary)
        if (defined $statement_coverage) {
            $overall = <<"END";
<tr><td class="$structcolorb">$gOverall_structter %</td><td class="$structcolor">$structalarm</td><td class="$structcolor">$gOverall_structhits_short</td><td class="histogram">$structhist</td><td class="$stmtcolorb">$stmtter %</td><td class="$stmtcolor">$stmtalarm</td><td class="$stmtcolor">$stmthits</td><td class="histogram">$stmthist</td><td><a href="$overall_html" class="underlineb">OVERALL</a></td></tr>
END
        } else {
            $overall = <<"END";
<tr><td class="$structcolorb">$gOverall_structter %</td><td class="$structcolor">$structalarm</td><td class="$structcolor">$gOverall_structhits_short</td><td class="histogram">$structhist</td><td><a href="$overall_html" class="underlineb">OVERALL</a></td></tr>
END
        }
        print FILES $overall;
        print FILES <<"END";
</tbody>
</table><br>
END
        print DIRECTORY <<"END";
<tr class="sortbottom"><td class="ruler" colspan="$colspan">&nbsp;</td></tr>
END
        # print OVERALL (in Directory Summary)
        if (defined $statement_coverage) {
            $overall = <<"END";
<tr class="sortbottom"><td class="$structcolorb">$gOverall_structter %</td><td class="$structcolor">$structalarm</td><td class="$structcolor">$gOverall_structhits_short</td><td class="histogram">$structhist</td><td class="$stmtcolorb">$stmtter %</td><td class="$stmtcolor">$stmtalarm</td><td class="$stmtcolor">$stmthits</td><td class="histogram">$stmthist</td><td><a href="$overall_html" class="underlineb">OVERALL</a></td></tr>
END
        } else {
            $overall = <<"END";
<tr class="sortbottom"><td class="$structcolorb">$gOverall_structter %</td><td class="$structcolor">$structalarm</td><td class="$structcolor">$gOverall_structhits_short</td><td class="histogram">$structhist</td><td><a href="$overall_html" class="underlineb">OVERALL</a></td></tr>
END
        }
        print DIRECTORY $overall;
        print DIRECTORY <<"END";
</tbody>
</table><br>
END
        # print OVERALL (in Overall Summary)
        if (defined $statement_coverage) {
            $overall = <<"END";
<tr><td class="$structcolorb">$gOverall_structter %</td><td class="$structcolor">$structalarm</td><td class="$structcolor">$gOverall_structhits_short</td><td class="histogram">$structhist</td><td class="$stmtcolorb">$stmtter %</td><td class="$stmtcolor">$stmtalarm</td><td class="$stmtcolor">$stmthits</td><td class="histogram">$stmthist</td><td class="infob">OVERALL</td></tr>
END
        } else {
            $overall = <<"END";
<tr><td class="$structcolorb">$gOverall_structter %</td><td class="$structcolor">$structalarm</td><td class="$structcolor">$gOverall_structhits_short</td><td class="histogram">$structhist</td><td class="infob">OVERALL</td></tr>
END
        }
        print OVERALL $overall;
        print OVERALL <<"END";
</tbody>
</table><br>
END
        # print Directory/Files/Overall Summary footer
        if (defined $statement_coverage) {
            $gFooter .= <<"END";
<tr><td class="info">TER statement</td><td class="info">:</td><td><span class="$stmtcolorb">$stmtter %</span><span class="$stmtcolor">$stmthits$4</span></td></tr>
END
        }       
        } # end of "if ($gNextTERs == 1 || $gNextTERs == 2)"
        
        else {
            # This SUMMARY's stm TER line is of "Functions all".
            # just copy it to various summary html pages (no color etc)
            $gFooter .= <<"END";
<tr><td class="info">TER statement</td><td class="info">:</td><td class="info">$1% \($2/$3\) statement$4</td></tr>
END
            
        } # end of $gNextTERs == 1, 2, 3
        
 
        if ($gNextTERs == 1 || # normal ctcpost/ctcxmlmerge generated
            $gNextTERs == 3) { # ctcdiff generated
            # all good inputs end to prev.handled SUMMARY stm ter line,
            # so close the table and emit the bottom-links...
            $gFooter .= <<"END";
</table><br>
<span class="pages"><a href="$directory_html">Directory Summary</a> | <a href="$files_html">Files Summary</a> | <a href="$funcs_html{1}">Functions Summary</a> | <a href="$untested_html">Untested Code</a> | <a href="$profile_html{1}">Execution Profile</a></span><br><br>
</body>
</html>
END
            print FILES $gFooter;
            print DIRECTORY $gFooter;
            print OVERALL $gFooter;

            close FILES;
            close DIRECTORY;
            close OVERALL;
        }
    }

    elsif (/^TER\s+: (\d+) % \((\[.+\]|)\s*(\d+)\/(\d+)\)(.+)/) { # 59 % (30/51) MC/DC
        # SUMMARY block's structural TER
        if ($gNextTERs == 1 || $gNextTERs == 2) { # Functions [compared]
            # in these cases do proper coloring game etc.
            $gOverall_structter  = $1;
            $gOverall_structhits = toArrow($3,$2,$4);
            # $gOverall_structhits_short = "($3".toArrowShort($3)."/$4)";
	        $gOverall_structhits_short = toArrowShort($3,$2,$4);
	        $gOverall_structhits_short = $gOverall_structhits;
	
            if ($gOverall_structter < $threshold) {
                $structcolor = "below";
                $structcolorb = "belowb";
            } else {
                $structcolor = "above";
                $structcolorb = "aboveb";
            }

            $gFooter .= <<"END";
<tr><td class="info">TER structural</td><td class="info">:</td><td><span class="$structcolorb">$gOverall_structter% </span><span class="$structcolor">$gOverall_structhits$5</span></td></tr>
END
        } else {
            # SUMMARY block's structural TER, Functions all, no color game
            $gFooter .= <<"END";
<tr><td class="info">TER structural</td><td class="info">:</td><td class="info">$1% ($3/$4)$5</td></tr>
END
        }
    }    
} # files_summary

##########################################################################
# SUBROUTINE: functions_summary
# PURPOSE   : This subroutine builds the functions summary.
##########################################################################
sub functions_summary
{
    $_ = $_[0];
    my ($next, $previous);
    my ($structcolor, $structhits, $structhist);
    my ($stmtcolor, $stmthits, $stmthist);
    my ($structter, $stmtter);
    my ($function, $ter_stmt);
    my ($structalarm, $stmtalarm);
    my $flag = undef;
    my $current_dir = "";
    my $colspan = "";

    if (defined $statement_coverage) {
        $colspan = "11";
    } else {
        $colspan = "7";
    }

    if (/^MONITORED (.+) FILE : .+/) {
        my $ter_directory = "";
        my $current_file = "";
        my $base_name = "";

        if (not defined $directory_cur_filecount{$gCur_directory}) {
            $directory_cur_filecount{$gCur_directory} = 1;
            $gIndex_dir_id++;
        } else {
            $directory_cur_filecount{$gCur_directory}++;
        }

        open(FUNCS, ">>$html_dir/$gFuncs_html")
            or die "ctc2html: Cannot append file $html_dir/$gFuncs_html\n";
        # directory start (in Functions Summary)
        if ($directory_cur_filecount{$gCur_directory} == 1) {
            $current_dir = $original_dir{$gCur_directory};
            $current_dir = utf8it($current_dir);

            print FUNCS <<"END";
<span class="infob">Directory:</span><span class="infob">$current_dir</span><br>
END
            print INDEX_FUNCS <<"END";
<tr><td><a href="$gFuncs_html" name="ad$gIndex_dir_id" class="underlineb" target="functions" title="#$gIndex_dir_id">$current_dir</a></td></tr>
END
            if ($dir_ter_all{$gCur_directory} > 0) {
		my $diff='';
                $structter = $dir_ter_hits{$gCur_directory}*100/$dir_ter_all{$gCur_directory};
                $structter = int($structter);
		$diff = "[$dir_ter_middle{$gCur_directory} +$dir_ter_up{$gCur_directory} -$dir_ter_down{$gCur_directory}]";
		#                $structhits = "($dir_ter_hits{$gCur_directory}/$dir_ter_all{$gCur_directory})";
		$structhits = toArrow($dir_ter_hits{$gCur_directory},$diff,$dir_ter_all{$gCur_directory}); 
            } else {
                $structter = 100;
                $structhits = "(0/0)";
            }
            $structhits = "$structter % $structhits";

            if ($structter < $threshold) {
                $structcolor = "below";
            } else {
                $structcolor = "above";
            }
            # print TER of Directory
            if (defined $statement_coverage) {
                if ($dir_ter_stmt_all{$gCur_directory} > 0) {
                    $stmtter = $dir_ter_stmt_hits{$gCur_directory}*100/$dir_ter_stmt_all{$gCur_directory};
                    $stmtter = int($stmtter);
                    $stmthits = "($dir_ter_stmt_hits{$gCur_directory}/$dir_ter_stmt_all{$gCur_directory})";
                } else {
                    $stmtter = 100;
                    $stmthits = "(0/0)";
                }
                $stmthits = "$stmtter % $stmthits";

                if ($stmtter < $stmtthreshold) {
                    $stmtcolor = "below";
                } else {
                    $stmtcolor = "above";
                }
                $ter_directory = <<"END";
<span class="infob">TER:</span><span class="$structcolor">$structhits structural,</span><span class="$stmtcolor">$stmthits statement</span><br><br>
END
            } else {
                $ter_directory = <<"END";
<span class="infob">TER:</span><span class="$structcolor">$structhits structural</span><br><br>
END
            }
            print FUNCS $ter_directory;
        }

        $gFile_ter_struct_procent =~ /^TER\s+(\d+) % \((\[.+\]|)\s*(\d+)\/\s*(\d+)\)/;
        $structter = "TER $1 % ".toArrow($3,$2,$4);
        $current_file = defined $relativepath ? relname($original{$gParent}) : $original{$gParent};
        $current_file = utf8it($current_file);
        $base_name = basename($original{$gParent});
        $base_name = utf8it($base_name);

        # print and make a link from the source file name to the profile listing
        print FUNCS <<"END";
<span class="infob">$gFileType:</span><span class="infob"><a href="$profile_html{$gSource_id}" name="a$gSource_id" target="_top">$current_file</a></span><br>
END
        print INDEX_FUNCS <<"END";
<tr><td><span class="indent"></span><a href="$gFuncs_html#a$gSource_id" name="a$gSource_id" class="underline" target="functions" title="$structter">$base_name</a></td></tr>
END
    }

    elsif (/^INSTRUMENTATION MODE\s+: (.+)/) {
        my $previous_source_id = 0;
        my $next_source_id = 0;
        my $no_previous_link = undef;
        my $no_next_link = undef;
        my $header_funcs = "";

        if ($directory_filecount{$gCur_directory} == $directory_cur_filecount{$gCur_directory}) {
            $no_next_link = 1;
        }

        if ($directory_cur_filecount{$gCur_directory} == 1) {
            $no_previous_link = 1;
        }

        if ($gSource_id == 1) {
            $previous = "<span class=\"info\">To files: Previous | ";
        } else {
            $previous_source_id = $gSource_id - 1;

            if (defined $no_previous_link) {  
                $previous = "<span class=\"info\">To files: Previous | ";
            } else {
                $previous = "<span class=\"info\">To files: ".
                            "<a href=\"$gFuncs_html#a$previous_source_id\">Previous</a> | ";
            }
        }

        if ($gSource_id == $numFiles) {
            $next = "Next</span><br><br>";
        } else {
            $next_source_id = $gSource_id + 1;

            if (defined $no_next_link) {
                $next = "Next</span><br><br>";
            } else {
                $next = "<a href=\"$gFuncs_html#a$next_source_id\">Next</a></span><br><br>";
            }
        }

        print FUNCS <<"END";
<span class="infob">Instrumentation mode:</span><span class="info">$gInstrumentationMode</span>$reduced_to<br>
<span class="infob">TER:</span>$gFile_ter_procent<br>
$previous$next
<table>
<thead>
END
        if (defined $statement_coverage) {
            $header_funcs = <<"END";
<tr><th>TER %</th><th>-</th><th colspan="2">$file_coverage_view</th><th>TER %</th><th>-</th><th colspan="2">statement</th><th>Calls</th><th>Line</th><th>Function</th></tr>
END
        } else {
            $header_funcs = <<"END";
<tr><th>TER %</th><th>-</th><th colspan="2">$file_coverage_view</th><th>Calls</th><th>Line</th><th>Function</th></tr>
END
        }
        print FUNCS $header_funcs;
        print FUNCS <<"END";
</thead>
<tbody>
END
    }

#    elsif (/^\s*(\d+)([\^v]*)\s+(-| ) {0,5}(\d+)\s*FUNCTION (.+)/) {
    elsif (/^\s*(\d+)( |\^|v)(          |    \(new\) |\(changed\) )\s+(-| ) {0,5}(\d+)\s*FUNCTION (.+)/) {
        # a function begins in the profile list
        $gFunc_calls = $1;
	my $arrow = $2;
        $flag = $4;
        $gFunc_line = $5;
        $function = $6;
        my $ter_function = "";

        if ($flag ne "-") {
            undef $flag;
        }

        # There's no '***TER ... of FUNCTION ..." line in the profile listing
        # when function coverage instrumentation. Hence, "simulate" it.
        if ($gInstrumentationMode eq "function" or
            $gInstrumentationMode eq "function+inclusive_timing" or
            $gInstrumentationMode eq "function+exclusive_timing" or
            $gCoverageView eq "Reduced to function coverage")
        {
            if (defined $flag) {
                $structter = 0;        # 0 %
                $structhits = "(0/1)"; # (0/1) (hits/all)
                $structhist = histogram(0, 0); # 0 %
                $structalarm = getAlarmCh($flag);
                $structcolor = "below";
            } else {
                $structter = 100;      # 100 %
                $structhits = "(1/1)"; # (1/1) (hits/all)
                $structhist = histogram(100, 0); # 100 %
                $structalarm = getAlarmCh($flag);
                $structcolor = "above";
            }

            if (defined $statement_coverage) {
                $stmthits = "N.A.";
                $stmthist = histogram(0, 1);
                $ter_function = <<"END";
<tr><td class="$structcolor">$structter %</td><td class="$structcolor">$structalarm</td><td class="$structcolor">$structhits</td><td class="histogram">$structhist</td><td></td><td></td><td class="NAright">$stmthits</td><td class="histogram">$stmthist</td><td class="calls">$gFunc_calls</td><td class="line">$gFunc_line</td><td><a href="$profile_html{$gSource_id}#a$gFunction_id" class="underline" target="_top">$function</a></td></tr>
END
            } else {
                $ter_function = <<"END";
<tr><td class="$structcolor">$structter %</td><td class="$structcolor">$structalarm</td><td class="$structcolor">$structhits</td><td class="histogram">$structhist</td><td class="calls">$gFunc_calls</td><td class="line">$gFunc_line</td><td><a href="$profile_html{$gSource_id}#a$gFunction_id" class="underline" target="_top">$function</a></td></tr>
END
            }
            print FUNCS $ter_function;
        }
    }

    elsif (/^\*\*\*TER\s+(\d+) % \((\[.+\]|)\s*(\d+)\/\s*(\d+)\) of FUNCTION (.+)/)
    {
        $gTer_of_function = 1;
        $structter = $1;
        $structhits = toArrowShort($3,$2,$4);
        $function = $5;
        my $profile_link = "";

        if ($structter < $threshold) {
            $flag = "-";
            $structcolor = "below";
        } else {
            undef $flag;
            $structcolor = "above";
        }
        $structhist = histogram($structter, 0);
        $structalarm = getAlarmCh($flag);
        $profile_link = $profile_html{$gSource_id} . "#a$gFunction_id";
        $gTer_struct = "<td class=\"$structcolor\">$structter %</td>".
                       "<td class=\"$structcolor\">$structalarm</td>".
                       "<td class=\"$structcolor\">$structhits</td>".
                       "<td class=\"histogram\">$structhist</td>";
        $gFunction_link = "<td class=\"calls\">$gFunc_calls</td><td class=\"line\">$gFunc_line</td>".
                          "<td><a href=\"$profile_link\" class=\"underline\" target=\"_top\">$function</a></td>";
    }

    elsif (/^\s+N\.A\. statement/) {
        $gTer_of_function = 0;

        if (defined $statement_coverage) {
            $stmthits = "N.A.";
            $stmthist = histogram(0, 1);
            $ter_stmt = "<td></td><td></td><td class=\"NAleft\">$stmthits</td>".
                        "<td class=\"histogram\">$stmthist</td>";
        } else {
            $ter_stmt = "";
        }
        print FUNCS <<"END";
<tr>$gTer_struct$ter_stmt$gFunction_link</tr>
END
    }

    elsif (/^\*\*\*TER\s+(\d+) % \(\s*(\[.+\]|)\s*(\d+)\/\s*(\d+)\) of FILE .+/) {
        $structter = $1;
        $structhits = toArrowShort($3,$2,$4);
        my $base_name = "";

        if ($structter < $threshold) {
            $flag = "-";
            $structcolor = "below";
            $structcolorb = "belowb";
        } else {
            undef $flag;
            $structcolor = "above";
            $structcolorb = "aboveb";
        }
        $structhist = histogram($structter, 0);
        $structalarm = getAlarmCh($flag);
        $base_name = basename($original{$gParent});
        $base_name = utf8it($base_name);
        $gTer_struct_funcs = "<td class=\"$structcolorb\">$structter %</td>".
                             "<td class=\"$structcolor\">$structalarm</td>".
                             "<td class=\"$structcolor\">$structhits</td>".
                             "<td class=\"histogram\">$structhist</td>";
        $gFile_link_funcs = "<td></td><td></td>".
                            "<td><a href=\"$profile_html{$gSource_id}\" class=\"underlineb\" target=\"_top\">$base_name</a></td>";

        # all source files in directory printed (in Functions Summary)
        if ($directory_filecount{$gCur_directory} == $directory_cur_filecount{$gCur_directory}) {
            $gFuncs_dir_id++;
            # TER of DIRECTORY OVERALL follows
            if ($dir_ter_all{$gCur_directory} > 0) { 
                $structter = $dir_ter_hits{$gCur_directory}*100/$dir_ter_all{$gCur_directory};
                $structter = int($structter);
                $structhits = "($dir_ter_hits{$gCur_directory}/$dir_ter_all{$gCur_directory})";
            } else {
                $structter = 100;
                $structhits = "(0/0)";
            }

            if ($structter < $threshold) {
                $flag = "-";
                $structcolor = "below";
                $structcolorb = "belowb";
            } else {
                undef $flag;
                $structcolor = "above";
                $structcolorb = "aboveb";
            }
            $structhist = histogram($structter, 0);
            $structalarm = getAlarmCh($flag);
            $current_dir = $original_dir{$gCur_directory};
            $current_dir = utf8it($current_dir);
            $gTer_directory_overall = <<"END";
<tr><td class="ruler" colspan="$colspan">&nbsp;</td></tr>
END
            if (defined $statement_coverage) {
                if ($dir_ter_stmt_all{$gCur_directory} > 0) {
                    $stmtter = $dir_ter_stmt_hits{$gCur_directory}*100/$dir_ter_stmt_all{$gCur_directory};
                    $stmtter = int($stmtter);
                    $stmthits = "($dir_ter_stmt_hits{$gCur_directory}/$dir_ter_stmt_all{$gCur_directory})";
                } else {
                    $stmtter = 100;
                    $stmthits = "(0/0)";
                }

                if ($stmtter < $stmtthreshold) {
                    $flag = "-";
                    $stmtcolor = "below";
                    $stmtcolorb = "belowb";
                } else {
                    undef $flag;
                    $stmtcolor = "above";
                    $stmtcolorb = "aboveb";
                }
                $stmthist = histogram($stmtter, 1);
                $stmtalarm = getAlarmCh($flag);
                $gTer_directory_overall .= <<"END";
<tr><td class="$structcolorb">$structter %</td><td class="$structcolor">$structalarm</td><td class="$structcolor">$structhits</td><td class="histogram">$structhist</td><td class="$stmtcolorb">$stmtter %</td><td class="$stmtcolor">$stmtalarm</td><td class="$stmtcolor">$stmthits</td><td class="histogram">$stmthist</td><td></td><td></td><td class="dirb" title="$current_dir">DIRECTORY OVERALL</td></tr>
END
            } else {
                $gTer_directory_overall .= <<"END";
<tr><td class="$structcolorb">$structter %</td><td class="$structcolor">$structalarm</td><td class="$structcolor">$structhits</td><td class="histogram">$structhist</td><td></td><td></td><td class="dirb" title="$current_dir">DIRECTORY OVERALL</td></tr>
END
            }
            $gTer_directory_overall .= <<"END";
</tbody>
</table><br>
END
        }
    }

    elsif (/^\s+(\d+) % \(\s*(\d+)\/\s*(\d+)\) statement.*/) { # 100 % (  0/  0) statement (N.A. for 2 functions)
        $stmtter  = $1;
        $stmthits = "($2/$3)";

        if (defined $statement_coverage) {
            if ($stmtter < $stmtthreshold) {
                $flag = "-";
                $stmtcolor = "below";
                $stmtcolorb = "belowb";
            } else {
                undef $flag;
                $stmtcolor = "above";
                $stmtcolorb = "aboveb";
            }
            $stmthist = histogram($stmtter, 1);
            $stmtalarm = getAlarmCh($flag);
        }
        # print TER of Function
        if ($gTer_of_function == 1) {
            $gTer_of_function = 0;
            if (defined $statement_coverage) {
                $ter_stmt = "<td class=\"$stmtcolor\">$stmtter %</td>".
                            "<td class=\"$stmtcolor\">$stmtalarm</td>".
                            "<td class=\"$stmtcolor\">$stmthits</td>".
                            "<td class=\"histogram\">$stmthist</td>";
            } else {
                $ter_stmt = "";
            }
            print FUNCS <<"END";
<tr>$gTer_struct$ter_stmt$gFunction_link</tr>
END
        } else {
            # print TER of File
            if (defined $statement_coverage) {
                $ter_stmt = "<td class=\"$stmtcolorb\">$stmtter %</td>". # bold
                            "<td class=\"$stmtcolor\">$stmtalarm</td>".
                            "<td class=\"$stmtcolor\">$stmthits</td>".
                            "<td class=\"histogram\">$stmthist</td>";
            } else {
                $ter_stmt = "";
            }

            print FUNCS <<"END";
<tr><td class="ruler" colspan="$colspan">&nbsp;</td></tr>
<tr>$gTer_struct_funcs$ter_stmt$gFile_link_funcs</tr>
END
            # all source files in directory printed
            if ($gTer_directory_overall ne "") {
                print FUNCS $gTer_directory_overall;
                $gTer_directory_overall = "";
                printFuncsFooter();
                print FUNCS <<"END";
</body>
</html>
END
            } else {
                # source file in directory follows next
                print FUNCS <<"END";
</tbody>
</table><br>
END
            }
            close FUNCS;
        }
    }
} # functions_summary

##########################################################################
# SUBROUTINE: directory_summary
# PURPOSE   : generates the directory summary report
##########################################################################
sub directory_summary
{
    my $dir_id = 0;
    my ($current_dir, $key);
    my ($structter, $stmtter);
    my ($structcolor, $structhist, $structhits);
    my ($stmtcolor, $stmthist, $stmthits);
    my ($structalarm, $stmtalarm);
    my $flag = undef;
    my $ter_directory = "";

    foreach $key (sort keys %directory_filecount) {
        $dir_id++;
        $directory_ordinal{$key} = $dir_id;

        if ($dir_ter_all{$key} > 0) {
	    my $diff='';
            $structter = $dir_ter_hits{$key}*100/$dir_ter_all{$key};
            $structter = int($structter);
	    $diff = "[$dir_ter_middle{$key} +$dir_ter_up{$key} -$dir_ter_down{$key}]";
	    $structhits = toArrow($dir_ter_hits{$key},$diff,$dir_ter_all{$key}); 
        } else {
            $structter = 100;
            $structhits = "(0/0)";
        }

        if ($structter < $threshold) {
            $flag = "-";
            $structcolor = "below";
        } else {
            undef $flag;
            $structcolor = "above";
        }
        $structhist = histogram($structter, 0);
        $structalarm = getAlarmCh($flag);
        $current_dir = $original_dir{$key};
        $current_dir = utf8it($current_dir);

        if (defined $statement_coverage) {
            if ($dir_ter_stmt_all{$key} > 0) { 
                $stmtter = $dir_ter_stmt_hits{$key}*100/$dir_ter_stmt_all{$key};
                $stmtter = int($stmtter);
                $stmthits = "($dir_ter_stmt_hits{$key}/$dir_ter_stmt_all{$key})";
            } else {
                $stmtter = 100;
                $stmthits = "(0/0)";
            }

            if ($stmtter < $stmtthreshold) {
                $flag = "-";
                $stmtcolor = "below";
            } else {
                undef $flag;
                $stmtcolor = "above";
            }
            $stmthist = histogram($stmtter, 1);
            $stmtalarm = getAlarmCh($flag);
            $ter_directory = <<"END";
<tr><td class="$structcolor">$structter %</td><td class="$structcolor">$structalarm</td><td class="$structcolor">$structhits</td><td class="histogram">$structhist</td><td class="$stmtcolor">$stmtter %</td><td class="$stmtcolor">$stmtalarm</td><td class="$stmtcolor">$stmthits</td><td class="histogram">$stmthist</td><td><a href="$files_html#a$dir_id" class="underline">$current_dir</a></td></tr>
END
        } else {
            $ter_directory = <<"END";
<tr><td class="$structcolor">$structter %</td><td class="$structcolor">$structalarm</td><td class="$structcolor">$structhits</td><td class="histogram">$structhist</td><td><a href="$files_html#a$dir_id" class="underline">$current_dir</a></td></tr>
END
        }
        print DIRECTORY $ter_directory;
    }
} # directory_summary

##########################################################################
# SUBROUTINE: process_source_file
# PURPOSE   : This subroutine builds an HTML version of a source code
#             file and combines it with profile listing data.
#
#             A source file is processed up to $to_probe_line at a time. 
#
#             If $to_probe_line equals -1, the rest of the source file is
#             printed to the HTML file (source file is to be closed later).
##########################################################################
sub process_source_file
{
    my $to_probe_line = $_[0];
    my $flag = $_[1];
    my $handle = "";
    my $source_line = "";
    my $descr = "";
    my $descr2 = "";
    my $descr3 = "";
    my $descr4 = "";
    my $comment = "";
    my $sourcestyle = "";
    my $line_num = 0;
    my $cur_pos = 0;
    my $preproc_start = 0;
    my $preproc_close = 0;
    my $key = 0;
    my $lcc = undef;
    my %lines = ();

    $handle = $gSource_handle{$gSource};
    $cur_pos = tell($handle); # required

    while (<$handle>) { # $. contains line number
        s/\015?\012$//;
        $source_line = $_;
        $cur_pos = $.;
        $line_num = $cur_pos;
        if(/.*(\r|\n).*/) {
            warning("Mixed line endings detected in file '$gSource' at line $line_num or above!\n")
        }

        $descr = "";
        $descr2 = "";
        $descr3 = "";
        $descr4 = "";
        $comment = "";
        undef $lcc;
        setSyntaxMode($cur_pos, $to_probe_line, $flag);
        # remove one line comments, spaces from original source line
        setOrigSourceLine($source_line);
        $source_line = replaceEntity($source_line);

        if (defined $gComment_pending)
        { # multiline C comment pending in syntax highlighting
            if ($source_line =~ /(.*\*\/)(.*)/) {
                $comment = $1;
                $source_line = $2;
                $comment = getSyntaxHighlight($comment);
                $sourcestyle = getStyle(); # (no)hit after comment
                $source_line = getSyntaxHighlight($source_line);
                $source_line = $comment . $source_line;
            } else {
                $sourcestyle = "lineplain"; # plain inside comment
                $source_line = getSyntaxHighlight($source_line);
            }
        }

        elsif (defined $gPreproc_lcc)
        { # line-continuation char again in preprocessor conditional
            if ($source_line =~ /\\$/) {
                $lcc = 1;
            } else {
                if ($source_line =~ /(.*)(\/\*.*)/ or
                    $source_line =~ /(.*)(\/\/.*)/)
                {
                    $source_line = $1;
                    $comment = $2;
                }
            }
            if (defined $gOutsideFunction) {
                $sourcestyle = getCondStyle(1);
            } else {
                $sourcestyle = getCondStyle(2);
            }
            $source_line = getSyntaxHighlight($source_line);
            if (not defined $lcc) {
                undef $gPreproc_lcc;
                $comment = getSyntaxHighlight($comment); # after preprocessor conditional
                $source_line .= $comment;
            }
        }

        elsif (defined $gPragma_lcc)
        { # line-continuation char again in #pragma CTC ANNOTATION
            if ($source_line =~ /\\$/) {
                $lcc = 1;
                if (not defined $visibility) {
                    $source_line =~ s/\\$//; # remove lcc
                }
            } else {
                if ($source_line =~ /(.*)(\/\*.*)/ or
                    $source_line =~ /(.*)(\/\/.*)/)
                {
                    $source_line = $1;
                    $comment = $2;
                }
            }
            $sourcestyle = "annotation";
            $source_line = nbspit($source_line);
            if (not defined $lcc) {
                undef $gPragma_lcc;
                $comment = getSyntaxHighlight($comment);
                $source_line .= $comment;
            }
        }

        elsif (defined $gDefine_lcc)
        { # line-continuation char again in #define macro
            if ($source_line =~ /\\$/) {
                $lcc = 1;
            } else {
                if ($source_line =~ /(.*)(\/\*.*)/ or
                    $source_line =~ /(.*)(\/\/.*)/)
                {
                    $source_line = $1;
                    $comment = $2;
                }
            }
            $sourcestyle = "lineplain";
            $source_line = getSyntaxHighlight($source_line);
            if (not defined $lcc) {
                undef $gDefine_lcc;
                $comment = getSyntaxHighlight($comment); # after #define macro
                $source_line .= $comment;
            }
        }

        elsif (defined $gString_lcc)
        { # line-continuation char again in string
            if ($source_line =~ /\\$/ and not $source_line =~ /\"/) {
                $lcc = 1;
            } else {
                if ($source_line =~ /(.*)(\/\*.*)/ or
                    $source_line =~ /(.*)(\/\/.*)/)
                {
                    $source_line = $1;
                    $comment = $2;
                }
                $source_line =~ /(.*")(.*)/;
                $source_line = $1; # string end
                $descr = $2; # after string end or between string end and comment
            }
            $sourcestyle = getStyle();
            $source_line = getSyntaxHighlight($source_line);
            if (not defined $lcc) {
                undef $gString_lcc;
                $descr = getSyntaxHighlight($descr); # after string end
                $comment = getSyntaxHighlight($comment); # comment
                $source_line .= $descr . $comment;
            }
        }

        elsif (defined $gComment_lcc)
        { # line-continuation char again in C++ comment
            if ($source_line =~ /\\$/) {
                $lcc = 1;
            }
            $sourcestyle = "lineplain";
            $source_line = getSyntaxHighlight($source_line);
            if (not defined $lcc) {
                undef $gComment_lcc;
            }
        }

        elsif ($source_line =~ /^\s*\/\*/)
        { # C comment
            $sourcestyle = "lineplain";
            $source_line = getSyntaxHighlight($source_line);
        }

        elsif ($source_line =~ /^\s*\/\/.*\\$/)
        { # line-continuation char in C++ comment
            $sourcestyle = "lineplain";
            $source_line = getSyntaxHighlight($source_line);
            $gComment_lcc = 1;
        }

        elsif ($source_line =~ /^\s*\/\//)
        { # C++ comment
            $sourcestyle = "lineplain";
            $source_line = getSyntaxHighlight($source_line);
        }

        elsif ($source_line =~ /^\s*#\s*if\s*\(*\s*0\s*\)*/)
        { # #if 0  i.e. preprocessor conditional
            $preproc_start = $cur_pos;
            $preproc_close = getClosingLine($source_line, $gSource, $preproc_start);
            $preproc_close--;
            %lines = getPreprocLines($gSource, $preproc_start, $preproc_close);
            for ($key = $preproc_start; $key <= $preproc_close; $key++) {
                $source_line = $lines{$key};
                $line_num = $key;
                if ($key == $preproc_start) {
                    if ($source_line =~ /(.*)(\/\*.*)/ or
                        $source_line =~ /(.*)(\/\/.*)/)
                    {
                        $source_line = $1;
                        $comment = $2;
                    }
                    $sourcestyle = getCondStyle(0);
                    $source_line = getSyntaxHighlight($source_line);
                    $comment = getSyntaxHighlight($comment);
                    $source_line .= $comment;
                } else {
                    $sourcestyle = "disable_code";
                    $source_line = nbspit($source_line);
                }
                # replace UTF8 encoding sequence with HTML notation
                $source_line = utf8it($source_line);
                # just print the source line
                print PROFILE <<"END";
<tr><td class="profile" colspan="2"></td><td class="profile_line">$line_num</td><td><span class="$sourcestyle">$source_line</span></td></tr>
END
            }
            $handle = getHandle($handle, $preproc_start, $preproc_close);
            next;
        }

        elsif ($source_line =~ /^\s*#\s*if/ or $source_line =~ /^\s*#\s*elif/ or
               $source_line =~ /^\s*#\s*else/)
        { # #if .../ #ifdef .../ #ifndef .../#elif .../ #else  i.e. preprocessor conditional
            $preproc_start = $cur_pos;
            if (defined $gOutsideFunction) {
                # line-continuation char in preprocessor conditional outside of function
                if ($source_line =~ /\\$/) {
                    $lcc = 1;
                } else {
                    if ($source_line =~ /(.*)(\/\*.*)/ or
                        $source_line =~ /(.*)(\/\/.*)/)
                    {
                        $source_line = $1;
                        $comment = $2;
                    }
                }
                $sourcestyle = getCondStyle(1);
                $source_line = getSyntaxHighlight($source_line);
                if (not defined $lcc) {
                    $comment = getSyntaxHighlight($comment);
                    $source_line .= $comment;
                } else {
                    $gPreproc_lcc = 1;
                }
            }
            else {
                $preproc_close = getClosingLine($source_line, $gSource, $preproc_start);
                $preproc_close--;
                # yes we have probe inside preprocessor block, enable syntax and line coverage
                if ($to_probe_line <= $preproc_close)
                { # line-continuation char in preprocessor conditional inside of function
                    if ($source_line =~ /\\$/) {
                        $lcc = 1;
                    } else {
                        if ($source_line =~ /(.*)(\/\*.*)/ or
                            $source_line =~ /(.*)(\/\/.*)/)
                        {
                            $source_line = $1;
                            $comment = $2;
                        }
                    }
                    $sourcestyle = getCondStyle(2);
                    $source_line = getSyntaxHighlight($source_line);
                    if (not defined $lcc) {
                        $comment = getSyntaxHighlight($comment);
                        $source_line .= $comment;
                    } else {
                        $gPreproc_lcc = 1;
                    }
                } else { # no probe inside preprocessor block, disable code
                    %lines = getPreprocLines($gSource, $preproc_start, $preproc_close);
                    for ($key = $preproc_start; $key <= $preproc_close; $key++) {
                        $source_line = $lines{$key};
                        $line_num = $key;
                        undef $lcc;
                        if (defined $gPreproc_lcc)
                        { # line-continuation char again in preprocessor conditional inside of function
                            if ($source_line =~ /\\$/) {
                                $lcc = 1;
                            } else {
                                if ($source_line =~ /(.*)(\/\*.*)/ or
                                    $source_line =~ /(.*)(\/\/.*)/)
                                {
                                    $source_line = $1;
                                    $comment = $2;
                                }
                            }
                            $sourcestyle = getCondStyle(2);
                            $source_line = getSyntaxHighlight($source_line);
                            if (not defined $lcc) {
                                undef $gPreproc_lcc;
                                $comment = getSyntaxHighlight($comment); # after preprocessor conditional
                                $source_line .= $comment;
                            }
                        }
                        elsif ($key == $preproc_start)
                        { # line-continuation char in preprocessor conditional inside of function
                            if ($source_line =~ /\\$/) {
                                $lcc = 1;
                            } else {
                                if ($source_line =~ /(.*)(\/\*.*)/ or
                                    $source_line =~ /(.*)(\/\/.*)/)
                                {
                                    $source_line = $1;
                                    $comment = $2;
                                }
                            }
                            $sourcestyle = getCondStyle(2);
                            $source_line = getSyntaxHighlight($source_line);
                            if (not defined $lcc) {
                                $comment = getSyntaxHighlight($comment);
                                $source_line .= $comment;
                            } else {
                                $gPreproc_lcc = 1;
                            }
                        }
                        else {
                            $sourcestyle = "disable_code";
                            $source_line = nbspit($source_line);
                        }
                        # replace UTF8 encoding sequence with HTML notation
                        $source_line = utf8it($source_line);
                        # just print the source line
                        print PROFILE <<"END";
<tr><td class="profile" colspan="2"></td><td class="profile_line">$line_num</td><td><span class="$sourcestyle">$source_line</span></td></tr>
END
                    }
                    $handle = getHandle($handle, $preproc_start, $preproc_close);
                    next;
                }
            }
        }

        elsif ($source_line =~ /^\s*#\s*endif/)
        { # #endif
            if ($source_line =~ /(.*)(\/\*.*)/ or
                $source_line =~ /(.*)(\/\/.*)/)
            {
                $source_line = $1;
                $comment = $2;
            }
            $sourcestyle = getCondStyle(0);
            $source_line = getSyntaxHighlight($source_line);
            $comment = getSyntaxHighlight($comment);
            $source_line .= $comment;
        }

        elsif ($source_line =~ /^(\s*#\s*pragma\s+CTC\s+ANNOTATION\s*)(.*\\)$/)
        { # line-continuation char in #pragma CTC ANNOTATION descr  //...
            $source_line = $1;
            $descr = $2;
            if (not defined $visibility) {
                $descr =~ s/\\$//; # remove lcc
            }
            $sourcestyle = "lineplain";
            $source_line = getSyntaxHighlight($source_line);
            $descr = nbspit($descr);
            $gPragma_lcc = 1;
            if (not defined $visibility) { # hide #pragma CTC ANNOTATION
                $source_line = "<span class=\"hidden\">$source_line</span>";
            }
            $descr = "<span class=\"annotation\">$descr</span>";
            $source_line .= $descr; # #pragma CTC ANNOTATION descr //...
        }

        elsif ($source_line =~ /^(\s*#\s*pragma\s+CTC\s+ANNOTATION\s*)(.*)/)
        { # #pragma CTC ANNOTATION descr  //...
            $source_line = $1;
            $descr = $2;
            if ($descr =~ /(.*)(\/\*.*)/ or
                $descr =~ /(.*)(\/\/.*)/)
            {
                $descr = $1;
                $comment = $2;
            }
            $sourcestyle = "lineplain";
            $source_line = getSyntaxHighlight($source_line);
            $descr = nbspit($descr);
            $comment = getSyntaxHighlight($comment);
            if (not defined $visibility) { # hide #pragma CTC ANNOTATION
                $source_line = "<span class=\"hidden\">$source_line</span>";
            }
            $descr = "<span class=\"annotation\">$descr$comment</span>";
            $source_line .= $descr; # #pragma CTC ANNOTATION descr //...
        }

        elsif ($source_line =~ /^(\s*#\s*pragma\s+CTC\s+COUNT\s*)(.*)/)
        { # #pragma CTC COUNT descr  //...
            $source_line = $1;
            $descr = $2;
            if ($descr =~ /(.*)(\/\*.*)/ or
                $descr =~ /(.*)(\/\/.*)/)
            {
                $descr = $1;
                $comment = $2;
            }
            $sourcestyle = "lineplain";
            $source_line = getSyntaxHighlight($source_line);
            $descr = nbspit($descr);
            $comment = getSyntaxHighlight($comment);
            if (not defined $visibility) { # hide #pragma CTC COUNT
                $source_line = "<span class=\"hidden\">$source_line</span>";
            }
            $descr = "<span class=\"count\">$descr$comment</span>";
            $source_line .= $descr; # #pragma CTC COUNT descr //...
        }

        elsif ($source_line =~ /^\s*#\s*define.*\\$/)
        { # line-continuation char in #define macro, #define PII \ 
            $sourcestyle = "lineplain";
            $source_line = getSyntaxHighlight($source_line);
            $gDefine_lcc = 1;
        }

        elsif ($source_line =~ /^\s*#\s*define/)
        { # #define PI 3.14 /* comment */
            if ($source_line =~ /(.*)(\/\*.*)/ or
                $source_line =~ /(.*)(\/\/.*)/)
            {
                $source_line = $1;
                $comment = $2;
            }
            $sourcestyle = "lineplain";
            $source_line = getSyntaxHighlight($source_line);
            $comment = getSyntaxHighlight($comment);
            $source_line .= $comment;
        }

        elsif ($source_line =~ /^\s*#/)
        { # #include <iostream>  /* comment */
            if ($source_line =~ /(.*)(\/\*.*)/ or
                $source_line =~ /(.*)(\/\/.*)/)
            {
                $source_line = $1;
                $comment = $2;
            }
            $sourcestyle = "lineplain";
            $source_line = getSyntaxHighlight($source_line);
            $comment = getSyntaxHighlight($comment);
            $source_line .= $comment;
        }

        elsif ($source_line =~ /^(.*?)(["'].*?["'])(.*?)(["'].*?["'])(.*?)(\/\*.*)/ or
               $source_line =~ /^(.*?)(["'].*?["'])(.*?)(["'].*?["'])(.*?)(\/\/.*)/)
        { #strValue.replace(strValue.rfind(">"), 3, " />"); //name="A&lt;T&gt;::A" />
            $source_line = $1;
            $descr = $2;
            $descr2 = $3;
            $descr3 = $4;
            $descr4 = $5;
            $comment = $6;
            $sourcestyle = getStyle();
            $source_line = getSyntaxHighlight($source_line);
            $descr = getSyntaxHighlight($descr);
            $descr2 = getSyntaxHighlight($descr2);
            $descr3 = getSyntaxHighlight($descr3);
            $descr4 = getSyntaxHighlight($descr4);
            $comment = getSyntaxHighlight($comment);
            $source_line .= $descr . $descr2 . $descr3 . $descr4 . $comment;
        }

        elsif ($source_line =~ /^(.*?)(".*?")(.*?)(".*?\/\*.*?")(.*)/ or
               $source_line =~ /^(.*?)(".*?")(.*?)(".*?\/\/.*?")(.*)/)
        { # lookalike C comment in string, printf("%s, %s\n", "/*dir", "foo:docName");
          # lookalike C++ comment in string, printf("%s, %s\n", "http://docu.namespace", "foo:docName");
            $source_line = $1;
            $descr = $2;
            $descr2 = $3;
            $descr3 = $4;
            $comment = $5;
            $sourcestyle = getStyle();
            $source_line = getSyntaxHighlight($source_line);
            $descr = getSyntaxHighlight($descr);
            $descr2 = getSyntaxHighlight($descr2);
            $descr3 = getSyntaxHighlight($descr3);
            $comment = getSyntaxHighlight($comment);
            $source_line .= $descr . $descr2 . $descr3 . $comment;
        }

        elsif ($source_line =~ /^(.*?)(["'].*?["'])(.*?)(\/\*.*["'].*)/ or 
               $source_line =~ /^(.*?)(["'].*?["'])(.*?)(\/\/.*["'].*)/)
        { # char lex[]="INF"; // " 3.402823466E39";
          # foo('C'); //E11 rejected so can't get to textNode1
            $source_line = $1;
            $descr = $2;
            $descr2 = $3;
            $comment = $4;
            $sourcestyle = getStyle();
            $source_line = getSyntaxHighlight($source_line);
            $descr = getSyntaxHighlight($descr);
            $descr2 = getSyntaxHighlight($descr2);
            $comment = getSyntaxHighlight($comment);
            $source_line .= $descr . $descr2 . $comment;
        }

        elsif ($source_line =~ /^(.*?)(".*?\/\*.*?")(.*)/ or
               $source_line =~ /^(.*?)(".*?\/\/.*?")(.*)/)
        { # lookalike C comment in string, TEST_VALID_XPATH("/*dir", 1, __LINE__);
          # lookalike C++ comment in string, printf("http://docu.namespace\n");
            $source_line = $1;
            $descr = $2;
            $comment = $3;
            $sourcestyle = getStyle();
            $source_line = getSyntaxHighlight($source_line);
            $descr = getSyntaxHighlight($descr);
            $comment = getSyntaxHighlight($comment);
            $source_line .= $descr . $comment;
        }

        elsif ($source_line =~ /^(.*?)(".*")(.*\\)$/)
        { # Guard case "line-continuation char in string"
            $sourcestyle = getStyle();
            $source_part1 = getSyntaxHighlight($1);
            $string_literal = getSyntaxHighlight($2);
            $source_part2 = getSyntaxHighlight($3);
            $source_line = $source_part1 . $string_literal . $source_part2;
        }

        elsif ($source_line =~ /^(.*?)(\/\*.*["'].*)/)
        { # Guard following case if there is a comment before the string literal
            $source_line = $1;
            $comment = $2;
            $sourcestyle = getStyle();
            $source_line = getSyntaxHighlight($source_line);
            $comment = getSyntaxHighlight($comment);
            $source_line .= $comment;
        }

        elsif ($source_line =~ /^(.*?)(".*\\)$/)
        { # line-continuation char in string, foo("huuhaa \ 
            $source_line = $1;
            $descr = $2;
            $sourcestyle = getStyle();
            $source_line = getSyntaxHighlight($source_line);
            $gString_lcc = 1;
            $descr = getSyntaxHighlight($descr);
            $source_line .= $descr;
        }

        elsif ($source_line =~ /^(.*?)(["'].*)(\/\*.*)/ or
               $source_line =~ /^(.*?)(["'].*)(\/\/.*)/)
        { # foo("kukkuu"); //comment or foo2('A'); /*com*/
            $source_line = $1;
            $descr = $2;
            $comment = $3;
            $sourcestyle = getStyle();
            $source_line = getSyntaxHighlight($source_line);
            $descr = getSyntaxHighlight($descr);
            $comment = getSyntaxHighlight($comment);
            $source_line .= $descr . $comment;
        }

        elsif ($source_line =~ /^(.*?)(\/\*.*["'].*)/ or 
               $source_line =~ /^(.*?)(\/\/.*["'].*)/)
        { # foo3(); //E11 rejected so can't get to textNode1
            $source_line = $1;
            $comment = $2;
            $sourcestyle = getStyle();
            $source_line = getSyntaxHighlight($source_line);
            $comment = getSyntaxHighlight($comment);
            $source_line .= $comment;
        }

        elsif ($source_line =~ /^(.*?)(["'].*)/)
        { # foo("kukkuu"); or foo2('A');
            $source_line = $1;
            $descr = $2;
            $sourcestyle = getStyle();
            $source_line = getSyntaxHighlight($source_line);
            $descr = getSyntaxHighlight($descr);
            $source_line .= $descr;
        }

        elsif ($source_line =~ /(.+)(\/\*.*)/ or
               $source_line =~ /(.+)(\/\/.*)/)
        { # foo(1); //comment or int main( /* com123 */ )
            $source_line = $1;
            $comment = $2;
            $sourcestyle = getStyle(); # (no)hit before comment
            $source_line = getSyntaxHighlight($source_line);
            $comment = getSyntaxHighlight($comment);
            $source_line .= $comment;
        }

        else {
            $sourcestyle = getStyle();
            $source_line = getSyntaxHighlight($source_line);
        }
        # replace UTF8 encoding sequence with HTML notation
        $source_line = utf8it($source_line);
        # return source line that corresponds profile listing probe line
        if ($cur_pos == $to_probe_line) {
            return $source_line;
        }
        # just print the source line
        print PROFILE <<"END";
<tr><td class="profile" colspan="2"></td><td class="profile_line">$line_num</td><td><span class="$sourcestyle">$source_line</span></td></tr>
END
    }
}

##########################################################################
# SUBROUTINE: setSyntaxMode
# PURPOSE   : set syntax mode on or off depending on --enable-syntax_highlight
##########################################################################
sub setSyntaxMode
{
    my ($cur_pos, $to_probe_line, $flag) = @_;

    if (defined $flag) {
        if (defined $syntax_highlight) {
            if ($cur_pos <= $to_probe_line or $to_probe_line == -1) {
                $gSyntaxmode = 1;
            } else {
                undef $gSyntaxmode;
            }
        } else {
            undef $gSyntaxmode;
        }
    } else {
        if (defined $syntax_highlight) {
            $gSyntaxmode = 1;
        } else {
            undef $gSyntaxmode;
        }
    }
}
        
##########################################################################
# SUBROUTINE: getSyntaxHighlight
# PURPOSE   : get syntax highlighted source line if syntax mode is on
##########################################################################
sub getSyntaxHighlight
{
    my ($source_line) = @_;

    if (defined $gSyntaxmode) {
        $source_line = syntaxHighLight($source_line);
    } else {
        $source_line = nbspit($source_line);
    }
    return $source_line;
}

##########################################################################
# SUBROUTINE: syntaxHighLight
# PURPOSE   : syntax highlights source line
##########################################################################
sub syntaxHighLight
{
    my ($line) = @_;
    my $source_line = "";
    my $pos = 0;
    my $comment = "";

    if ($line =~ /^(\t+)/) {
        $source_line .= '&nbsp;&nbsp;&nbsp;' x length $1;
        $line = substr($line, length $1);
    }

    if ($line =~ /^(\s+)/) {
        $source_line .= '&nbsp;' x length $1;
        $line = substr($line, length $1);
    }

    if (defined $gDefine_lcc or defined $gPreproc_lcc)
    {
        $source_line .= $s{PREP} . nbspit($line) . $e{PREP};
        $line = "";
    }
    elsif (defined $gString_lcc)
    {
        $source_line .= $s{STRING} . nbspit($line) . $e{STRING};
        $line = "";
    }
    elsif (defined $gComment_lcc)
    {
        $source_line .= $s{COMMENT} . nbspit($line) . $e{COMMENT};
        $line = "";
    }

    while (length $line > 0) {
        if (defined $gComment_pending) {
            $pos = index($line, "*/"); # C comment end index
            if ($pos >= 0) {
                undef $gComment_pending;
                undef $gComment_line;
            }
            $source_line .= $s{COMMENT} . nbspit($line) . $e{COMMENT};
            $line = "";
        }

        if ($line ne "") {
            if ($line =~ /^(\s+)/) {
                $source_line .= '&nbsp;' x length $1;
                $line = substr($line, length $1);
            }

            elsif ($line =~ /^\/\*/) { # C comment start
                $pos = index($line, "*/"); # C comment end index
                if ($pos >= 0) {
                    $comment = substr($line, 0, $pos + 2);
                    $source_line .= $s{COMMENT} . nbspit($comment) . $e{COMMENT};
                    $line = substr($line, $pos + 2);
                } else {
                    $gComment_pending = 1;
                    $source_line .= $s{COMMENT} . nbspit($line) . $e{COMMENT};
                    $line = "";
                }
            }

            elsif ($line =~ /^\/\//) { # C++ comment
                $source_line .= $s{COMMENT} . nbspit($line) . $e{COMMENT};
                $line = "";
            }

            elsif ($line =~ /^#/)
            { # preprocessor directive, #pragma CTC COUNT/ANNOTATION
                $source_line .= $s{PREP} . nbspit($line) . $e{PREP};
                $line = "";
            }

            elsif ($line =~ /^(".*?\/\*.*?")/ or $line =~ /^(".*?\/\/.*?")/)
            { # lookalike C comment in string, "/*dir"
              # lookalike C++ comment in string, "http://docu.namespace"
                $source_line .= $s{STRING} . nbspit($1) . $e{STRING};
                $line = "";
            }

            elsif ($line =~ /^("[^"]*")/ or $line =~ /^('[^']*')/)
            {
                my $one = $1;
                $one = fixEscape($line) if $one =~ /\\["']$/;
                $source_line .= $s{STRING} . nbspit($one) . $e{STRING};
                $line = substr($line, length $one);
            }

            elsif ($line =~ /^\b(new|int|long|float|double|bool|if|do|while|
                            for|else|continue|default|case|goto|return|
                            switch|break|static|const|enum|extern|register|
                            short|signed|auto|unsigned|char|void|typedef|
                            volatile|wchar_t|char16_t|char32_t|class|typename|
                            struct|union|sizeof|asm|delete|namespace|operator|
                            friend|inline|virtual|private|protected|public|
                            template|this|alignas|alignof|constexpr|decltype|
                            noexcept|nullptr|static_assert|thread_local|
                            explicit|true|false|mutable|typeid|using|throw|
                            try|catch|const_cast|dynamic_cast|
                            reinterpret_cast|static_cast)\b/x)
            {
                $source_line .= $s{KEYW} . nbspit($1) . $e{KEYW};
                $line = substr($line, length $1);
            }

            elsif ($line =~ /(.+?)["']/)
            { # foo('A'); or printf("%s, %s, %d\n", 
                $source_line .= nbspit($1);
                $line = substr($line, length $1);
            }
            
            elsif ($line =~ /(.+?)\b(new|int|long|float|double|bool|if|do|while|
                            for|else|continue|default|case|goto|return|
                            switch|break|static|const|enum|extern|register|
                            short|signed|auto|unsigned|char|void|typedef|
                            volatile|wchar_t|char16_t|char32_t|class|typename|
                            struct|union|sizeof|asm|delete|namespace|operator|
                            friend|inline|virtual|private|protected|public|
                            template|this|alignas|alignof|constexpr|decltype|
                            noexcept|nullptr|static_assert|thread_local|
                            explicit|true|false|mutable|typeid|using|throw|
                            try|catch|const_cast|dynamic_cast|
                            reinterpret_cast|static_cast)\b/x)
            { # foo2(const long val);
                $source_line .= nbspit($1);
                $line = substr($line, length $1);
            }

            elsif ($line =~ /(.+?)\/\*/ or $line =~ /(.+?)\/\//)
            {
                $source_line .= nbspit($1);
                $line = substr($line, length $1);
            }

            else {
                $source_line .= nbspit($line);
                $line = "";
            }
        }
    }
    return $source_line;
}

##########################################################################
# SUBROUTINE: getStyle
# PURPOSE   : get stylesheet of line coverage execution painting color
##########################################################################
sub getStyle
{
    my $style = "lineplain";

    if (not defined $gComment_pending) {
        if (defined $gLine_coverage) {
            if (paintLine()) {
                if ($gExepassed == 1) {
                    $style = "linehit";
                } else {
                    $style = "linenhit";
                }
            }
        }
    }
    return $style;
}

##########################################################################
# SUBROUTINE: getCondStyle
# PURPOSE   : get stylesheet of preprocessor conditional background color
##########################################################################
sub getCondStyle
{
    my ($both) = @_; # 0=inside or outside of function, 1=outside, 2=inside
    my $style = "lineplain";

    if ($both == 0) {
        if (defined $gOutsideFunction) {
            if (defined $ppcond_highlight) {
                $style = "ppcond";
            }
        } else {
            if (defined $ppcond_highlight) {
                $style = "ppcondin";
            }
        }
    }
    elsif ($both == 1) {
        if (defined $ppcond_highlight) {
            $style = "ppcond";
        }
    }
    else {
        if (defined $ppcond_highlight) {
            $style = "ppcondin";
        }
    }
    return $style;
}

##########################################################################
# SUBROUTINE: getClosingLine
# PURPOSE   : get on what line is the next matching one
##########################################################################
sub getClosingLine
{
    my ($source_line, $file_name, $preproc_start) = @_;
    my $preproc_close = 0;

    if ($source_line =~ /^\s*#\s*if/) {
        $preproc_close = getStopper($file_name, $preproc_start, "#elif", "#else", "#endif");
    } elsif ($source_line =~ /^\s*#\s*elif/) {
        $preproc_close = getStopper($file_name, $preproc_start, "#elif", "#else", "#endif");
    } else { # the #else case
        $preproc_close = getStopper($file_name, $preproc_start, "#--", "#--", "#endif");
    }
    return $preproc_close;
}

##########################################################################
# SUBROUTINE: getStopper
# PURPOSE   : Open given source code file (=current code file). Scan it
#             to given line (=which has starting #if/#elif/#else). Scan
#             onwards upto its matching/next #elif/#else/#endif (the
#             stopper is given in parameter). Tell on what line the
#             stopper is. Close the file.
##########################################################################
sub getStopper
{
    my ($file_name, # source code file
        $line,      # first read over file begin upto here
        $stop1,     # read upto this (nonsense or "#elif")
        $stop2,     # or to this (nonsense or "#else")
        $stop3      # or to this (nonsense or "#endif")
        ) = @_;
    my $cur_pos = 0;
    my $nesting = 0; # not yet skipping any inner #if...#endif

    # open source file for input
    $file_name = stripSecondCopySuffix($file_name);

    open(SOURCE, "<" . openName($file_name))
        or die "ctc2html: Cannot open file $file_name\n";
    $cur_pos = tell(SOURCE); # required
    while (<SOURCE>) {
        if ($. == $line) {
            last;
        }
    }

    # match to the block stopper
    while (<SOURCE>) {
        if ($. == $line + 1 and
            ($_ =~ /^\s*#\s*elif/ or $_ =~ /^\s*#\s*else/ or $_ =~ /^\s*#\s*endif/))
        {
            $line = $.;
            last;
        }
        # possible nested #if...#endif
        if ($_ =~ /^\s*#\s*if/) {
            $nesting = 1;
            while (<SOURCE>) {
                # read those inner lines upto matching #endif
                if ($_ =~ /^\s*#\s*if/) { # but inner #if...#endif started
                    $nesting++;
                }
                elsif ($_ =~ /^\s*#\s*endif/ and $nesting > 1) {
                    $nesting--;
                }
                elsif ($_ =~ /^\s*#\s*endif/ and $nesting <= 1) {
                    $nesting = 0;
                    last; # from the inner while()
                }
            }
        }
        elsif ($_ =~ /^\s*#\s*elif/ and $stop1 eq "#elif") {
            $line = $.;
            last;
        }
        elsif ($_ =~ /^\s*#\s*else/ and $stop2 eq "#else") {
            $line = $.;
            last;
        }
        elsif ($_ =~ /^\s*#\s*endif/ and $stop3 eq "#endif") {
            $line = $.;
            last;
        }
    }
    close SOURCE;
    return $line;
}

##########################################################################
# SUBROUTINE: getPreprocLines
# PURPOSE   : get source lines in preprocessor block up to closing line
##########################################################################
sub getPreprocLines
{
    my ($file_name, $line, $to_line) = @_;
    my $cur_pos = 0;
    my $source_line = "";
    my %lines = ();

    # open source file for input
    $file_name = stripSecondCopySuffix($file_name);

    open(SOURCE, "<". openName($file_name))
        or die "ctc2html: Cannot open file $file_name\n";
    $cur_pos = tell(SOURCE); # required
    while(<SOURCE>) {
        s/\015?\012$//;
        $source_line = $_;
        $source_line = replaceEntity($source_line);
        if ($. < $line) {
            next;
        }
        elsif ($. < $to_line) {
            $lines{$.} = $source_line;
        }
        elsif ($. == $to_line) {
            $lines{$.} = $source_line;
            last; 
        }
    }
    close SOURCE;
    return %lines;
}

##########################################################################
# SUBROUTINE: getHandle
# PURPOSE   : get handle of last disabled code line in preprocessor block
##########################################################################
sub getHandle
{
    my ($handle, $preproc_start, $preproc_close) = @_;

    if ($preproc_start != $preproc_close) {
        while (<$handle>) {
            if ($. == $preproc_close) {
                last;
            }
        }
    }
    return $handle;
}

##########################################################################
# SUBROUTINE: setOrigSourceLine
# PURPOSE   : get rid of unwanted parts of original source line
##########################################################################
sub setOrigSourceLine
{
    $gOrig_source_line = $_[0];
    $gOrig_source_line =~ s/\s//g; # remove all space
    $gOrig_source_line =~ s/^#\S*//; # remove preproc directive, not valid in probe line

    # one line C comment, eat away all instances
    if ($gOrig_source_line =~ /\/\*\S*?\*\//) { # /*com1*//*com2*/
        $gOrig_source_line =~ s/\/\*\S*?\*\///g;
    }
    elsif ($gOrig_source_line =~ /"\S*?\/\*\S*?"/) { # TEST_VALID_XPATH("/*dir",1,__LINE__);
        # lookalike C comment start in string, eat away all instances
        $gOrig_source_line =~ s/"\S*?\/\*\S*?"//g;
    }
    elsif ($gOrig_source_line =~ /\/\*\S*?\/\//) { # /*com1//com2
        # lookalike C++ comment inside multiline C comment start, do not eat away
        ;
    }
    elsif ($gOrig_source_line =~ /\/\/\S*\*\//) { # //com1*/
        # lookalike C++ comment inside multiline C comment end, do not eat away
        ;
    }
    elsif ($gOrig_source_line =~ /\/\/\S*/) { # //com12
        # C++ comment or lookalike C++ comment inside multiline C comment, eat away
        $gOrig_source_line =~ s/\/\/\S*//;
    }
    else {
        ;
    }

    # copy of cleaned source line used for multiple block end in line
    $gOrig_source_line2 = $gOrig_source_line;
}

##########################################################################
# SUBROUTINE: paintLine
# PURPOSE   : find out if in source line (not probe) line coverage color
#             painting is to be used
#             1 = use line coverage color, 0 = not use line coverage color
##########################################################################
sub paintLine
{
    my $line = $gOrig_source_line;

    if ($line =~ /\/\*/) { # multiline C comment start, eat away
        $line =~ s/^(\S*)\/\*\S*/$1/;
        $gComment_line = 1;
    }
    elsif ($line =~ /\*\//) { # multiline C comment end, eat away
        $line =~ s/\S*\*\/(\S*)$/$1/;
        undef $gComment_line;
    }
    elsif (defined $gComment_line) { # multiline C comment continues, eat away
        $line =~ s/\S//g;
    }
    $line =~ s/{//; # remove function/block start
    $line =~ s/}//; # remove block end

    if (length $line == 0) {
        return 0; # comment, empty line
    }
    return 1; # statement, multiline statement, macro
}

##########################################################################
# SUBROUTINE: getColor
# PURPOSE   : This subroutine gets structural coverage background color
##########################################################################
sub getColor
{
    my ($start, $end, $flag, $descr) = @_;
    my @color = ();

    if (length $start == 0 && length $end == 0) { # no counters
        $color[0] = "profile"; # start color
        $color[1] = "profile"; # end color

        if ($descr =~ /MC\/DC \(cond \d+\): \d+ [+-] \d+/) { # MC/DC (cond 1): 1 + 2
            if (defined $flag) {
                $color[0] = "mcdc_fail";
                $color[1] = "mcdc_fail"; 
            } else {
                $color[0] = "mcdc_pass";
                $color[1] = "mcdc_pass";
            }
        }
    } # no counters

    elsif (length $start > 0 && length $end > 0) { # 2 counters
        if ($start == 0) {
            $color[0] = "tcolnhit";
        } else {
            $color[0] = "profile";
        }
      
        if ($end == 0) {
            $color[1] = "fcolnhit";
        } else {
            $color[1] = "profile";
        }
    } # 2 counters

    elsif (length $start > 0 && length $end == 0) { # 1 counter in first column
        if ($start == 0) {
            $color[0] = "tcolnhit";
            $color[1] = "profile";
        } else {
            $color[0] = "profile";
            $color[1] = "profile";
        }

        if ($descr =~ /\d+: [TF&amp;!|_\s()]+/) { # multicondition true
            if ($gCoverageView eq "Reduced to MC/DC coverage") { # and MC/DC
                $color[0] = "profile";
                $color[1] = "profile";
            }
        }
    } # 1 counter in first column

    else { # 1 counter in second column
        if ($end == 0) {
            $color[0] = "profile";
            $color[1] = "fcolnhit";
        } else {
            $color[0] = "profile";
            $color[1] = "profile";
        }

        if ($descr =~ /\d+: [TF&amp;!|_\s()]+/) { # multicondition false
            if ($gCoverageView eq "Reduced to MC/DC coverage") { # and MC/DC
                $color[0] = "profile";
                $color[1] = "profile";
            }
        }
    } # 1 counter in second column
    return @color;
}

##########################################################################
# SUBROUTINE: printHeaderInfo
# PURPOSE   : print dates of the monitor and the original profile listing
#             to FILES, DIRECTORY and OVERALL
##########################################################################
sub printHeaderInfo
{
    $_ = $_[0];

    if (/(Symbol file\(s\)) used\s+: (.+)/) {
        my $symbol_line = <<"END";
<table>
<tr><td class="info">$1</td><td class="info">:</td><td class="info">$2</td></tr>
END
        print FILES $symbol_line;
        print DIRECTORY $symbol_line;
        print OVERALL $symbol_line;
    }

    elsif (/(Input profile 1 \s+): (.+)/) {

        my $symbol_line = <<"END";
<table>
<tr><td class="info">$1</td><td class="info">:</td><td class="info">$2</td></tr>
END
        print FILES $symbol_line;
        print DIRECTORY $symbol_line;
        print OVERALL $symbol_line;
	$input_profile1 = $2;
	$input_profile1 =~s/\s*\([^)]+\)$//;
    }
    elsif (/(Input profile \d+ \s+): (.+)/) {
        my $symbol_line = <<"END";
<tr><td class="info">$1</td><td class="info">:</td><td class="info">$2</td></tr>
END
        print FILES $symbol_line;
        print DIRECTORY $symbol_line;
        print OVERALL $symbol_line;
	$input_profile2 = $2;
	$input_profile2 =~s/\s*\([^)]+\)$//;

	if (basename($input_profile1) ne basename($input_profile2)) {
	    $input_profile1 = basename($input_profile1);
	    $input_profile2 = basename($input_profile2);
	}
	$input_profile1 =~s/v/&#118;/g;
	$input_profile2 =~s/v/&#118;/g;
	$input_profile1 =~ s/\.[^.]+$//;
	$input_profile2 =~ s/\.[^.]+$//;
    }

    elsif (/(Data file\(s\)) used\s+: (.+)/) {
        my $data_line = <<"END";
<tr><td class="info">$1</td><td class="info">:</td><td class="info">$2</td></tr>
END
        if ($#list >= 0) {
            printEllipsis(@list);
            @list = ();
        }
        print FILES $data_line;
        print DIRECTORY $data_line;
        print OVERALL $data_line;
    }

    elsif (/(XML file\(s\)) used\s+: (.+)/) {
        my $xml_line = <<"END";
<table>
<tr><td class="info">$1</td><td class="info">:</td><td class="info">$2</td></tr>
END
        if ($#list >= 0) {
            printEllipsis(@list);
            @list = ();
        }
        print FILES $xml_line;
        print DIRECTORY $xml_line;
        print OVERALL $xml_line;
   }

   elsif (/^\s+: (.+)/) {
        # Additional symbol, data or (Un)Chosen file name
        my $additional_line = <<"END";
<tr><td class="info"></td><td class="info">:</td><td class="info">$1</td></tr>
END
        if ($files_reduction) {
            push(@list, $additional_line);
        } else {
            print FILES $additional_line;
            print DIRECTORY $additional_line;
        }
        print OVERALL $additional_line;
    }

    elsif (/(Chosen file\(s\))\s+: (.+)/) {
        my $chosen_line = <<"END";
<tr><td class="info">$1</td><td class="info">:</td><td class="info">$2</td></tr>
END
        if ($#list >= 0) {
            printEllipsis(@list);
            @list = ();
        }
        print FILES $chosen_line;
        print DIRECTORY $chosen_line;
        print OVERALL $chosen_line;
    }

    elsif (/(Unchosen file\(s\))\s+: (.+)/) {
        my $unchosen_line = <<"END";
<tr><td class="info">$1</td><td class="info">:</td><td class="info">$2</td></tr>
END
        if ($#list >= 0) {
            printEllipsis(@list);
            @list = ();
        }
        print FILES $unchosen_line;
        print DIRECTORY $unchosen_line;
        print OVERALL $unchosen_line;
    }

    elsif (/(Listing produced at)\s+: (.+)/) {
        my $listing_line = <<"END";
<tr><td class="info">$1</td><td class="info">:</td><td class="info">$2</td></tr>
END
        if ($#list >= 0) {
            printEllipsis(@list);
            @list = ();
        }
        print FILES $listing_line;
        print DIRECTORY $listing_line;
        print OVERALL $listing_line;
    }

    elsif (/(Coverage view)\s+: (.+)/) {
        $gCoverageView = $2;
        my $coverage_line = <<"END";
<tr><td class="info">$1</td><td class="info">:</td><td class="info">$gCoverageView</td></tr>
<tr><td class="separator" colspan="3"></td></tr>
END
        my $versions = <<"END";
<tr><td class="info">ctcpost version</td><td class="info">:</td><td class="info">$gVctcpost</td></tr>
<tr><td class="info">ctcxmlmerge version</td><td class="info">:</td><td class="info">$gVctcxmlmerge</td></tr>
<tr><td class="info">ctc2html version</td><td class="info">:</td><td class="info">$gVctc2html</td></tr>
<tr><td class="separator" colspan="3"></td></tr>
END
        my $html_input = <<"END";
<tr><td class="info">Input listing</td><td class="info">:</td><td class="info">$input_file</td></tr>
<tr><td class="info">HTML generated at</td><td class="info">:</td><td class="info">$time_stamp</td></tr>
<tr><td class="info">ctc2html options</td><td class="info">:</td><td class="info">$html_options</td></tr>
<tr><td class="info">Structural threshold</td><td class="info">:</td><td class="infob">$threshold %</td></tr>
END
        if (defined $statement_coverage) {
            $html_input .= <<"END";
<tr><td class="info">Statement threshold</td><td class="info">:</td><td class="infob">$stmtthreshold %</td></tr>
END
        }
        $html_input .= <<"END";
</table><br>
END
        print FILES $coverage_line . $html_input;
        print DIRECTORY $coverage_line . $html_input;
        print OVERALL $coverage_line . $versions . $html_input;
    }

    elsif (/^\*\*\* \d+ verbose notice\(s\) written to stderr/) {
        my $notice_line = <<"END";
<span class="info">$_</span><br><br>
END
        print FILES $notice_line;
        print DIRECTORY $notice_line;
        print OVERALL $notice_line;
    }

    elsif (/^MONITORED/) {
        $lookahead = $_;
        # print coverage table headers
        print FILES <<"END";
<table>
<thead>
END
        if (defined $statement_coverage) {
            print FILES <<"END";
<tr><th>TER %</th><th>-</th><th colspan="2">$shown_coverage_views</th><th>TER %</th><th>-</th><th colspan="2">statement</th><th>File</th></tr>
END
        } else {
            print FILES <<"END";
<tr><th>TER %</th><th>-</th><th colspan="2">$shown_coverage_views</th><th>File</th></tr>
END
        }
        print FILES <<"END";
</thead>
<tbody>
END
        my $click = "";
        if (defined $javascript) {
            $click = "(Click on header to sort)";
        }

        print DIRECTORY <<"END";
<span class="info">$click</span>
<table class="sortable">
<thead>
END
        if (defined $javascript) {
            if (defined $statement_coverage) {
                print DIRECTORY <<"END";
<tr><th class="sorttable_numeric"><a title="Click to sort">TER %</a></th><th class="sorttable_nosort">-</th><th class="sorttable_nosort" colspan="2">$shown_coverage_views</th><th class="sorttable_numeric"><a title="Click to sort">TER %</a></th><th class="sorttable_nosort">-</th><th class="sorttable_nosort" colspan="2">statement</th><th class="sorttable_alpha"><a title="Click to sort">Directory</a></th></tr>
END
            } else {
                print DIRECTORY <<"END";
<tr><th class="sorttable_numeric"><a title="Click to sort">TER %</a></th><th class="sorttable_nosort">-</th><th class="sorttable_nosort" colspan="2">$shown_coverage_views</th><th class="sorttable_alpha"><a title="Click to sort">Directory</a></th></tr>
END
            }
        } else {
            if (defined $statement_coverage) {
                print DIRECTORY <<"END";
<tr><th>TER %</th><th>-</th><th colspan="2">$shown_coverage_views</th><th>TER %</th><th>-</th><th colspan="2">statement</th><th>Directory</th></tr>
END
            } else {
                print DIRECTORY <<"END";
<tr><th>TER %</th><th>-</th><th colspan="2">$shown_coverage_views</th><th>Directory</th></tr>
END
            }
        }
        print DIRECTORY <<"END";
</thead>
<tbody>
END
        print OVERALL <<"END";
<table>
<thead>
END
        if (defined $statement_coverage) {
            print OVERALL <<"END";
<tr><th>TER %</th><th>-</th><th colspan="2">$shown_coverage_views</th><th>TER %</th><th>-</th><th colspan="2">statement</th><th></th></tr>
END
        } else {
            print OVERALL <<"END";
<tr><th>TER %</th><th>-</th><th colspan="2">$shown_coverage_views</th><th></th></tr>
END
        }
        print OVERALL <<"END";
</thead>
<tbody>
END
        last;
    }

    elsif (/^SUMMARY/) { # no monitored source files, print summary footer
        while ($current_line = getLine()) {
            $current_line =~ s/\015?\012$//;
            printSummary($current_line);
        }
        last;
    }
}

##########################################################################
# SUBROUTINE: printSummary
# PURPOSE   : This subroutine builds the empty files, directory
#             and overall summary footer of the report.
##########################################################################
sub printSummary
{
    $_ = $_[0];

    if (/^Source files\s+: (.+)/) {
        $gFooter = <<"END";
<span class="pages"><a href="$overall_html">Overall Summary</a></span><br><br>
<table>
<tr><td class="info">Directories</td><td class="info">:</td><td class="info">$numDirectories</td></tr>
<tr><td class="info">Source files</td><td class="info">:</td><td class="info">$1</td></tr>
END
    }

    elsif (/^Headers extracted\s+: (.+)/) {
        $gFooter .= <<"END";
<tr><td class="info">Headers extracted</td><td class="info">:</td><td class="info">$1</td></tr>
END
    }
#new in future
    #elsif (/^Functions\s+: (.+)/) {
    #    $gFooter .= <<"END";
#<tr><td class="info">Functions</td><td class="info">:</td><td class="info">$1</td></tr>
#END
    #}
#end in future
    elsif (/^Source lines\s+: (.+)/) {
        $gFooter .= <<"END";
<tr><td class="info">Functions</td><td class="info">:</td><td class="info">$numFunctions2</td></tr>
END
        $gFooter .= <<"END";
<tr><td class="info">Source lines</td><td class="info">:</td><td class="info">$1</td></tr>
END
    }

    #elsif (/^Measurement points\s+: (.+)/) {
    #    $gFooter .= <<"END";
#<tr><td class="info">Measurement points</td><td class="info">:</td><td class="info">$1</td></tr>
#END
    #}

    elsif (/^TER\s+: (\d+) % \((\d+)\/(\d+)\) statement/) { # 100 % (0/0) statement
        if (defined $statement_coverage) {
            $gFooter .= <<"END";
<tr><td class="info">TER statement</td><td class="info">:</td><td><span class="aboveb">$1 %</span><span class="above"> ($2/$3)</span></td></tr>
END
        }

        if ($gNextTERs == 1 || # normal profile input's SUMMART stm TER
            $gNextTERs == 3) { # ctcdiffed input, at "Functions all"
            # Now the input is fully processed (versus this were ctcdiffed
            # input's "Functions compared" and "functions all" woudl follow)

            $gFooter .= <<"END";
</table><br>
<span class="pages"><a href="$directory_html">Directory Summary</a> | <a href="$files_html">Files Summary</a> | Functions Summary | Untested Code | Execution Profile</span><br><br>
</body>
</html>
END
            print FILES $gFooter;
            print DIRECTORY $gFooter;
            print OVERALL $gFooter;

            close FILES;
            close DIRECTORY;
            close OVERALL;
        }
    }

    elsif (/^TER\s+: (\d+) % \((\d+)\/(\d+)\)/) { # 100 % (0/0)
        $gFooter .= <<"END";
<tr><td class="info">TER structural</td><td class="info">:</td><td><span class="aboveb">$1 %</span><span class="above"> ($2/$3)</span></td></tr>
END
    }
} # printSummary

###########################################################################
# SUBROUTINE: printEllipsis
# PURPOSE   : Writes out remaining Symbol/Data/(Un)chosen files
#             If the then seen amount is > $max_files, it writes
#             then effectively only $min_files, then a reference
#             to indexO.html
# PARAMETERS: @list -- list of files
##########################################################################
sub printEllipsis 
{
    my (@list) = @_;
    my $overall_link = "";

    if (@list < $max_files) { # 3
        foreach (@list) {
            print FILES $_;
            print DIRECTORY $_;
        }
    } else {
        for (0..($min_files - 2)) { # 3
            print FILES $list[$_];
            print DIRECTORY $list[$_];
        }
        $overall_link = <<"END";
<tr><td class="info"></td><td class="info">:</td><td><a href="$overall_html">&hellip; etc.</a></td></tr>
END
        print FILES $overall_link;
        print DIRECTORY $overall_link;
    }
}

##########################################################################
# SUBROUTINE: calculateDirectoryTer
# PURPOSE   : Need to calculate per-directory TER structural
#             Need to calculate per-directory TER statement
##########################################################################
sub calculateDirectoryTer
{
    my ($dir, $key);

    # calculate per-directory TER structural here
    foreach $key (keys %source_ter) {
        $dir = dirname($key);
        if (not defined $dir_ter_all{$dir}) {
            $dir_ter_hits{$dir} = 0;
            $dir_ter_all{$dir} = 0;
	    $dir_ter_up{$dir} = 0;
	    $dir_ter_down{$dir} = 0;
        }
        $source_ter{$key} =~ /(\[.+\]|)\s*(\d+)\/\s*(\d+)/;
        $dir_ter_hits{$dir} += $2;
        $dir_ter_all{$dir} += $3;
	my ($middle, $up, $down) = updown($1);
        $dir_ter_up{$dir} += $up;
	$dir_ter_middle{$dir} += $middle;
	$dir_ter_down{$dir} += $down;
    }

    # calculate per-directory TER statement here
    foreach $key (keys %source_ter_stmt) {
        $dir = dirname($key);
        if (not defined $dir_ter_stmt_all{$dir}) {
            $dir_ter_stmt_hits{$dir} = 0;
            $dir_ter_stmt_all{$dir} = 0;
        }
        $source_ter_stmt{$key} =~ /(\d+)\/\s*(\d+)/;
        $dir_ter_stmt_hits{$dir} += $1;
        $dir_ter_stmt_all{$dir} += $2;
    }
}


##########################################################################
# SUBROUTINE: setTimeStamp
# PURPOSE   : sets the time stamp when execution starts
##########################################################################
sub setTimeStamp
{
    $year = 1900 + $year;
    $time_stamp = 
        (Sun,Mon,Tue,Wed,Thu,Fri,Sat)[$weekday] . " " .
        (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec)[$month] . " " .
        $day;
    if ($hour < 10) {
        $time_stamp = $time_stamp . " 0" . $hour . ":"; 
    } else {
        $time_stamp = $time_stamp . " " . $hour . ":";
    }

    if ($min < 10) {
        $time_stamp = $time_stamp . "0" . $min . ":"; 
    } else {
        $time_stamp = $time_stamp . $min . ":";
    }

    if ($sek < 10) {
        $time_stamp = $time_stamp . "0" . $sek; 
    } else {
        $time_stamp = $time_stamp . $sek;
    }
    $time_stamp = $time_stamp . " " .$year;
}

##########################################################################
# SUBROUTINE: setMacroDefinitions
# PURPOSE   : get macro definitions from text file
##########################################################################
sub setMacroDefinitions
{
    my $macro = "";

    if (defined $macro_definitions) {
        # open macro definitions file for input
        open(MACROS, "<$macro_definitions")
            or die "ctc2html: Cannot open file $macro_definitions\n";
        while(<MACROS>) {
            chop;
            $macro = $_;
            #if ($macro =~ /\S/) {
            #    $macro =~ s/\s*?(\S+?)\s*$/$1/;
                $defined_macros{$macro} = 1;
            #}
        }
        close MACROS;
    }
}

##########################################################################
# SUBROUTINE: setInfo
# PURPOSE   : 
##########################################################################
sub setInfo
{
    $doctype_info = <<"END";
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
END
    $doctype_info_frames = <<"END";
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN">
END
#HTML5 <!DOCTYPE html>
    if (defined $charset) {
        $meta_info = "<meta http-equiv=\"Content-Type\" content=\"text/html; ".
                     "charset=$charset" . "\">\n";
    }
    $meta_info .= <<"END";
<meta name="keyword" content="CTC++, Testwell, Test Coverage Analyzer">
<meta name="date" content="$time_stamp">
<meta name="generator" content="Testwell CTC++ add-on utility $version">
<link href="$prefix$postfix" rel="contents">
<link href="ctc.css" rel="stylesheet" type="text/css">
END
    if (defined $webfonts) {
        $meta_info .= <<"END";
<link href="http://fonts.googleapis.com/css?family=Droid+Sans:400,700" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=Droid+Sans+Mono" rel="stylesheet" type="text/css">
END
    }
}

##########################################################################
# SUBROUTINE: setStyleInfo
# PURPOSE   : 
##########################################################################
sub setStyleInfo
{
    my $seven;
    my $nine;
    my $ten;
    my $seventeen;
    my $fontfamilyarial = "";
    my $fontfamilycourier = "";

    $fontfamilyarial = "font-family: Droid, Ubuntu, arial, helvetica, sans-serif";
    $fontfamilycourier = "font-family: \"Droid Sans Mono\", \"Ubuntu Mono\", consolas, \"courier new\", courier, monospace";

    unless ($zoom =~ /^\d+\.\d+$/ or $zoom =~ /^\.\d+$/ or $zoom =~ /^\d/) {
        $zoom = 1;
    }
    $zoom = 0.5 if $zoom < 0.5;
    $zoom = 3 if $zoom > 10;
    $zoom = int($zoom * 100);
    $seven = ((int (8.75 * $zoom))/100) . "pt";
    $nine = ((int (11.25 * $zoom))/100) . "pt";
    $ten = ((int (12.5 * $zoom))/100) . "pt";
    $seventeen = ((int (21.25 * $zoom))/100) . "pt";
    
    if (defined $own_stylesheet) {
        $copied_style_info = <<"END";
/*
  CSS stylesheet file copied from $own_stylesheet to ctc.css
  by $version at $time_stamp
*/
END
    }

    $style_info = <<"END";
/************************************************************************
* CSS stylesheet file generated by $version at $time_stamp
* Copyright (c) 2006-2013 Testwell Oy
* Copyright (c) 2013-2018 Verifysoft Technology GmbH
************************************************************************/
/* Provided that you know how, and at your own risk, you can change the styles
*  how some of the generated coverage report HTML pages look. The styles that
*  we suggest that you at most would modify are marked by a leading comment */   

/* Structural coverage Hits/True column not hit in Execution Profile */
 .tcolnhit { color: #FF0000; /* font-weight: bold; */
       text-align: right;
       padding-right: 0.40em;
       background-color: $tcolnhit_background; }

/* Structural coverage False column not hit in Execution Profile */
 .fcolnhit { color: #FF0000; /* font-weight: bold;*/
       text-align: right;
       padding-right: 0.40em;
       background-color: $fcolnhit_background; }

/* Structural coverage Hits/True/False columns hit or no counter at all
   in Execution Profile */
 .profile { text-align: right;
       padding-right: 0.40em;
       background-color: $profile_background; }

/* Line number column in Execution Profile */
 .profile_line { text-align: right;
       padding-right: 0.40em;
       border-left: 1px solid white;
       background-color: $profile_line_background; }

/* Structural coverage additional Description column in Execution Profile */
 .profile_descr { padding-right: 0.40em;
       border: 1px solid $profile_background;
       background-color: $profile_background; }

/* Line coverage line has been executed in Execution Profile */
 .linehit { border: 1px solid $linehit_border;
       background-color: $linehit_background; }

/* Line coverage line has not been executed in Execution Profile */
 .linenhit { border: 1px solid $linenhit_border;
       background-color: $linenhit_background; }

/* No line coverage painting for empty lines, plain {, } lines,
   lines outside of functions in Execution Profile */
 .lineplain { border: 1px solid $lineplain_border;
       background-color: $lineplain_background; }

/* Code line is disabled in preprocessor conditional (e.g. #if 0) in Execution Profile */
 .disable_code { color: #7B7B7B; font-weight: normal;
       border: 1px solid $disable_code_border;
       background-color: $disable_code_background; }

/* Structural coverage MC/DC criterion passed in Execution Profile */
 .mcdc_pass { color: #000000; font-weight: normal;
       text-align: center;
       padding-right: 0.40em;
       background-color: $mcdc_pass_background; }

/* Structural coverage MC/DC criterion failed in Execution Profile */
 .mcdc_fail { color: #FF0000; font-weight: bold;
       text-align: center;
       padding-right: 0.40em;
       background-color: $mcdc_fail_background; }

/* Preprocessor conditional outside of function background color in Execution Profile */
 .ppcond { border: 1px solid $ppcond_border;
       background-color: $ppcond_background; }

/* Preprocessor conditional inside of function background color in Execution Profile */
 .ppcondin { border: 1px solid $ppcondin_border;
       background-color: $ppcondin_background; }

/* Syntax highlight colors of source code in Execution Profile */
 .comment { color: green; font-weight: $comment_weight; }
 .string { color: maroon; font-weight: $string_weight; }
 .preproc { color: maroon; font-weight: $preproc_weight; }
 .keyword { color: blue; font-weight: $keyword_weight; }

 .count { font-weight: $count_weight; }
 .annotation { font-weight: $annotation_weight;
       visibility: $annotation_visibility;
       border: 1px solid $annotation_border;
       background-color: $annotation_background; }

 .highlight { text-align: right;
       padding-right: 0.40em;
       background-color: $mcdc_background; }

 .highlight_line { text-align: right;
       padding-right: 0.40em;
       border-left: 1px solid $mcdc_background;
       background-color: $mcdc_background; }

 .highlight_descr { padding-right: 0.40em;
       border: 1px solid $mcdc_background;
       background-color: $mcdc_background; }

 .linedir { padding-right: 0.40em;
       border: 1px solid $profile_background;
       background-color: $profile_background; }

 .profile_notfound { color: #FF00FF;
       border: 1px solid $profile_background;
       background-color: $profile_background; }

 .untested_flag { color: #FF0000; font-weight: normal;
       text-align: right;
       padding-right: 0.40em;
       background-color: $profile_background; }

 .report { font-size: $seventeen;
       padding-right: 0.80em; }

 .reportb { color: #000088; font-size: $seventeen; font-weight: bold;
       padding-right: 0.40em; }

 .pages, .info { font-size: $ten;
       padding-right: 0.40em; }

 .dirb, .infob { font-size: $ten; font-weight: bold;
       white-space:nowrap;
       padding-right: 0.40em; }

 .above { font-size: $ten;
       white-space:nowrap;
       text-align: right;
       padding-right: 0.40em; }

 .aboveb { font-size: $ten; font-weight: bold;
       white-space:nowrap;
       text-align: right;
       padding-right: 0.40em; }

 .NAright { font-size: $ten;
       text-align: right;
       padding-right: 0.40em; }

 .NAleft { font-size: $ten;
       text-align: left;
       padding-right: 0.40em; }

 .below { color: #FF0000; font-size: $ten;
       white-space:nowrap;
       text-align: right;
       padding-right: 0.40em; }

 .belowb { color: #FF0000; font-size: $ten; font-weight: bold;
       white-space:nowrap;
       text-align: right;
       padding-right: 0.40em; }

 .notfound { color: #FF00FF; font-size: $ten; }
 
 .calls, .line { font-size: $ten;
       text-align: right;
       padding-right: 0.40em; }

 .top { $fontfamilyarial;
       font-size: $seven; }

 .underline { font-size: $ten;
       white-space:nowrap;
       text-decoration: none; }

 .underlineb { font-size: $ten; font-weight: bold;
       white-space:nowrap;
       text-decoration: none; }

 body { $fontfamilyarial;
       color: #000000;
       background-color: white; }

 table { border-spacing: 0; }
 a:hover { text-decoration: underline; }
 a:link { color: #000088; }
 a:visited { color: #007788; }

 table.execution, table.untested { $fontfamilycourier;
       color: #000000;
       font-size: $nine;
       background-color: white; }

 table.execution thead tr th { position:-webkit-sticky; 
       position:sticky; 
       top:0; 
       font-size: $nine;
       padding-bottom: 0em;
       background-color:#dfdfe5; }

:target::before {
      content: "";
      display: block;
      height: 34px; /* same as header height */
      margin: -34px 0 0; /* negative header height */ }

 table.sortable thead { cursor: default; }

 thead { $fontfamilyarial;
       font-size: $ten; font-weight: normal; }

 th { border-bottom: thin solid black;
       white-space:nowrap;
       text-align: left;
       padding-right: 0.40em;
       padding-bottom: 0.20em; }

 .histogram { min-width: 115px; }
 .hidden { visibility: hidden; }
 .ruler { border-bottom: thin solid black; }
 .separator { padding-bottom: 0.80em; }
 .terindent { padding-right: 4.90em; }
 .indent { padding-right: 0.80em; }
 
 .tooltip {
    position: relative;
    display: inline-block;
  }
 .tooltip .tooltiptext {
    visibility: hidden;
    background-color: #FFFFE0;
    opacity: 1; 
    white-space:nowrap;
    color: black; 
    text-align: center;
    padding: 5px 0;
    border-radius: 6px;

    /* Position the tooltip text - see examples below! */
    position: absolute;
    z-index: 1;
 }

  /* Show the tooltip text when you mouse over the tooltip container */
  .tooltip:hover .tooltiptext {
    visibility: visible;
   }
 .tooltip .tooltiptext {
    top: 100%;
    left: 00%;
    margin-left: 3ex; /* Use half of the width (120/2 = 60), to center the tooltip */
 }
/* end of ctc.css */
END
}

##########################################################################
# SUBROUTINE: setFilenames
# PURPOSE   : Sets the report filenames
##########################################################################
sub setFilenames
{
    my $sub;

    for ($sub = 1; $sub <= $numDirectories; $sub++) {
        $funcs_html{$sub} = $prefix . "B" . $sub . $postfix;
    }
    for ($sub = 1; $sub <= $numFiles; $sub++) {
        $profile_html{$sub} = $prefix . "D" . $sub . $postfix;
    }
    #for ($sub = 1; $sub <= $numFiles; $sub++) {
    #    $profile_html{$sub} = $prefix . "D" . $sub . "_" .$orig_filenames{$sub} . $postfix;
    #}

    $files_html          = $prefix . $postfix;
    $frame_profile_html  = $prefix . "A" . $postfix;
    $index_profile_html  = $prefix . "C" . $postfix;
    $missing_html        = $prefix . "E" . $postfix;
    $directory_html      = $prefix . "F" . $postfix;
    $overall_html        = $prefix . "O" . $postfix;
    $frame_funcs_html    = $prefix . "G" . $postfix;
    $index_funcs_html    = $prefix . "H" . $postfix;
    $index_untested_html = $prefix . "I" . $postfix;
    $frame_untested_html = $prefix . "J" . $postfix;
    $untested_html       = $prefix . "U" . $postfix;
    $funcs_wild          = $prefix . "B*" . $postfix;
    $profile_wild        = $prefix . "D*" . $postfix;
}

##########################################################################
# SUBROUTINE: unlinkReportFiles
# PURPOSE   : Deletes all report files
##########################################################################
sub unlinkReportFiles
{
    unlink "$html_dir/$files_html";          # CTCHTML/index.html
    unlink "$html_dir/$frame_profile_html";  # CTCHTML/indexA.html
    unlink "$html_dir/$index_profile_html";  # CTCHTML/indexC.html
    unlink "$html_dir/$missing_html";        # CTCHTML/indexE.html
    unlink "$html_dir/$directory_html";      # CTCHTML/indexF.html
    unlink "$html_dir/$overall_html";        # CTCHTML/indexO.html
    unlink "$html_dir/$frame_funcs_html";    # CTCHTML/indexG.html
    unlink "$html_dir/$index_funcs_html";    # CTCHTML/indexH.html
    unlink "$html_dir/$index_untested_html"; # CTCHTML/indexI.html
    unlink "$html_dir/$frame_untested_html"; # CTCHTML/indexJ.html
    unlink "$html_dir/$untested_html";       # CTCHTML/indexU.html
   
    unlink "$html_dir/blue.gif"; 
    unlink "$html_dir/red.gif";
    unlink "$html_dir/white.gif";
    unlink "$html_dir/yellow.gif";
    unlink "$html_dir/ctc.js";
    unlink "$html_dir/sorttable.js";
    unlink "$html_dir/own_javascript.js";
    unlink "$html_dir/ctc.css";

    unlink <$html_dir/$funcs_wild>;          # CTCHTML/indexB*.html
    unlink <$html_dir/$profile_wild>;        # CTCHTML/indexD*.html
}

##########################################################################
# SUBROUTINE: openReportFiles
# PURPOSE   : create the report files
##########################################################################
sub openReportFiles
{
    open(FILES, ">$html_dir/$files_html")
        or die "ctc2html: Cannot create file $html_dir/$files_html\n";
    open(FRAME_PROFILE, ">$html_dir/$frame_profile_html")
        or die "ctc2html: Cannot create file $html_dir/$frame_profile_html\n";
    open(FRAME_FUNCS, ">$html_dir/$frame_funcs_html")
        or die "ctc2html: Cannot create file $html_dir/$frame_funcs_html\n";
    open(FRAME_UNTESTED, ">$html_dir/$frame_untested_html")
        or die "ctc2html: Cannot create file $html_dir/$frame_untested_html\n";
    open(INDEX_PROFILE, ">$html_dir/$index_profile_html")
        or die "ctc2html: Cannot create file $html_dir/$index_profile_html\n";
    open(INDEX_FUNCS, ">$html_dir/$index_funcs_html")
        or die "ctc2html: Cannot create file $html_dir/$index_funcs_html\n";
    open(INDEX_UNTESTED, ">$html_dir/$index_untested_html")
        or die "ctc2html: Cannot create file $html_dir/$index_untested_html\n";
    open(MISSING, ">$html_dir/$missing_html")
        or die "ctc2html: Cannot create file $html_dir/$missing_html\n";
    open(OVERALL, ">$html_dir/$overall_html")
        or die "ctc2html: Cannot create file $html_dir/$overall_html\n";
    open(DIRECTORY, ">$html_dir/$directory_html")
        or die "ctc2html: Cannot create file $html_dir/$directory_html\n";
    open(UNTESTED, ">$html_dir/$untested_html")
        or die "ctc2html: Cannot create file $html_dir/$untested_html\n";
}

##########################################################################
# SUBROUTINE: histogram
# PURPOSE   : This subroutine returns a histogram representing the TER%
#             given as an argument. Three small gifs are used, whose
#             widths are scaled to match the TER%. A red gif is used to
#             show the portion of the TER% that is below the threshold
#             percent and blue gif when beyond that.
##########################################################################
sub histogram
{
    my ($ter, $stmt) = @_;
    my ($natural, $untested);
    my $alt = "";
    my $yellow = "";
    my $white = " ";
    my $hist = "";
    my $naturalcolor = "";
    my $thold;

    if ($stmt == 1) {
        $thold = $stmtthreshold; # statement threshold
    } else {
        $thold = $threshold; # structural threshold
    }
    
    if ($ter < $thold) {
        $naturalcolor = "red.gif";
    } else {
        $naturalcolor = "blue.gif";
    }

    $natural = $ter;
    if ($natural > 0) {
        $alt = "&#9608;" x int($natural/10);
        $hist .= "<img border=\"1\" src=\"$naturalcolor\" width=\"$natural\" ".
                 "height=\"5\" alt=\"$alt\">";
    }

    $untested = 100 - $ter;
    if ($untested > 0) {
        $hist .= "<img border=\"1\" src=\"white.gif\" width=\"$untested\" ".
                 "height=\"5\" alt=\"$white\">";
    }
    return $hist;
}

##########################################################################
# SUBROUTINE: exp_format
# PURPOSE   : Converts $number to an exponential form with
#             $precision characters. Example: exp_format(10000,3)
#             yields 1E4, exp_format(65309,4) yields 65E3.
##########################################################################
sub exp_format 
{
    my ($number, $precision) = @_;
    my $result;
    my $exp = 3;

    $number =~ s/ //g;
    return "" if ($number eq "");

    if ($number >= 10**$precision) {
        while ($number/10**$exp >= 10**($precision - 2)) {
            ++$exp;
        }
        $result = int($number/(10**$exp))."E$exp";
    } else {
        $result = $number;
    }
    return $result;
}

##########################################################################
# SUBROUTINE: printHTMLHeader
# PURPOSE   : write the header parts of the report HTML files
##########################################################################
sub printHTMLHeader
{
    my ($sub, $key);
    my $missing_source_files = "";

    foreach $key (keys %file_not_found) {
        $missing_source_files = " | <a href=\"$missing_html\">Missing Source Files</a>";
        last;
    }

    for ($sub = 1; $sub <= $numFiles; $sub++) {
        open(PROFILE, ">$html_dir/$profile_html{$sub}")
            or die "ctc2html: Cannot create file $html_dir/$profile_html{$sub}\n";
        print PROFILE <<"END";
$doctype_info<html>
<head>
<title>$reptitle - Execution Profile - $basenames{$sub}</title>
$meta_info$script_info</head>
<body>
<span class="reportb">$reptitle</span><span class="report">- Execution Profile</span><span class="info">#$sub/$numFiles</span><br><br>
END
        if ($numFiles > 1) {
            if ($sub == 1) {
                print PROFILE <<"END";
<span class="pages"><a href="$directory_html" target="_top">Directory Summary</a> | <a href="$files_html" target="_top">Files Summary</a> | <a href="$funcs_html{1}" target="_top">Functions Summary</a> | <a href="$untested_html" target="_top">Untested Code</a> | <a href="$profile_html{1}">Execution Profile</a><br>
To files: <a href="$profile_html{1}">First</a> | Previous | <a href="$profile_html{2}">Next</a> | <a href="$profile_html{$numFiles}">Last</a> | <a href="$frame_profile_html#a1">Index</a> | <a href="$profile_html{1}" target="_top">No Index</a></span><br><br>
END
            } elsif ($sub < $numFiles) {
                print PROFILE <<"END";
<span class="pages"><a href="$directory_html" target="_top">Directory Summary</a> | <a href="$files_html" target="_top">Files Summary</a> | <a href="$funcs_html{1}" target="_top">Functions Summary</a> | <a href="$untested_html" target="_top">Untested Code</a> | <a href="$profile_html{1}">Execution Profile</a><br>
To files: <a href="$profile_html{1}">First</a> | <a href="$profile_html{$sub-1}">Previous</a> | <a href="$profile_html{$sub+1}">Next</a> | <a href="$profile_html{$numFiles}">Last</a> | <a href="$frame_profile_html#a$sub">Index</a> | <a href="$profile_html{$sub}" target="_top">No Index</a></span><br><br>
END
            } else { 
                print PROFILE <<"END";
<span class="pages"><a href="$directory_html" target="_top">Directory Summary</a> | <a href="$files_html" target="_top">Files Summary</a> | <a href="$funcs_html{1}" target="_top">Functions Summary</a> | <a href="$untested_html" target="_top">Untested Code</a> | <a href="$profile_html{1}">Execution Profile</a><br>
To files: <a href="$profile_html{1}">First</a> | <a href="$profile_html{$numFiles-1}">Previous</a> | Next | <a href="$profile_html{$numFiles}">Last</a> | <a href="$frame_profile_html#a$numFiles">Index</a> | <a href="$profile_html{$numFiles}" target="_top">No Index</a></span><br><br>
END
            }
        } else {
            print PROFILE <<"END";
<span class="pages"><a href="$directory_html" target="_top">Directory Summary</a> | <a href="$files_html" target="_top">Files Summary</a> | <a href="$funcs_html{1}" target="_top">Functions Summary</a> | <a href="$untested_html" target="_top">Untested Code</a> | <a href="$profile_html{1}">Execution Profile</a><br>
To files: <a href="$profile_html{1}">First</a> | Previous | Next | <a href="$profile_html{1}">Last</a> | <a href="$frame_profile_html#a1">Index</a> | <a href="$profile_html{1}" target="_top">No Index</a></span><br><br>
END
        }
        close PROFILE;
    }
 
    print FILES <<"END";
$doctype_info<html>
<head>
<title>$reptitle - Files Summary</title>
$meta_info$script_info</head>
<body>
<span class="reportb">$reptitle</span><span class="report">- Files Summary</span><br><br>
<span class="pages"><a href="$directory_html">Directory Summary</a> | <a href="$files_html">Files Summary</a> | <a href="$funcs_html{1}">Functions Summary</a> | <a href="$untested_html">Untested Code</a> | <a href="$profile_html{1}">Execution Profile</a></span><br><br>
END
    print OVERALL <<"END";
$doctype_info<html>
<head>
<title>$reptitle - Overall Summary</title>
$meta_info$script_info</head>
<body>
<span class="reportb">$reptitle</span><span class="report">- Overall Summary</span><br><br>
<span class="pages"><a href="$directory_html">Directory Summary</a> | <a href="$files_html">Files Summary</a> | <a href="$funcs_html{1}">Functions Summary</a> | <a href="$untested_html">Untested Code</a> | <a href="$profile_html{1}">Execution Profile</a>$missing_source_files</span><br><br>
END
    print DIRECTORY <<"END";
$doctype_info<html>
<head>
<title>$reptitle - Directory Summary</title>
$meta_info$script_info</head>
<body>
<span class="reportb">$reptitle</span><span class="report">- Directory Summary</span><br><br>
<span class="pages"><a href="$directory_html">Directory Summary</a> | <a href="$files_html">Files Summary</a> | <a href="$funcs_html{1}">Functions Summary</a> | <a href="$untested_html">Untested Code</a> | <a href="$profile_html{1}">Execution Profile</a></span><br><br>
END
    for ($sub = 1; $sub <= $numDirectories; $sub++) {
        open(FUNCS, ">$html_dir/$funcs_html{$sub}")
            or die "ctc2html: Cannot create file $html_dir/$funcs_html{$sub}\n";
        print FUNCS <<"END";
$doctype_info<html>
<head>
<title>$reptitle - Functions Summary - $directories{$sub}</title>
$meta_info$script_info</head>
<body>
<span class="reportb">$reptitle</span><span class="report">- Functions Summary</span><span class="info">#$sub/$numDirectories</span><br><br>
END
        if ($numDirectories > 1) {
            if ($sub == 1) {
                print FUNCS <<"END";
<span class="pages"><a href="$directory_html" target="_top">Directory Summary</a> | <a href="$files_html" target="_top">Files Summary</a> | <a href="$funcs_html{1}">Functions Summary</a> | <a href="$untested_html" target="_top">Untested Code</a> | <a href="$profile_html{1}" target="_top">Execution Profile</a><br>
To directories: <a href="$funcs_html{1}">First</a> | Previous | <a href="$funcs_html{2}">Next</a> | <a href="$funcs_html{$numDirectories}">Last</a> | <a href="$frame_funcs_html#ad1">Index</a> | <a href="$funcs_html{1}" target="_top">No Index</a></span><br><br>
END
            } elsif ($sub < $numDirectories) {
                print FUNCS <<"END";
<span class="pages"><a href="$directory_html" target="_top">Directory Summary</a> | <a href="$files_html" target="_top">Files Summary</a> | <a href="$funcs_html{1}">Functions Summary</a> | <a href="$untested_html" target="_top">Untested Code</a> | <a href="$profile_html{1}" target="_top">Execution Profile</a><br>
To directories: <a href="$funcs_html{1}">First</a> | <a href="$funcs_html{$sub-1}">Previous</a> | <a href="$funcs_html{$sub+1}">Next</a> | <a href="$funcs_html{$numDirectories}">Last</a> | <a href="$frame_funcs_html#ad$sub">Index</a> | <a href="$funcs_html{$sub}" target="_top">No Index</a></span><br><br>
END
            } else { 
                print FUNCS <<"END";
<span class="pages"><a href="$directory_html" target="_top">Directory Summary</a> | <a href="$files_html" target="_top">Files Summary</a> | <a href="$funcs_html{1}">Functions Summary</a> | <a href="$untested_html" target="_top">Untested Code</a> | <a href="$profile_html{1}" target="_top">Execution Profile</a><br>
To directories: <a href="$funcs_html{1}">First</a> | <a href="$funcs_html{$numDirectories-1}">Previous</a> | Next | <a href="$funcs_html{$numDirectories}">Last</a> | <a href="$frame_funcs_html#ad$numDirectories">Index</a> | <a href="$funcs_html{$numDirectories}" target="_top">No Index</a></span><br><br>
END
            }
        } else {
            print FUNCS <<"END";
<span class="pages"><a href="$directory_html" target="_top">Directory Summary</a> | <a href="$files_html" target="_top">Files Summary</a> | <a href="$funcs_html{1}">Functions Summary</a> | <a href="$untested_html" target="_top">Untested Code</a> | <a href="$profile_html{1}" target="_top">Execution Profile</a><br>
To directories: <a href="$funcs_html{1}">First</a> | Previous | Next | <a href="$funcs_html{1}">Last</a> | <a href="$frame_funcs_html#ad1">Index</a> | <a href="$funcs_html{1}" target="_top">No Index</a></span><br><br>
END
        }
        close FUNCS;
    }

    print INDEX_PROFILE <<"END";
$doctype_info<html>
<head>
<title>$reptitle - Execution Profile - Index</title>
$meta_info$script_info</head>
<body>
<span class="infob">Index</span><br>
<span class="info">$verboseIndexDescr</span>
<table>
END
    print INDEX_FUNCS <<"END";
$doctype_info<html>
<head>
<title>$reptitle - Functions Summary - Index</title>
$meta_info$script_info</head>
<body>
<span class="infob">Index</span><br>
<span class="info"></span>
<table>
END
    print INDEX_UNTESTED <<"END";
$doctype_info<html>
<head>
<title>$reptitle - Untested Code - Index</title>
$meta_info$script_info</head>
<body>
<span class="infob">Index</span><br>
<span class="info"></span>
<table>
END
    print UNTESTED <<"END";
$doctype_info<html>
<head>
<title>$reptitle - Untested Code</title>
$meta_info$script_info</head>
<body>
<span class="reportb">$reptitle</span><span class="report">- Untested Code</span><br><br>
<span class="pages"><a href="$directory_html" target="_top">Directory Summary</a> | <a href="$files_html" target="_top">Files Summary</a> | <a href="$funcs_html{1}" target="_top">Functions Summary</a> | <a href="$untested_html">Untested Code</a> | <a href="$profile_html{1}" target="_top">Execution Profile</a><br>
To files: <a href="$frame_untested_html#ufi1">Index</a> | <a href="$untested_html" target="_top">No Index</a></span><br><br>
END
    # write the container file for the two frames, files/functions index and
    # execution profile listing (combined with source code file)
    print FRAME_PROFILE <<"END";
$doctype_info_frames<html>
<head>
<title>$reptitle - Execution Profile - Index</title>
$meta_info$script_info</head>
<frameset cols="25%,75%"$onLoad_profile>
<frame src="$index_profile_html" name="index_profile">
<frame src="$profile_html{1}" name="profile">
</frameset>
</html>
END
    close FRAME_PROFILE;
    # write the container file for the two frames, directories/files index and
    # functions summary
    print FRAME_FUNCS <<"END";
$doctype_info_frames<html>
<head>
<title>$reptitle - Functions Summary - Index</title>
$meta_info$script_info</head>
<frameset cols="25%,75%"$onLoad_funcs>
<frame src="$index_funcs_html" name="index_funcs">
<frame src="$funcs_html{1}" name="functions">
</frameset>
</html>
END
    close FRAME_FUNCS;
    # write the container file for the two frames, files/functions index and
    # untested code listing
    print FRAME_UNTESTED <<"END";
$doctype_info_frames<html>
<head>
<title>$reptitle - Untested Code - Index</title>
$meta_info$script_info</head>
<frameset cols="25%,75%"$onLoad_untested>
<frame src="$index_untested_html" name="index_untested">
<frame src="$untested_html" name="untested">
</frameset>
</html>
END
    close FRAME_UNTESTED;

    print MISSING <<"END";
$doctype_info<html>
<head>
<title>$reptitle - Source Files Not Found</title>
$meta_info$script_info</head>
<body>
<span class="infob">The following source files were not found by ctc2html:</span><br><br>
<span class="info">
END
}

##########################################################################
# SUBROUTINE: printHTMLHeader_NSF
# PURPOSE   : write the initial parts of the empty (No Source Files)
#             report HTML files
##########################################################################
sub printHTMLHeader_NSF
{
    print FILES <<"END";
$doctype_info<html>
<head>
<title>$reptitle - Files Summary</title>
$meta_info$script_info</head>
<body>
<span class="reportb">$reptitle</span><span class="report">- Files Summary</span><br><br>
<span class="pages"><a href="$directory_html">Directory Summary</a> | <a href="$files_html">Files Summary</a> | Functions Summary | Untested Code | Execution Profile</span><br><br>
END
    print OVERALL <<"END";
$doctype_info<html>
<head>
<title>$reptitle - Overall Summary</title>
$meta_info$script_info</head>
<body>
<span class="reportb">$reptitle</span><span class="report">- Overall Summary</span><br><br>
<span class="pages"><a href="$directory_html">Directory Summary</a> | <a href="$files_html">Files Summary</a> | Functions Summary | Untested Code | Execution Profile</span><br><br>
END
    print DIRECTORY <<"END";
$doctype_info<html>
<head>
<title>$reptitle - Directory Summary</title>
$meta_info$script_info</head>
<body>
<span class="reportb">$reptitle</span><span class="report">- Directory Summary</span><br><br>
<span class="pages"><a href="$directory_html">Directory Summary</a> | <a href="$files_html">Files Summary</a> | Functions Summary | Untested Code | Execution Profile</span><br><br>
END
}

##########################################################################
# SUBROUTINE: printProfileFooter
# PURPOSE   : print the links at end of execution profile html page
##########################################################################
sub printProfileFooter
{
    my $sub = $gSource_id;

    if ($numFiles > 1) {
        if ($sub == 1) {
            print PROFILE <<"END";
<span class="pages"><a href="$directory_html" target="_top">Directory Summary</a> | <a href="$files_html" target="_top">Files Summary</a> | <a href="$funcs_html{1}" target="_top">Functions Summary</a> | <a href="$untested_html" target="_top">Untested Code</a> | <a href="$profile_html{1}">Execution Profile</a><br>
To files: <a href="$profile_html{1}">First</a> | Previous | <a href="$profile_html{2}">Next</a> | <a href="$profile_html{$numFiles}">Last</a> | <a href="$profile_html{1}">Top</a> | <a href="$frame_profile_html#a1">Index</a> | <a href="$profile_html{1}" target="_top">No Index</a></span><br><br>
END
        } elsif ($sub < $numFiles) {
            print PROFILE <<"END";
<span class="pages"><a href="$directory_html" target="_top">Directory Summary</a> | <a href="$files_html" target="_top">Files Summary</a> | <a href="$funcs_html{1}" target="_top">Functions Summary</a> | <a href="$untested_html" target="_top">Untested Code</a> | <a href="$profile_html{1}">Execution Profile</a><br>
To files: <a href="$profile_html{1}">First</a> | <a href="$profile_html{$sub-1}">Previous</a> | <a href="$profile_html{$sub+1}">Next</a> | <a href="$profile_html{$numFiles}">Last</a> | <a href="$profile_html{$sub}">Top</a> | <a href="$frame_profile_html#a$sub">Index</a> | <a href="$profile_html{$sub}" target="_top">No Index</a></span><br><br>
END
        } else { 
            print PROFILE <<"END";
<span class="pages"><a href="$directory_html" target="_top">Directory Summary</a> | <a href="$files_html" target="_top">Files Summary</a> | <a href="$funcs_html{1}" target="_top">Functions Summary</a> | <a href="$untested_html" target="_top">Untested Code</a> | <a href="$profile_html{1}">Execution Profile</a><br>
To files: <a href="$profile_html{1}">First</a> | <a href="$profile_html{$numFiles-1}">Previous</a> | Next | <a href="$profile_html{$numFiles}">Last</a> | <a href="$profile_html{$numFiles}">Top</a> | <a href="$frame_profile_html#a$numFiles">Index</a> | <a href="$profile_html{$numFiles}" target="_top">No Index</a></span><br><br>
END
        }
    } else {
        print PROFILE <<"END";
<span class="pages"><a href="$directory_html" target="_top">Directory Summary</a> | <a href="$files_html" target="_top">Files Summary</a> | <a href="$funcs_html{1}" target="_top">Functions Summary</a> | <a href="$untested_html" target="_top">Untested Code</a> | <a href="$profile_html{1}">Execution Profile</a><br>
To files: <a href="$profile_html{1}">First</a> | Previous | Next | <a href="$profile_html{1}">Last</a> | <a href="$profile_html{1}">Top</a> | <a href="$frame_profile_html#a1">Index</a> | <a href="$profile_html{1}" target="_top">No Index</a></span><br><br>
END
    }
}

##########################################################################
# SUBROUTINE: printFuncsFooter
# PURPOSE   : print the links at end of functions summary html page
##########################################################################
sub printFuncsFooter
{
    my $sub = $gFuncs_dir_id;

    if ($numDirectories > 1) {
        if ($sub == 1) {
            print FUNCS <<"END";
<span class="pages"><a href="$directory_html" target="_top">Directory Summary</a> | <a href="$files_html" target="_top">Files Summary</a> | <a href="$funcs_html{1}">Functions Summary</a> | <a href="$untested_html" target="_top">Untested Code</a> | <a href="$profile_html{1}" target="_top">Execution Profile</a><br>
To directories: <a href="$funcs_html{1}">First</a> | Previous | <a href="$funcs_html{2}">Next</a> | <a href="$funcs_html{$numDirectories}">Last</a> | <a href="$funcs_html{1}">Top</a> | <a href="$frame_funcs_html#ad1">Index</a> | <a href="$funcs_html{1}" target="_top">No Index</a></span><br><br>
END
        } elsif ($sub < $numDirectories) {
            print FUNCS <<"END";
<span class="pages"><a href="$directory_html" target="_top">Directory Summary</a> | <a href="$files_html" target="_top">Files Summary</a> | <a href="$funcs_html{1}">Functions Summary</a> | <a href="$untested_html" target="_top">Untested Code</a> | <a href="$profile_html{1}" target="_top">Execution Profile</a><br>
To directories: <a href="$funcs_html{1}">First</a> | <a href="$funcs_html{$sub-1}">Previous</a> | <a href="$funcs_html{$sub+1}">Next</a> | <a href="$funcs_html{$numDirectories}">Last</a> | <a href="$funcs_html{$sub}">Top</a> | <a href="$frame_funcs_html#ad$sub">Index</a> | <a href="$funcs_html{$sub}" target="_top">No Index</a></span><br><br>
END
        } else { 
            print FUNCS <<"END";
<span class="pages"><a href="$directory_html" target="_top">Directory Summary</a> | <a href="$files_html" target="_top">Files Summary</a> | <a href="$funcs_html{1}">Functions Summary</a> | <a href="$untested_html" target="_top">Untested Code</a> | <a href="$profile_html{1}" target="_top">Execution Profile</a><br>
To directories: <a href="$funcs_html{1}">First</a> | <a href="$funcs_html{$numDirectories-1}">Previous</a> | Next | <a href="$funcs_html{$numDirectories}">Last</a> | <a href="$funcs_html{$numDirectories}">Top</a> | <a href="$frame_funcs_html#ad$numDirectories">Index</a> | <a href="$funcs_html{$numDirectories}" target="_top">No Index</a></span><br><br>
END
        }
    } else {
        print FUNCS <<"END";
<span class="pages"><a href="$directory_html" target="_top">Directory Summary</a> | <a href="$files_html" target="_top">Files Summary</a> | <a href="$funcs_html{1}">Functions Summary</a> | <a href="$untested_html" target="_top">Untested Code</a> | <a href="$profile_html{1}" target="_top">Execution Profile</a><br>
To directories: <a href="$funcs_html{1}">First</a> | Previous | Next | <a href="$funcs_html{1}">Last</a> | <a href="$funcs_html{1}">Top</a> | <a href="$frame_funcs_html#ad1">Index</a> | <a href="$funcs_html{1}" target="_top">No Index</a></span><br><br>
END
    }
}

##########################################################################
# SUBROUTINE: printHTMLFooter
# PURPOSE   : print the end of the rest of HTML files
##########################################################################
sub printHTMLFooter
{
    my $key;

    foreach $key (keys %file_not_found) {
        print MISSING "$key<br>\n";
    }
    print MISSING <<"END";
</span>
</body>
</html>
END
    print UNTESTED <<"END";
<span class="pages"><a href="$directory_html" target="_top">Directory Summary</a> | <a href="$files_html" target="_top">Files Summary</a> | <a href="$funcs_html{1}" target="_top">Functions Summary</a> | <a href="$untested_html">Untested Code</a> | <a href="$profile_html{1}" target="_top">Execution Profile</a><br>
To files: <a href="$frame_untested_html#ufi1">Index</a> | <a href="$untested_html" target="_top">No Index</a></span><br><br>
</body>
</html>
END
    print INDEX_PROFILE <<"END";
</table>
</body>
</html>
END
    print INDEX_FUNCS <<"END";
</table>
</body>
</html>
END
    print INDEX_UNTESTED <<"END";
</table>
</body>
</html>
END
    close MISSING;
    close UNTESTED;
    close INDEX_PROFILE;
    close INDEX_FUNCS;
    close INDEX_UNTESTED;
}

##########################################################################
# SUBROUTINE: same_file
# PURPOSE   : Tells if two filenames given as arguments are referring to
#             the same location independently of how the names are given.
#             For example, one name can contain a relative path to a file
#             and the other an absolute path.
##########################################################################
sub same_file
{
    my ($file1, $file2) = @_;

    if ($file1 eq $file2) {
        return 1;
    }
    # If the strings are not equal, convert to absolute paths before comparing
    $file1 = get_full_path_name($file1);
    $file2 = get_full_path_name($file2);
    if ($^O eq "MSWin32") {     # on Windows filenames are not case sensitive
        $file1 = lc($file1);
        $file2 = lc($file2);
    }
    return $file1 eq $file2;
}

##########################################################################
# SUBROUTINE: relname
# PURPOSE   : Returns relative path if option --enable-relativepath ($relativepath) is defined
# ARGUMENT  : - the original absolute pathname
# RETURNS   : basename or relative pathname, working in Linux/Unix/Windows
##########################################################################
sub relname
{
    my $path = $_[0];
    my $cwd;

    # Get current/working directory
    if ($^O eq "MSWin32") { # on Windows filenames are not case sensitive
        $cwd = `cd`;
        $cwd =~ s/\n//;             # Remove ending "\n"
        $path = lc($path);
        $cwd = lc($cwd);
        #$cwd =~ s/^.+:(.+)/$1/; # remove drive letter
    } else {                    # hpux, solaris or linux,
        $cwd = `pwd`;
        $cwd =~ s/\n//;             # Remove ending "\n"
    }

    # absolute path => relative path
    if (index($path, $cwd) == 0) {
        $path = substr($path, length($cwd));
        while (length($path) &&
                (substr($path, 0, 1) eq '/' || substr($path, 0, 1) eq '\\' ))
        {
            $path = substr($path, 1);
        }
    }
    return $path;
}

##########################################################################
# SUBROUTINE: which
# PURPOSE   : Determines fullpath of an executable in $PATH
# ARGUMENTS : - Name of executable
# RETURNS   : Fullpath to executable
# NOTE      : Windows may not work, but unneeded here
#             Not work, in sense of missing extension
##########################################################################
sub which {
    my ($exe) = @_;
    my $tmp;
    my $separator = '/';
    my $envseparator = ':';
    $separator = '\\' if $^O eq "MSWin32";
    $separator = ';' if $^O eq "MSWin32";

    foreach (split $envseparator, $ENV{PATH}) {
	$tmp =~ s/\/\//\//g;
	$tmp = $_ . $separator . $exe;
	return $tmp if -x $tmp;
    }

    return undef;
}

##########################################################################
# SUBROUTINE: get_full_path_name
# PURPOSE   : Returns the full (absolute) path to a file given as argument
#             name of a specified file
##########################################################################
sub get_full_path_name 
{
    my ($filename) = @_;
    my ($fullpathname, $cwd, $drive);
    my $is_absolute = 0;

    # Get current/working directory
    if ($^O eq "MSWin32") {     # Windows
        $cwd = `cd`;
    } else {                    # hpux, solaris or linux,
        $cwd = `pwd`;
    }
    $cwd =~ s/\n//;             # Remove ending "\n"

    if ($^O eq "MSWin32") {                 # Windows
       if ($filename =~ /^[a-zA-Z]:/) {         # Drive given
           if ($filename =~ /^..[\\\/]/) {      # Already absolute
               $fullpathname = $filename;
           } else {                             # Drive without root directory given
              $drive = substr($filename, 0, 2);
              $cwd = `cd $drive`;               # Get current directory on that drive
              $cwd =~ s/\n//;                   # Remove ending "\n"
              $fullpathname = $cwd . "/" . substr($filename, 2);
           }
       } elsif ($filename =~ /^\\\\/) {         # A UNC name
           $fullpathname = $filename;
       } elsif ($filename =~ /^[\\\/]/) {       # Absolute but without drive name
           $drive = substr($filename, 0, 2);
           $fullpathname = $drive . $filename;
       } else {                                 # Relative
           $fullpathname = $cwd . "/" . $filename;
       }
    }
    else {                                # hpux, solaris or linux,
       if ($filename =~ /^\//) {                # Already absolute
           $fullpathname = $filename;
       } else {                                 # Relative
           $fullpathname = $cwd . "/" . $filename;
       }
    }

    $fullpathname =~ s/\\/\//g;             # Every "\" -> "/"
    if ($^O eq "MSWin32" and $filename =~ /^\\\\/) {   # A UNC name
        $fullpathname =~ s/^\/\//\\\\/;                    # preserve starting "\\"
    }

    do {
        if ($fullpathname =~ s/\/\//\//g) {             # "//" -> "/"
            ;
        } elsif ($fullpathname =~ s/\/\.\//\//g) {      # "/./" -> "/"
            ;
        } elsif ($fullpathname =~ /(.*\/)([^\/\.]+\/\.\.\/)(.*)/) {     # "subdir/../"
            $fullpathname = $1 . $3;
        } else {
            $is_absolute = 1;
        }
    } until ($is_absolute);

    if ($^O eq "MSWin32") {                 # On Windows, "/" -> "\"
        $fullpathname =~ s/\//\\/g;
    }
    return $fullpathname;
}

##########################################################################
# SUBROUTINE: dirname
# PURPOSE   : Returns the directory part of a filename
##########################################################################
sub dirname
{
    my ($filename) = @_;
    my $dir = "";
    my $end;

    $end = rindex $filename, '\\';
    if ((rindex $filename, '/') > $end) {
        $end = rindex $filename, '/';
    }
    if ($end > 0) {
        $dir = substr $filename, 0, $end;
    } elsif ($end == 0) {
        $dir = substr $filename, 0, 1;
    }
    return $dir;
}

##########################################################################
# SUBROUTINE: basename
# PURPOSE   : Strip directory from a filename
##########################################################################
sub basename 
{
    my ($filename) = @_;
    my $base; 
    my $end;

#    $filename=~s/\s+\(NO\sCOMPARE,.+\)$//; 
    $base = $filename;
    
    $end = rindex $filename, '\\';
    if ((rindex $filename, '/') > $end) {
        $end = rindex $filename, '/';
    }
    if ($end >= 0) {
        $base = substr $filename, $end + 1;
    }
    return $base;
}

##########################################################################
# SUBROUTINE: getAlarmCh
# PURPOSE   : get alarm character if warning is on
##########################################################################
sub getAlarmCh
{
    my ($flag) = @_;
    my $alarm = "";

    $alarm = $alarmch if defined $flag;
    return $alarm;
}

##########################################################################
# SUBROUTINE: warning
# PURPOSE   : Display a warning message on stderr.
#
##########################################################################
sub warning
{
    $warning = $_[0];
    print STDERR "ctc2html: warning: $warning\n";
}

##########################################################################
# SUBROUTINE: copyProfileListing
# PURPOSE   : copy original Profile Listing to be used as new INPUT. Get
#             number of source files to be used as split number of html'zed profile.
#             Get function and source ter % to hash. 
#             Get directory names to hash.
##########################################################################
sub copyProfileListing
{
    $_ = $_[0];
    my ($aMon_dir, $mon_file_ter);
    my $orig_mon_file = "";
    my $orig_mon_dir = "";
    my $orig_linedir_file = "";
    my $aLinedir_file = "";
    my @normalized = ();
    my $Mon_sh_prefix = "";
    my $Mon_sh_fullline = "";

    if (/\*\s+CTC\+\+, Test Coverage Analyzer for C\/C\+\+, Version (9\.(0|1|2|3)\S*)/) {
        $gVctcpost = 'v' . $1;
        $version =~ / (v.+)/;
        $gVctc2html = $1;
        $version_9_0 = 1;
    }

    elsif (/\*\s+EXECUTION PROFILE LISTING\s+\*/) {
        $listing_type = 1;
    }

    elsif (/\*\s+EXECUTION PROFILE LISTING \(MERGED by ctcxmlmerge (.+)\)/) {
        $gVctcxmlmerge = $1;
        $listing_type = 1;
    }   

    #*             EXECUTION PROFILE LISTING (COMPARED by ctcdiff v1.0)          *
    elsif (/\*\s+EXECUTION PROFILE LISTING \(COMPARED by ctcdiff (.+)\)/) {
        $gVctcdiff = $1;
        $listing_type = 1;
	$reptitle = "CTC++ CTCDIFF Report";
    }


    elsif (/Symbol file\(s\) used\s+: (.+)/) {
        $gIn_symbol_files = 1;
        appendSymDir($1);
    }

    elsif (/Data file\(s\) used\s+: .+/) {
        undef $gIn_symbol_files;
    }

    elsif (/XML file\(s\) used\s+: .+/) {
        undef $gIn_symbol_files;
    }

    elsif (/^\s+: (.+)/) { # Additional symbol, data or (Un)Chosen file name
        appendSymDir($1);
    }

    elsif (/^(MONITORED .+ FILE : )(.+)/) {
        $Mon_sh_prefix = $1;
        $orig_mon_file = $2;

        if (defined $processed_source_files{$orig_mon_file}) {
            $orig_mon_file = $2 . $second_copy_suffix;
        } else {
            $processed_source_files{$orig_mon_file} = 1;
        }

        $numFiles++;
        $orig_mon_dir = dirname($orig_mon_file);
        if ($orig_mon_dir eq "") {
            $orig_mon_dir = ".";
        }
        $gMon_file = find_file($orig_mon_file); # test.cpp -> ../test.cpp (-s ..)  test.cpp -> test.cpp (not found)  .\test.cpp -> ../.\test.cpp (-s ..)
        if (defined $gOption_s_used) {
            undef $gOption_s_used;
            $orig_mon_file = $gOption_s_file;
            $orig_mon_dir = $gOption_s_dir;
        }
        @normalized = getNormalized($gMon_file);
        $gMon_file = $normalized[0]; # (in Win) ../test.cpp -> ..\test.cpp  test.cpp -> .\test.cpp  ../.\test.cpp -> ..\test.cpp
        $aMon_dir = $normalized[1];  # .. or .
        $Mon_sh_fullline = $Mon_sh_prefix . $gMon_file;

        $original{$gMon_file} = $orig_mon_file;
        if (not defined $original_dir{$aMon_dir}) {
            $original_dir{$aMon_dir} = $orig_mon_dir;
        }
        if (not -e stripSecondCopySuffix(openName($gMon_file))) {
            if (not defined $file_not_found{$gMon_file}) {
                $file_not_found{$gMon_file} = 1; # .\test.cpp
            }
        }
        if (not defined $directory_filecount{$aMon_dir}) {
            $directory_filecount{$aMon_dir} = 1;
        } else {
            $directory_filecount{$aMon_dir}++;
        }
        $_ = $Mon_sh_fullline;
    }

    elsif (/^\s*\d+( |\^|v)(           |\(not avail\)|\(different\))( |-)\s+\d+\s*FUNCTION .+/) {
        # a FUNCTION begins in the profile list
        $gMon_function = $_;
        $gMon_function = replaceEntity($gMon_function);
        #17.3.2020 I do not understand. Why can't have TER line later??
        #(only if is "-i f" instrumented or report taken by "-ff" view...)
        $numFunctions2++; # function coverage report not having ***TER ...of FUNCTION
    }
 
    elsif (/^(.+#line \d+ \")(.+)\"/ or /^(#include \")(.+)\"/) {
        # 7 #line 1 "c:\users\jorma\koe2\header.h"
        # 5 #line 8 "koe1.cpp"
        # #include "c:\users\jorma.testwell2003\devel\ctc_xml\ctcxml\test1\header.h"
        $_ = $1;
        $orig_linedir_file = $2;
        $aLinedir_file = find_file($orig_linedir_file); # koe1.cpp -> ../koe1.cpp (-s ..)  koe1.cpp -> koe1.cpp (not found)
        if (defined $gOption_s_used) {
            undef $gOption_s_used;
            $orig_linedir_file = $gOption_s_file;
        }
        @normalized = getNormalized($aLinedir_file);
        $aLinedir_file = $normalized[0]; # ..\koe1.cpp or koe1.cpp -> .\koe1.cpp
        $_ .= $aLinedir_file . '"';
        if (not defined $original{$aLinedir_file}) {
            $original{$aLinedir_file} = $orig_linedir_file;
        }
        if (not -e $aLinedir_file) {
            if (not defined $file_not_found{$aLinedir_file}) {
                $file_not_found{$aLinedir_file} = 1; # .\koe1.cpp
            }
        }
    }

    elsif (/^\*\*\*TER\s+\d+ % \((\[.+\]|)\s*\d+\/\s*\d+\) of FUNCTION .+/) {
        $gTer_of_function = 1;
        $numFunctions++;
    }

    elsif (/^\s+(N\.A\. statement)/) {
        $gTer_of_function = 0;
        $no_linecov{$gMon_function} = 0;
    }

    elsif (/^(\*\*\*)(TER\s+\d+ % \(\s*(\[.+\]|)\s*\d+.*\/\s*\d+\))( of FILE ).+/) {
        $gTer_of_source = 1;  #FIXME
        $_ = $1 . $2. $4 . $gMon_file;
        $mon_file_ter = $2;
        $source_ter{$gMon_file} = $mon_file_ter;
        if ($mon_file_ter =! /^TER\s+100/) { 
            $numUntestedFiles++;
        }
    }

    elsif (/^\s+(\d+ % \(\s*\d+\/\s*\d+\) statement \(N\.A\. for \d+ functions\))/)
    { # 100 % (  0/  0) statement (N.A. for 2 functions)
        $gTer_of_source = 0;
        $source_ter_stmt{$gMon_file} = $1;
    }

    elsif (/^\s+(\d+ % \(\s*\d+\/\s*\d+\) statement)/) {
        if ($gTer_of_source == 1) {
            $gTer_of_source = 0;
            $source_ter_stmt{$gMon_file} = $1;
        } else {
            $gTer_of_function = 0;
        }
    }
#new in future
    #elsif (/^Functions\s+: (.+)/) {
    #    $numFunctions = $1;
    #}
#end in future    
    elsif (/^TER .+: .+ statement.*/)
    { # 100 % (10/10) statement (N.A. for 3 functions) or
      # 100 % (0/0) statement
        ;
    }

    elsif (/^TER .+: \d+ % \(\d+\/\d+\)(.*)/ ||
	   /^TER .+: \d+ % \(.*\d+\/\d+\)(.*)/)
    { # 59 % (30/51) MC/DC or 100 % (0/0) or 
      # mixed multicondition/function or mixed MC/DC/function ...
        $shown_coverage_views = $1;
        $shown_coverage_views =~ s/^\s(.*)/$1/;     #MC/DC
        $shown_coverage_views =~ s/^mixed (.+)/$1/; #multicondition/function or MC/DC/function
    }

    print PROFILETMP1 $_ . "\n";
}


##########################################################################
# SUBROUTINE: compare_pathnames
# PURPOSE   : Used as comparision function for sorting pathnames. If one
#             just sorts lexically sub directories and similar named files
#             are not grouped correctly.
#
#             Wrong:            topdir\fa.txt
#                               topdir\fb\file2.txt
#                               topdir\fc.txt
#                               .\zzzotherdir\file.txt
#
#             Correct:          .\zzzotherdir\file.txt
#                               topdir\fa.txt
#                               topdir\fc.txt
#                               topdir\fb\file2.txt
##########################################################################
sub compare_pathnames
{
    my @parts_a = split(/\\|\//, $a);
    my @parts_b = split(/\\|\//, $b);

    # special handling of "." current directory
    my $result = ($parts_b[0] =~ m/./) <=> ($parts_a[0] =~ m/./);
    if($result) {
        return $result;
    }

    # One path name might contain more sub directories
    my $parts;
    if($#parts_a == $#parts_b) {
        $parts = scalar @parts_a;
    } else {
        $parts = (scalar @parts_a < scalar @parts_b ? scalar @parts_a : scalar @parts_b) - 1;
    }

    # first compare directory parts only
    foreach (my $i = 0; $i < $parts; $i++) {
        $result = $parts_a[$i] cmp $parts_b[$i];
        if($result) {
            last;
        }
    }

    if($result == 0) {
        # no difference found? -> check for different directory depth
        # Show shorter first
        $result = scalar @parts_a <=> scalar @parts_b;
    }

    return $result;
}

##########################################################################
# SUBROUTINE: sortProfileListing
# PURPOSE   : copy unsorted Profile Listing 1 to sorted Profile Listing 2
#             to be used as new INPUT. 
##########################################################################
sub sortProfileListing
{
    open(PROFILETMP1, "<$html_dir/$tmp_profilefile1")
        or die "ctc2html: Cannot open file $html_dir/$tmp_profilefile1\n";

    my $position;
    my $current_info = {
        start => 0,
        file_key => "header",
        contents => "",
        end => 0 };
    my %all_infos = ();

    my %header_info = ();
    my %footer_info = ();

    my $header_read = 0;

    my $dir_id = 0;

    while(<PROFILETMP1>) {
        $position = tell(PROFILETMP1);
        if (/^MONITORED .+ FILE : (.+)(\n)/) {
            $dir_id++;
            print STDERR $dir_id . " ";
            $$current_info{end} = $position;
            if( $header_read) {
                $all_infos{$$current_info{file_key}} = $current_info;
            } else {
                $header_read = 1;
                %header_info = %$current_info;
            }

            $current_info = {
                start => $position,
                file_key => $1,
                contents => $_,
                end => 0 };
        } elsif (/^SUMMARY/) {
            $$current_info{end} = $position;
            $all_infos{$$current_info{file_key}} = $current_info;

            $current_info = {
                start => $position,
                file_key => "summary",
                contents => $_,
                end => 0 };
        } else {
            $$current_info{contents} .= $_;
        }
    }
    close PROFILETMP1;

    $$current_info{end} = 9999;
    %footer_info = %$current_info;

    # Write sorted temp file
    print(PROFILETMP2 "$header_info{contents}");

    my $key;
    foreach $key (sort compare_pathnames keys %all_infos) {
        my $info_ref = $all_infos{$key};
        my %info = %$info_ref;
        print(PROFILETMP2 "$info{contents}");
    }

    print( PROFILETMP2 "$footer_info{contents}");

    # Fill %basenames for later use
    my $base_name;
    my $file_id = 0;
    foreach $key (sort compare_pathnames keys %all_infos) {
        $file_id++;
        $base_name = basename($key);
        $base_name = utf8it($base_name);
        $basenames{$file_id} = $base_name;
    }
}

##########################################################################
# SUBROUTINE: find_file
# PURPOSE   : search given file from additional source directories.
# ARGUMENTS : - $path_name = name of the searched file with path
# RETURNS   : - full path to the file (file found or file not found)
##########################################################################
sub find_file
{
    my ($path_name) = @_;
    my ($file_name, $tmp, $source_dir);
    my $index = 0;

    if (-e openName($path_name)) {
        return $path_name; # foo/src/bar.c (file found)
    }
    $file_name = $path_name; # foo/src/bar.c  .\src\stsys_strtrmp.c
    $file_name =~ s/^\.[\/\\](.+)/$1/; # src\stsys_strtrmp.c

    while ($index <= $#source_dirs) {
        $source_dir = $source_dirs[$index]; # -s ../topdir
        $source_dir =~ s/(.+)[\/\\]$/$1/;
        if ($^O eq "MSWin32") { # Windows
            $tmp = $source_dir . "\\" . $file_name;
        } else { # hpux, solaris or linux
            $tmp = $source_dir . "/" . $file_name;
        }
        if (-e openName($tmp)) {
            $gOption_s_used = 1;
            $gOption_s_file = $tmp; # ../topdir/foo/src/bar.c
            $gOption_s_dir = $tmp;
            $gOption_s_dir =~ s/(.+[\/\\]).*/$1/; # ../topdir/foo/src/
            $gOption_s_dir =~ s/(.+)[\/\\]$/$1/;  # ../topdir/foo/src
            return $tmp; # ../topdir/foo/src/bar.c (file found)
        }
        $index++;
    }

    if ($path_name =~ /.*[\/\\](.*)/) {
        $file_name = $1; # bar.c
        $index = 0;
        while ($index <= $#source_dirs) {
            $source_dir = $source_dirs[$index]; # -s ../topdir
            $source_dir =~ s/(.+)[\/\\]$/$1/;
            if ($^O eq "MSWin32") { # Windows
                $tmp = $source_dir . "\\" . $file_name;
            } else { # hpux, solaris or linux
                $tmp = $source_dir . "/" . $file_name;
            }
            if (-e openName($tmp)) {
                $gOption_s_used = 1;
                $gOption_s_file = $tmp; # ../topdir/bar.c
                $gOption_s_dir = $tmp;
                $gOption_s_dir =~ s/(.+[\/\\]).*/$1/; # ../topdir/
                $gOption_s_dir =~ s/(.+)[\/\\]$/$1/;  # ../topdir
                return $tmp; # ../topdir/bar.c (file found)
            }
            $index++;
        }
    }
    return $path_name; # foo/src/bar.c (file not found)
}

##########################################################################
# SUBROUTINE: getNormalized
# PURPOSE   : 
##########################################################################
sub getNormalized
{
    my ($mon_file) = @_;
    my $mon_dir = "";
    my @normalized = ();

    if ($^O eq "MSWin32") { # Windows
        $mon_file = lc $mon_file;         # to lower case
        $mon_file =~ s/\//\\/g;           # "/" -> "\"

        if ($mon_file =~ /^\./) {
            $mon_dir = dirname($mon_file); # ., .., .\source
        }
        elsif ($mon_file =~ /^\\\\/) {
            $mon_dir = dirname($mon_file); # \\server2\share\source
        }
        elsif ($mon_file =~ /^\\/) {
            $mon_dir = dirname($mon_file); # \, \source
        }
        elsif ($mon_file =~ /^.{1}:/) {
            $mon_dir = dirname($mon_file); # C:\source
        }
        else {
            $mon_file = ".\\$mon_file";
            $mon_dir = dirname($mon_file); # .
        }
    }
    else { # Linux/Unix
        if ($mon_file =~ /^\./) {
            $mon_dir = dirname($mon_file); # ., .., ./source
        }
        elsif ($mon_file =~ /^\//) {
            $mon_dir = dirname($mon_file); # /home/tw/source
        }
        else {
            $mon_file = "./$mon_file";
            $mon_dir = dirname($mon_file); # .
        }
    }

    if ($mon_file =~ /(.*[\/\\])\.[\/\\](.+)/) { # ..\.\cube.cpp
        $mon_file = $1 . $2; # ..\cube.cpp
    }
    if ($mon_dir =~ /(.*)[\/\\]\.$/) { # ..\.
        $mon_dir = $1; # ..
    }
    $normalized[0] = $mon_file;
    $normalized[1] = $mon_dir;
    return @normalized;
}

##########################################################################
# SUBROUTINE: setDirData
# PURPOSE   : 
##########################################################################
sub setDirData
{
    my $numTotal = 0;
    my $key;
    my $dir_id = 0;
    my $current_dir = "";

    $numDirectories = scalar keys %directory_filecount;

    if ($numFunctions > 0) {
        $numTotal = $numFiles + $numFunctions;
    } else {
        $numTotal = $numFiles + $numFunctions2;
    }
#new in future
    #$numTotal = $numFiles + $numFunctions;
#end in future    
    if ($numTotal > $limit_index) {
        undef $gVerboseIndex;
        $verboseIndexDescr = "(Limited to show files only)";
    }

    foreach $key (sort keys %directory_filecount) {
        $dir_id++;
        $directory_id_filecount{$dir_id} = $directory_filecount{$key};
        $current_dir = $original_dir{$key};
        $current_dir = utf8it($current_dir);
        $directories{$dir_id} = $current_dir;
    }
}

##########################################################################
# SUBROUTINE: appendSymDir
# PURPOSE   : Append the symbol file's directory to the set of directories
#             where the original source files are to be searched
##########################################################################
sub appendSymDir
{
    my ($dir) = @_;
    my $pos = rindex $dir, '(';
    my $found = 0;

    $dir = dirname(substr $dir, 0, $pos - 1);

    if ($dir eq "") {
        $dir = ".";
    }

    if (defined $gIn_symbol_files) {
        for ($i = 0; $i <= $#source_dirs; $i++) {
            if ($dir eq $source_dirs[$i]) {
                $found = 1;
                last;
            }
        }
        if (not $found) {
            push(@source_dirs, $dir); # "New" directory
        }
    }
}

##########################################################################
# SUBROUTINE: setReducedTo
# PURPOSE   : 
##########################################################################
sub setReducedTo
{
    my $reduced_view = "";
    my $instrumentation_mode = $gInstrumentationMode;

    if ($instrumentation_mode =~ /(.+)\+inclusive_timing/ or
        $instrumentation_mode =~ /(.+)\+exclusive_timing/)
    {
        $instrumentation_mode = $1;
    }

    # multicondition/condition coverage
    if ($instrumentation_mode eq "multicondition" &&
        $gCoverageView eq "Reduced to MC/DC coverage")
    {
        $reduced_view = "MC/DC coverage";
        $file_coverage_view = "MC/DC";
    }

    elsif ($instrumentation_mode eq "multicondition" &&
           $gCoverageView eq "Reduced to condition coverage")
    {
        $reduced_view = "condition coverage";
        $file_coverage_view = "condition";
    }

    elsif ($instrumentation_mode eq "multicondition" &&
           $gCoverageView eq "Reduced to decision coverage")
    {
        $reduced_view = "decision coverage";
        $file_coverage_view = "decision";
    }

    elsif ($instrumentation_mode eq "multicondition" &&
           $gCoverageView eq "Reduced to function coverage")
    {
        $reduced_view = "function coverage";
        $file_coverage_view = "function";
    }

    # decision coverage
    elsif ($instrumentation_mode eq "decision" &&
           $gCoverageView eq "Reduced to function coverage")
    {
        $reduced_view = "function coverage";
        $file_coverage_view = "function";
    }

    else {
        $file_coverage_view = $instrumentation_mode;
    }

    if ($reduced_view ne "") {
        $reduced_to = "<span class=\"indent\"></span>".
                      "<span class=\"infob\">Reduced to:</span>".
                      "<span class=\"info\">$reduced_view</span>";
    } else {
        $reduced_to = "";
    }
}

##########################################################################
# SUBROUTINE: setFileTer
# PURPOSE   : 
##########################################################################
sub setFileTer
{
    my ($structcolor, $stmtcolor);
    my ($ter_struct, $ter_stmt);

    $gFile_ter_struct_procent =~ /^TER\s+(\d+) % \((\[.+\]|)\s*(\d+)\/\s*(\d+)\)/;
    $ter_struct = "$1 % ".toArrowShort($3,$2,$4)." structural";
    if (defined $statement_coverage) {
        $ter_struct .= ",";
    }

    if ($1 < $threshold) {
        $structcolor = "below";
    } else {
        $structcolor = "above";
    }

    $gFile_ter_stmt_procent =~ /^(\d+) % \(\s*(\d+)\/\s*(\d+)\) (statement.*)/;
    $ter_stmt = "$1 % ($2/$3) $4";
    if ($1 < $stmtthreshold) {
        $stmtcolor = "below";
    } else {
        $stmtcolor = "above";
    }

    $gFile_ter_procent = "<span class=\"$structcolor\">$ter_struct</span>";
    if (defined $statement_coverage) {
        $gFile_ter_procent .= "<span class=\"$stmtcolor\">$ter_stmt</span>";
    }
}

##########################################################################
# SUBROUTINE: isWindows
# PURPOSE   : Concludes if the platform is Windows or UNIX
# ARGUMENTS : none
# RETURNS   : - true  1 if seems to be Windows
#             - false 0 if seems not to be Windows
##########################################################################
sub isWindows
{
    if ($^O eq "MSWin32") {
        return 1;
    } else { # linux, unix, cygwin etc.
        return 0;
    }
}

##########################################################################
# SUBROUTINE: isMacOS
# PURPOSE   : Concludes if the platform is macOS
# ARGUMENTS : none
# RETURNS   : - true  1 if seems to be macOS
#             - false 0 if seems not to be Windows
##########################################################################
sub isMacOS
{
    if ($^O eq "darwin") {
        return 1;
    } else { # linux, unix, cygwin etc.
        return 0;
    }
}

##########################################################################
# SUBROUTINE: start_browsing
# PURPOSE   : check if to start browsing (only in MsWindows env.)
# ARGUMENTS : -
# RETURNS   : -
##########################################################################
sub start_browsing
{
    # MsWindows only:
    # call "launch_browser()" to start browsing automatically
    if ($start_browsing) {
	if (isWindows()) {
	    launch_browser();
	} elsif (isMacOS()) {
	    launch_browser_macos();
	} else {
	    launch_browser_xdg();
	}
    }
}

##########################################################################
# SUBROUTINE: launch_browser
# PURPOSE   : automatically launch html-browser
#             (should be called only in MsWindows env.)
# ARGUMENTS : -
# RETURNS   : -
##########################################################################
sub launch_browser
{
    print STDERR "Starting browser...\n";

    my $tobestarted = 'start "" "' . "$html_dir\\$prefix$postfix" . '"';

    # for Wine usage
    if (defined $ENV{DISPLAY} && defined $ENV{winsysdir} &&
            -f $ENV{winsysdir} . "\\winebrowser.exe") {
        $tobestarted = "winebrowser " . $tobestarted;
    }

    my $value = system($tobestarted);

    if ($value == 0 || $value == 256) {
        return;
    } else {
        print STDERR <<"END";
ctc2html: Seems like the starting of the .html file browsing did not succeed.
Please start the '$html_dir\\$prefix$postfix' file explicitly by your browser.
END
    }
}

##########################################################################
# SUBROUTINE: launch_browser_macos
# PURPOSE   : automatically launch html-browser
#             (should be called only in macOS env.)
# ARGUMENTS : -
# RETURNS   : -
##########################################################################
sub launch_browser_macos
{
    print STDERR "Starting browser...\n";

    my $tobestarted = '"/usr/bin/open ' . "$html_dir/$prefix$postfix" . '"';

    my $value = system("open", "$html_dir/$prefix$postfix");

    if ($value == 0 || $value == 256) {
        return;
    } else {
        print STDERR <<"END";
ctc2html: Seems like the starting of the .html file browsing did not succeed.
Please start the '$html_dir/$prefix$postfix' file explicitly by your browser.
END
    }
}

##########################################################################
# SUBROUTINE: launch_browser_xdg
# PURPOSE   : automatically launch html-browser
#             (should be called only in X-Windows env.)
# ARGUMENTS : -
# RETURNS   : -
# NOTE      : Requires xdg-open from xdg-utils
##########################################################################
sub launch_browser_xdg
{
    my $cmd = "xdg-open";
    my $bg = "";

    if (defined $ENV{DISPLAY} && length $ENV{DISPLAY}) {
	unless (defined(which($cmd))) {
	    if (-f "/etc/alternatives/x-www-browser") {
		$cmd = "/etc/alternatives/x-www-browser";
	    } elsif (defined(which("firefox"))) {
		$cmd="firefox";
		$bg="&";
	    } elsif (defined(which("google-chrome"))) {
		$cmd="google-chrome";
		$bg="&";
	    } elsif (defined(which("opera"))) {
		$cmd="opera";
		$bg="&";
	    }
	}
    } else {
	# No X-Windows (only elinks and w3m, lynx unwilling 
	if (-f "/etc/alternatives/www-browser" &&
	    -l "/etc/alternatives/www-browser" && 
	    defined (readlink("/etc/alternatives/www-browser")) && 
	    basename(readlink("/etc/alternatives/www-browser")) ne "lynx") {
	    $cmd = readlink "/etc/alternatives/www-browser";
	} elsif (defined(which("elinks"))) {
	    $cmd="elinks";
	} elsif (defined(which("w3m"))) {
	    $cmd="w3m";
	}
	return;  # Not starting if no $DISPLAY
    }
    
    print STDERR "Starting browser...\n";

    my $tobestarted = "$cmd \"$html_dir/$prefix$postfix\" $bg";

    my $value = system($tobestarted);
    
    if ($value == 0 || $value == 256) {
        return;
    } else {
        print STDERR <<"END";
ctc2html: Seems like the starting of the .html file browsing did not succeed.
Do you have xdg-open (comes with xdg-utils) installed?
Please start the '$html_dir/$prefix$postfix' file explicitly by your browser.
END
    }
}

##########################################################################
# SUBROUTINE: create_gif
# PURPOSE   : create the gif's
##########################################################################
sub create_gif
{
    open(RED, ">$html_dir/red.gif")
        or die "ctc2html: Cannot create file $html_dir/red.gif\n";
    binmode RED;
    print RED map(chr, @gif_header);
    print RED map(chr, @gif_red);
    close RED;

    open(BLUE, ">$html_dir/blue.gif")
        or die "ctc2html: Cannot create file $html_dir/blue.gif\n";
    binmode BLUE;
    print BLUE map(chr, @gif_header);
    print BLUE map(chr, @gif_blue);
    close BLUE;

    open(YELLOW, ">$html_dir/yellow.gif")
        or die "ctc2html: Cannot create file $html_dir/yellow.gif\n";
    binmode YELLOW;
    print YELLOW map(chr, @gif_header);
    print YELLOW map(chr, @gif_yellow);
    close YELLOW;

    open(WHITE, ">$html_dir/white.gif")
        or die "ctc2html: Cannot create file $html_dir/white.gif\n";
    binmode WHITE;
    print WHITE map(chr, @gif_header);
    print WHITE map(chr, @gif_white);
    close WHITE;
}

##########################################################################
# SUBROUTINE: create_stylesheet
# PURPOSE   : create or copy the stylesheet file
##########################################################################
sub create_stylesheet
{
    open(STYLESHEET, ">$html_dir/ctc.css")
        or die "ctc2html: Cannot create file $html_dir/ctc.css\n";
    if (defined $own_stylesheet) {
        # open stylesheet cssfile for input
        open(OWNSTYLE, "<$own_stylesheet")
            or die "ctc2html: Cannot open file $own_stylesheet\n";
        # Copy stylesheet (e.g. ctc.css) of $CTCHOME...
        print STYLESHEET $copied_style_info;
        while(<OWNSTYLE>) {
            print STYLESHEET;
        }
        close OWNSTYLE;
    } else {
        # No stylesheet (e.g. ctc.css) found in $CTCHOME...
        print STYLESHEET $style_info;
    }
    close STYLESHEET;
}

##########################################################################
# SUBROUTINE: create_script
# PURPOSE   : create the script files
##########################################################################
sub create_script
{
    if (defined $javascript) {
        create_javascript();
        create_sorttable();
        # user's own javascript file is available
        if (defined $own_javascript) {
            create_own_javascript();
        } else {
            create_own_javascript_NA();
        }
        $script_info = <<"END";
<script src="ctc.js" type="text/javascript"></script>
<script src="sorttable.js" type="text/javascript"></script>
<script src="own_javascript.js" type="text/javascript"></script>
END
        $onLoad_profile  = " onLoad=\"load_profile(); return false;\"";
        $onLoad_funcs    = " onLoad=\"load_funcs(); return false;\"";
        $onLoad_untested = " onLoad=\"load_untested(); return false;\"";
    }
}

##########################################################################
# SUBROUTINE: create_javascript
# PURPOSE   : create the javascript file
#             (unless option --disable-javascript is given)
##########################################################################
sub create_javascript
{
    my ($sub, $sub2);

    open(JAVASCRIPT, ">$html_dir/ctc.js")
        or die "ctc2html: Cannot create file $html_dir/ctc.js\n";
    print JAVASCRIPT <<"END";
/////////////////////////////////////////////////////////////////////////
// Javascript file generated by $version at $time_stamp
// Copyright (c) 2006-2013 Testwell Oy
// Copyright (c) 2013-2016 Verifysoft Technology GmbH
/////////////////////////////////////////////////////////////////////////
target=location.hash;

function highlight(row, a, b) {
   var cl;
   var cells;
   row.style.cursor = 'pointer';
   if (row.tagName != "TR") {
      row = row.parentNode;
      if (row.tagName != "TR") {
         row = row.parentNode;
      }
   }
   cells = row.parentNode.rows[row.rowIndex - a - 1].getElementsByTagName("td");
   for (var i = 0; i < cells.length; i++) {
      cl = cells[i].getAttribute("class");
      if (cl != null) {
         cells[i].setAttribute("class", cl.replace(/profile/, "highlight"));
      } else {
	 cl = cells[i].getAttribute("className");
	 if (cl != null) {
	     cells[i].setAttribute("className", cl.replace(/profile/, "highlight"));
	 }
      }
   }
   cells = row.parentNode.rows[row.rowIndex - b - 1].getElementsByTagName("td");
   for (var i = 0; i < cells.length; i++) {
      cl = cells[i].getAttribute("class");
      if (cl != null) {
         cells[i].setAttribute("class", cl.replace(/profile/, "highlight"));
      } else {
	 cl = cells[i].getAttribute("className");
	 if (cl != null) {
	     cells[i].setAttribute("className", cl.replace(/profile/, "highlight"));
	 }
      }
   }
   cells = row.parentNode.rows[row.rowIndex - a - 1].getElementsByTagName("span");
   for (var i = 0; i < cells.length; i++) {
      cl = cells[0].getAttribute("class");
      if (cl != null) {
         cells[0].setAttribute("class", cl.replace(/profile/, "highlight"));
      } else {
	 cl = cells[0].getAttribute("className");
	 if (cl != null) {
	     cells[0].setAttribute("className", cl.replace(/profile/, "highlight"));
	 }
      }
   }
   cells = row.parentNode.rows[row.rowIndex - b - 1].getElementsByTagName("span");
   for (var i = 0; i < cells.length; i++) {
      cl = cells[0].getAttribute("class");
      if (cl != null) {
         cells[0].setAttribute("class", cl.replace(/profile/, "highlight"));
      } else {
	 cl = cells[0].getAttribute("className");
	 if (cl != null) {
	     cells[0].setAttribute("className", cl.replace(/profile/, "highlight"));
	 }
      }
   }
}

function unhighlight(row, a, b) {
   var cl;
   var cells;
   if (row.tagName != "TR") {
      row = row.parentNode;
      if (row.tagName != "TR") {
         row = row.parentNode;
      }
   }
   cells = row.parentNode.rows[row.rowIndex - a - 1].getElementsByTagName("td");
   for (var i = 0; i < cells.length; i++) {
      cl = cells[i].getAttribute("class");
      if (cl != null) {
         cells[i].setAttribute("class", cl.replace(/highlight/, "profile"));
      } else {
	 cl = cells[i].getAttribute("className");
	 if (cl != null) {
	     cells[i].setAttribute("className", cl.replace(/highlight/, "profile"));
	 }
      }
   }
   cells = row.parentNode.rows[row.rowIndex - b - 1].getElementsByTagName("td");
   for (var i = 0; i < cells.length; i++) {
      cl = cells[i].getAttribute("class");
      if (cl != null) {
         cells[i].setAttribute("class", cl.replace(/highlight/, "profile"));
      } else {
	 cl = cells[i].getAttribute("className");
	 if (cl != null) {
	     cells[i].setAttribute("className", cl.replace(/highlight/, "profile"));
	 }
      }
   }
   cells = row.parentNode.rows[row.rowIndex - a - 1].getElementsByTagName("span");
   for (var i = 0; i < cells.length; i++) {
      cl = cells[i].getAttribute("class");
      if (cl != null) {
         cells[0].setAttribute("class", cl.replace(/highlight/, "profile"));
      } else {
	 cl = cells[0].getAttribute("className");
	 if (cl != null) {
	     cells[0].setAttribute("className", cl.replace(/highlight/, "profile"));
	 }
      }
   }
   cells = row.parentNode.rows[row.rowIndex - b - 1].getElementsByTagName("span");
   for (var i = 0; i < cells.length; i++) {
      cl = cells[i].getAttribute("class");
      if (cl != null) {
         cells[0].setAttribute("class", cl.replace(/highlight/, "profile"));
      } else {
	 cl = cells[0].getAttribute("className");
	 if (cl != null) {
	     cells[0].setAttribute("className", cl.replace(/highlight/, "profile"));
	 }
      }
   }
}

function load_profile() {
END
    for ($sub = 1; $sub <= $numFiles; $sub++) {
        print JAVASCRIPT <<"END";
   if (target == "#a$sub") {
      parent.index_profile.location = "$index_profile_html#a$sub";
      parent.profile.location = "$profile_html{$sub}";
   }
END
    }

    print JAVASCRIPT <<"END";
}

function load_funcs() {
END
    for ($sub = 1; $sub <= $numDirectories; $sub++) {
        for ($sub2 = 1; $sub2 <= $directory_id_filecount{$sub}; $sub2++) {
            print JAVASCRIPT <<"END"; 
   if (target == "#ad$sub") {
      parent.index_funcs.location = "$index_funcs_html#ad$sub";
      parent.functions.location = "$funcs_html{$sub}";
   }
END
        }
    }

    print JAVASCRIPT <<"END";
}

function load_untested() {
END
    for ($sub = 1; $sub <= $numUntestedFiles; $sub++) {
        print JAVASCRIPT <<"END";
   if (target == "#ufi$sub") {
      parent.index_untested.location = "$index_untested_html#ufi$sub";
      parent.untested.location = "$untested_html";
   }
END
    }

    print JAVASCRIPT <<"END";
}
END
    close JAVASCRIPT;
}

##########################################################################
# SUBROUTINE: create_own_javascript
# PURPOSE   : create the user's own javascript file
#             (unless option --disable-javascript is given)
##########################################################################
sub create_own_javascript
{
    open(JAVASCRIPT, ">$html_dir/own_javascript.js")
        or die "ctc2html: Cannot create file $html_dir/own_javascript.js\n";
    # open javascript jsfile for input
    open(OWNJAVA, "<$own_javascript")
        or die "ctc2html: Cannot open file $own_javascript\n";
    # Copy javascript (e.g. ctc.js) of $CTCHOME...
    print JAVASCRIPT <<"END";
/////////////////////////////////////////////////////////////////////////
// Javascript file generated by $version at $time_stamp
// Copyright (c) 2006-2013 Testwell Oy
// Copyright (c) 2013-2016 Verifysoft Technology GmbH
/////////////////////////////////////////////////////////////////////////
// Javascript file copied from $own_javascript to own_javascript.js

END
    while(<OWNJAVA>) {
        print JAVASCRIPT;
    }
    close OWNJAVA;
    close JAVASCRIPT;
}

##########################################################################
# SUBROUTINE: create_own_javascript_NA
# PURPOSE   : create the user's own empty javascript file if N.A.
#             (unless option --disable-javascript is given)
##########################################################################
sub create_own_javascript_NA
{
    open(JAVASCRIPT, ">$html_dir/own_javascript.js")
        or die "ctc2html: Cannot create file $html_dir/own_javascript.js\n";
    # print own empty javascript file
    print JAVASCRIPT <<"END";
/////////////////////////////////////////////////////////////////////////
// Javascript file generated by $version at $time_stamp
// Copyright (c) 2006-2013 Testwell Oy
// Copyright (c) 2013-2016 Verifysoft Technology GmbH
/////////////////////////////////////////////////////////////////////////
// User's own Javascript file

END
    close JAVASCRIPT;
}

##########################################################################
# SUBROUTINE: create_sorttable
# PURPOSE   : 
##########################################################################
sub create_sorttable
{
   open(JAVASCRIPT, ">$html_dir/sorttable.js")
      or die "ctc2html: Cannot create file $html_dir/sorttable.js\n";
   print JAVASCRIPT <<"END";
/*
  SortTable
  version 2
  7th April 2007
  Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/
  
  Instructions:
  Download this file
  Add <script src="sorttable.js"></script> to your HTML
  Add class="sortable" to any table you'd like to make sortable
  Click on the headers to sort
  
  Thanks to many, many people for contributions and suggestions.
  Licenced as X11: http://www.kryogenix.org/code/browser/licence.html
  This basically means: do what you want with it.
*/

 
var stIsIE = /*\@cc_on!\@*/false;

sorttable = {
  init: function() {
    // quit if this function has already been called
    if (arguments.callee.done) return;
    // flag this function so we don't do the same thing twice
    arguments.callee.done = true;
    // kill the timer
    if (_timer) clearInterval(_timer);
    
    if (!document.createElement || !document.getElementsByTagName) return;
    
    sorttable.DATE_RE = /^(\\d\\d?)[\\\/\\.-](\\d\\d?)[\\\/\\.-]((\\d\\d)?\\d\\d)\$\/;
    
    forEach(document.getElementsByTagName('table'), function(table) {
      if (table.className.search(/\\bsortable\\b/) != -1) {
        sorttable.makeSortable(table);
      }
    });
    
  },
  
  makeSortable: function(table) {
    if (table.getElementsByTagName('thead').length == 0) {
      // table doesn't have a tHead. Since it should have, create one and
      // put the first table row in it.
      the = document.createElement('thead');
      the.appendChild(table.rows[0]);
      table.insertBefore(the,table.firstChild);
    }
    // Safari doesn't support table.tHead, sigh
    if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0];
    
    if (table.tHead.rows.length != 1) return; // can't cope with two header rows
    
    // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
    // "total" rows, for example). This is B&R, since what you're supposed
    // to do is put them in a tfoot. So, if there are sortbottom rows,
    // for backwards compatibility, move them to tfoot (creating it if needed).
    sortbottomrows = [];
    for (var i=0; i<table.rows.length; i++) {
      if (table.rows[i].className.search(/\\bsortbottom\\b/) != -1) {
        sortbottomrows[sortbottomrows.length] = table.rows[i];
      }
    }
    if (sortbottomrows) {
      if (table.tFoot == null) {
        // table doesn't have a tfoot. Create one.
        tfo = document.createElement('tfoot');
        table.appendChild(tfo);
      }
      for (var i=0; i<sortbottomrows.length; i++) {
        tfo.appendChild(sortbottomrows[i]);
      }
      delete sortbottomrows;
    }
    
    // work through each column and calculate its type
    headrow = table.tHead.rows[0].cells;
    for (var i=0; i<headrow.length; i++) {
      // manually override the type with a sorttable_type attribute
      if (!headrow[i].className.match(/\\bsorttable_nosort\\b/)) { // skip this col
        mtch = headrow[i].className.match(/\\bsorttable_([a-z0-9]+)\\b/);
        if (mtch) { override = mtch[1]; }
	      if (mtch && typeof sorttable["sort_"+override] == 'function') {
	        headrow[i].sorttable_sortfunction = sorttable["sort_"+override];
	      } else {
	        headrow[i].sorttable_sortfunction = sorttable.guessType(table,i);
	      }
	      // make it clickable to sort
	      headrow[i].sorttable_columnindex = i;
	      headrow[i].sorttable_tbody = table.tBodies[0];
	      dean_addEvent(headrow[i],"click", function(e) {

          if (this.className.search(/\\bsorttable_sorted\\b/) != -1) {
            // if we're already sorted by this column, just 
            // reverse the table, which is quicker
            sorttable.reverse(this.sorttable_tbody);
            this.className = this.className.replace('sorttable_sorted',
                                                    'sorttable_sorted_reverse');
            this.removeChild(document.getElementById('sorttable_sortfwdind'));
            sortrevind = document.createElement('span');
            sortrevind.id = "sorttable_sortrevind";
            sortrevind.innerHTML = stIsIE ? '&nbsp<font face="webdings">5</font>' : '&nbsp;&#x25B4;';
            this.appendChild(sortrevind);
            return;
          }
          if (this.className.search(/\\bsorttable_sorted_reverse\\b/) != -1) {
            // if we're already sorted by this column in reverse, just 
            // re-reverse the table, which is quicker
            sorttable.reverse(this.sorttable_tbody);
            this.className = this.className.replace('sorttable_sorted_reverse',
                                                    'sorttable_sorted');
            this.removeChild(document.getElementById('sorttable_sortrevind'));
            sortfwdind = document.createElement('span');
            sortfwdind.id = "sorttable_sortfwdind";
            sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
            this.appendChild(sortfwdind);
            return;
          }
          
          // remove sorttable_sorted classes
          theadrow = this.parentNode;
          forEach(theadrow.childNodes, function(cell) {
            if (cell.nodeType == 1) { // an element
              cell.className = cell.className.replace('sorttable_sorted_reverse','');
              cell.className = cell.className.replace('sorttable_sorted','');
            }
          });
          sortfwdind = document.getElementById('sorttable_sortfwdind');
          if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); }
          sortrevind = document.getElementById('sorttable_sortrevind');
          if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); }
          
          this.className += ' sorttable_sorted';
          sortfwdind = document.createElement('span');
          sortfwdind.id = "sorttable_sortfwdind";
          sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
          this.appendChild(sortfwdind);

	        // build an array to sort. This is a Schwartzian transform thing,
	        // i.e., we "decorate" each row with the actual sort key,
	        // sort based on the sort keys, and then put the rows back in order
	        // which is a lot faster because you only do getInnerText once per row
	        row_array = [];
	        col = this.sorttable_columnindex;
	        rows = this.sorttable_tbody.rows;
	        for (var j=0; j<rows.length; j++) {
	          row_array[row_array.length] = [sorttable.getInnerText(rows[j].cells[col]), rows[j]];
	        }
	        /* If you want a stable sort, uncomment the following line */
	        //sorttable.shaker_sort(row_array, this.sorttable_sortfunction);
	        /* and comment out this one */
	        row_array.sort(this.sorttable_sortfunction);
	        
	        tb = this.sorttable_tbody;
	        for (var j=0; j<row_array.length; j++) {
	          tb.appendChild(row_array[j][1]);
	        }
	        
	        delete row_array;
	      });
	    }
    }
  },
  
  guessType: function(table, column) {
    // guess the type of a column based on its first non-blank row
    sortfn = sorttable.sort_alpha;
    for (var i=0; i<table.tBodies[0].rows.length; i++) {
      text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]);
      if (text != '') {
        if (text.match(/^-?[\\d,.]+%?\$\/)) {
          return sorttable.sort_numeric;
        }
        // check for a date: dd/mm/yyyy or dd/mm/yy 
        // can have / or . or - as separator
        // can be mm/dd as well
        possdate = text.match(sorttable.DATE_RE)
        if (possdate) {
          // looks like a date
          first = parseInt(possdate[1]);
          second = parseInt(possdate[2]);
          if (first > 12) {
            // definitely dd/mm
            return sorttable.sort_ddmm;
          } else if (second > 12) {
            return sorttable.sort_mmdd;
          } else {
            // looks like a date, but we can't tell which, so assume
            // that it's dd/mm (English imperialism!) and keep looking
            sortfn = sorttable.sort_ddmm;
          }
        }
      }
    }
    return sortfn;
  },
  
  getInnerText: function(node) {
    // gets the text we want to use for sorting for a cell.
    // strips leading and trailing whitespace.
    // this is *not* a generic getInnerText function; it's special to sorttable.
    // for example, you can override the cell text with a customkey attribute.
    // it also gets .value for <input> fields.
    
    hasInputs = (typeof node.getElementsByTagName == 'function') &&
                 node.getElementsByTagName('input').length;
    
    if (node.getAttribute("sorttable_customkey") != null) {
      return node.getAttribute("sorttable_customkey");
    }
    else if (typeof node.textContent != 'undefined' && !hasInputs) {
      return node.textContent.replace(/^\\s+|\\s+\$\/g, '');
    }
    else if (typeof node.innerText != 'undefined' && !hasInputs) {
      return node.innerText.replace(/^\\s+|\\s+\$\/g, '');
    }
    else if (typeof node.text != 'undefined' && !hasInputs) {
      return node.text.replace(/^\\s+|\\s+\$\/g, '');
    }
    else {
      switch (node.nodeType) {
        case 3:
          if (node.nodeName.toLowerCase() == 'input') {
            return node.value.replace(/^\\s+|\\s+\$\/g, '');
          }
        case 4:
          return node.nodeValue.replace(/^\\s+|\\s+\$\/g, '');
          break;
        case 1:
        case 11:
          var innerText = '';
          for (var i = 0; i < node.childNodes.length; i++) {
            innerText += sorttable.getInnerText(node.childNodes[i]);
          }
          return innerText.replace(/^\\s+|\\s+\$\/g, '');
          break;
        default:
          return '';
      }
    }
  },
  
  reverse: function(tbody) {
    // reverse the rows in a tbody
    newrows = [];
    for (var i=0; i<tbody.rows.length; i++) {
      newrows[newrows.length] = tbody.rows[i];
    }
    for (var i=newrows.length-1; i>=0; i--) {
       tbody.appendChild(newrows[i]);
    }
    delete newrows;
  },
  
  /* sort functions
     each sort function takes two parameters, a and b
     you are comparing a[0] and b[0] */
  sort_numeric: function(a,b) {
    aa = parseFloat(a[0].replace(/[^0-9.-]/g,''));
    if (isNaN(aa)) aa = 0;
    bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); 
    if (isNaN(bb)) bb = 0;
    return aa-bb;
  },
  sort_alpha: function(a,b) {
    if (a[0]==b[0]) return 0;
    if (a[0]<b[0]) return -1;
    return 1;
  },
  sort_ddmm: function(a,b) {
    mtch = a[0].match(sorttable.DATE_RE);
    y = mtch[3]; m = mtch[2]; d = mtch[1];
    if (m.length == 1) m = '0'+m;
    if (d.length == 1) d = '0'+d;
    dt1 = y+m+d;
    mtch = b[0].match(sorttable.DATE_RE);
    y = mtch[3]; m = mtch[2]; d = mtch[1];
    if (m.length == 1) m = '0'+m;
    if (d.length == 1) d = '0'+d;
    dt2 = y+m+d;
    if (dt1==dt2) return 0;
    if (dt1<dt2) return -1;
    return 1;
  },
  sort_mmdd: function(a,b) {
    mtch = a[0].match(sorttable.DATE_RE);
    y = mtch[3]; d = mtch[2]; m = mtch[1];
    if (m.length == 1) m = '0'+m;
    if (d.length == 1) d = '0'+d;
    dt1 = y+m+d;
    mtch = b[0].match(sorttable.DATE_RE);
    y = mtch[3]; d = mtch[2]; m = mtch[1];
    if (m.length == 1) m = '0'+m;
    if (d.length == 1) d = '0'+d;
    dt2 = y+m+d;
    if (dt1==dt2) return 0;
    if (dt1<dt2) return -1;
    return 1;
  },
  
  shaker_sort: function(list, comp_func) {
    // A stable sort function to allow multi-level sorting of data
    // see: http://en.wikipedia.org/wiki/Cocktail_sort
    // thanks to Joseph Nahmias
    var b = 0;
    var t = list.length - 1;
    var swap = true;

    while(swap) {
        swap = false;
        for(var i = b; i < t; ++i) {
            if ( comp_func(list[i], list[i+1]) > 0 ) {
                var q = list[i]; list[i] = list[i+1]; list[i+1] = q;
                swap = true;
            }
        } // for
        t--;

        if (!swap) break;

        for(var i = t; i > b; --i) {
            if ( comp_func(list[i], list[i-1]) < 0 ) {
                var q = list[i]; list[i] = list[i-1]; list[i-1] = q;
                swap = true;
            }
        } // for
        b++;

    } // while(swap)
  }  
}

/* ******************************************************************
   Supporting functions: bundled here to avoid depending on a library
   ****************************************************************** */

// Dean Edwards/Matthias Miller/John Resig

/* for Mozilla/Opera9 */
if (document.addEventListener) {
    document.addEventListener("DOMContentLoaded", sorttable.init, false);
}

/* for Internet Explorer */
/*\@cc_on \@*/
/*\@if (\@_win32)
    document.write("<script id=__ie_onload defer src=javascript:void(0)><\\/script>");
    var script = document.getElementById("__ie_onload");
    script.onreadystatechange = function() {
        if (this.readyState == "complete") {
            sorttable.init(); // call the onload handler
        }
    };
/*\@end \@*/

/* for Safari */
if (/WebKit/i.test(navigator.userAgent)) { // sniff
    var _timer = setInterval(function() {
        if (/loaded|complete/.test(document.readyState)) {
            sorttable.init(); // call the onload handler
        }
    }, 10);
}

/* for other browsers */
window.onload = sorttable.init;

// written by Dean Edwards, 2005
// with input from Tino Zijdel, Matthias Miller, Diego Perini

// http://dean.edwards.name/weblog/2005/10/add-event/

function dean_addEvent(element, type, handler) {
	if (element.addEventListener) {
		element.addEventListener(type, handler, false);
	} else {
		// assign each event handler a unique ID
		if (!handler.\$\$guid) handler.\$\$guid = dean_addEvent.guid++;
		// create a hash table of event types for the element
		if (!element.events) element.events = {};
		// create a hash table of event handlers for each element/event pair
		var handlers = element.events[type];
		if (!handlers) {
			handlers = element.events[type] = {};
			// store the existing event handler (if there is one)
			if (element["on" + type]) {
				handlers[0] = element["on" + type];
			}
		}
		// store the event handler in the hash table
		handlers[handler.\$\$guid] = handler;
		// assign a global event handler to do all the work
		element["on" + type] = handleEvent;
	}
};
// a counter used to create unique IDs
dean_addEvent.guid = 1;

function removeEvent(element, type, handler) {
	if (element.removeEventListener) {
		element.removeEventListener(type, handler, false);
	} else {
		// delete the event handler from the hash table
		if (element.events && element.events[type]) {
			delete element.events[type][handler.\$\$guid];
		}
	}
};

function handleEvent(event) {
	var returnValue = true;
	// grab the event object (IE uses a global event object)
	event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
	// get a reference to the hash table of event handlers
	var handlers = this.events[event.type];
	// execute each event handler
	for (var i in handlers) {
		this.\$\$handleEvent = handlers[i];
		if (this.\$\$handleEvent(event) === false) {
			returnValue = false;
		}
	}
	return returnValue;
};

function fixEvent(event) {
	// add W3C standard event methods
	event.preventDefault = fixEvent.preventDefault;
	event.stopPropagation = fixEvent.stopPropagation;
	return event;
};
fixEvent.preventDefault = function() {
	this.returnValue = false;
};
fixEvent.stopPropagation = function() {
  this.cancelBubble = true;
}

// Dean's forEach: http://dean.edwards.name/base/forEach.js
/*
	forEach, version 1.0
	Copyright 2006, Dean Edwards
	License: http://www.opensource.org/licenses/mit-license.php
*/

// array-like enumeration
if (!Array.forEach) { // mozilla already supports this
	Array.forEach = function(array, block, context) {
		for (var i = 0; i < array.length; i++) {
			block.call(context, array[i], i, array);
		}
	};
}

// generic enumeration
Function.prototype.forEach = function(object, block, context) {
	for (var key in object) {
		if (typeof this.prototype[key] == "undefined") {
			block.call(context, object[key], key, object);
		}
	}
};

// character enumeration
String.forEach = function(string, block, context) {
	Array.forEach(string.split(""), function(chr, index) {
		block.call(context, chr, index, string);
	});
};

// globally resolve forEach enumeration
var forEach = function(object, block, context) {
	if (object) {
		var resolve = Object; // default
		if (object instanceof Function) {
			// functions have a "length" property
			resolve = Function;
		} else if (object.forEach instanceof Function) {
			// the object implements a custom forEach method so use that
			object.forEach(block, context);
			return;
		} else if (typeof object == "string") {
			// the object is a string
			resolve = String;
		} else if (typeof object.length == "number") {
			// the object is array-like
			resolve = Array;
		}
		resolve.forEach(object, block, context);
	}
};

END
    close(JAVASCRIPT);
}

##########################################################################
# SUBROUTINE: utf8
# PURPOSE   : Returns html notation of a utf8 sequence
# ARGUMENT  : - The utf8 sequence
# RETURNS   : The html utf8 sequence, e.g. &#8364; for Euro sign
##########################################################################
sub utf8
{
    my ($string) = @_;
    my @array = split(//, $string);
    my $ret = '';
    my $num = 0;

    if ($#array == 0) {
        $num = $array[0];
    } elsif ($#array == 1) {
        if ((ord($array[0]) >> 5) == 6) {
            $num = ((ord($array[0]) & 31) << 6) + ((ord($array[1]) & 63));
        }
    } elsif ($#array == 2) {
        if (ord($array[0] >> 4) == 14 || ord($array[0] >> 4) == 48) {
            $num = ((ord($array[0]) & 15) << 12) + ((ord($array[1]) & 63) << 6) + ((ord($array[2]) & 63));
        }
    }
    return "&#$num;";
}

##########################################################################
# SUBROUTINE: utf8it
# PURPOSE   : Returns html notation of string 
# ARGUMENT  : - $string -- String to convert
# RETURNS   : The html string e.g. &#8364; for Euro sign
##########################################################################
sub utf8it
{
    my ($string) = @_;

    return $string if defined $charset;
    $string =~ s/([\xC0-\xDF][\x80-\xBF])/utf8($1)/emg;
    $string =~ s/([\xE0-\xEF][\x80-\xBF][\x80-\xBF])/utf8($1)/emg;
    return $string;
}

 
##########################################################################
# SUBROUTINE: uriit
# PURPOSE   : Returns uri notation of string, for use with <a href=
# ARGUMENT  : - $string -- String to convert
# RETURNS   : The uri notation 
##########################################################################
sub uriit
{
    my ($string) = @_;

    $string =~ s/([\xC0-\xDF])([\x80-\xBF])/sprintf("%%%02X%%%02X",ord($1),ord($2))/emg;
    $string =~ s/([\xE0-\xEF])([\x80-\xBF])([\x80-\xBF])/sprintf("%%%02X%%%02X%%%02X",ord($1),ord($2),ord($3))/emg;
    return $string;
}

##########################################################################
# SUBROUTINE: nbspit
# PURPOSE   : HTML Escapes whitespace,
#             replace \t with &nbsp;&nbsp;&nbsp;
#             replace \s with &nbsp;
# ARGUMENT  : - $string -- String to convert
# RETURNS   : The escaped string
##########################################################################
sub nbspit
{
    my ($string) = @_;

    $string =~ s/\t/&nbsp;&nbsp;&nbsp;/g;
    $string =~ s/\s/&nbsp;/g;
    return $string;
}

##########################################################################
# SUBROUTINE: replaceEntity
# PURPOSE   : Replace & < > to &amp; &lt; &gt;
# ARGUMENT  : - $string -- String to convert
# RETURNS   : The escaped string
##########################################################################
sub replaceEntity
{
    my ($string) = @_;

    $string =~ s/&/&amp;/g;
    $string =~ s/</&lt;/g;
    $string =~ s/>/&gt;/g;
    return $string;
}

##########################################################################
# SUBROUTINE: fixEscape
# PURPOSE   : Backslash quote in string fixer
# ARGUMENT  : - $line -- String to fix
# RETURNS   : The fixed string
##########################################################################
sub fixEscape
{
    my ($line) = @_;
    my $ret = substr($line, 0, 1);
    my $done = 0;
    my $kind = $ret; # ' or "

    $line = substr($line, 1);

    while (length $line && not $done) {
        my $chr = substr($line, 0, 1);
        if ($chr eq $kind) {
            $ret .= $kind;
            if ($ret =~ /^'\\'$/) {
                $ret .= "'"; # '\''
            }
            return $ret;
        } elsif ($chr eq '\\') {
            if ($line =~ /^(\\\\)/ or $line =~ /^(\\\")/) {
                $ret .= $1;
                $line = substr($line, 2);
            } else {
                $ret .= $chr;
                $line = substr($line, 1);
            }
        } else {
            $ret .= $chr;
            $line = substr($line, 1);
        }
    }
    return $ret;
}

##########################################################################
# SUBROUTINE: cp1252
# PURPOSE   : Returns cp1252 notation of a utf8 sequence
# ARGUMENT  : - The utf8 sequence
# RETURNS   : The cp Utf8 sequence
##########################################################################
sub cp1252
{
     my ($string) = @_;
     my @array = split(//, $string);
     my $ret = '';
     my $num = 0;

     if ($#array == 0) {
        $num = $array[0];
     } elsif ($#array == 1) {
        if ((ord($array[0]) >> 5) == 6) {
            $num = ((ord($array[0]) & 31) << 6) + ((ord($array[1]) & 63));
        }
     } elsif ($#array == 2) {
        if (ord($array[0] >> 4) == 14 || ord($array[0] >> 4) == 48) {
            $num = ((ord($array[0]) & 15) << 12) + ((ord($array[1]) & 63) << 6)
                    + ((ord($array[2]) & 63));
        }
     }
     return chr($num);
}

##########################################################################
# SUBROUTINE: cp1252it
# PURPOSE   : Converts a string to a cp1252 string
# PARAMETERS: - $string - The UTF8 string
# RETURNS   :
##########################################################################
sub cp1252it
{
     my ($string) = @_;

     $string =~ s/([\xC0-\xDF][\x80-\xBF])/cp1252($1)/emg;
     $string =~ s/([\xE0-\xEF][\x80-\xBF][\x80-\xBF])/cp1252($1)/emg;

     return $string;
}

##########################################################################
# SUBROUTINE: unicode2utf8
# PURPOSE   : Converts a Unicode string to a UTF-8 string
# PARAMETERS: - $string - The string with unicode characters
# RETURNS   : $string -- UTF-8 string
# NOTE      : This is to get rid of wide char perl issue
##########################################################################
sub unicode2utf8
{
     my ($string) = @_;
     my @array = split //, $string;
     my $result = '';

     while(($_= shift(@array)) != undef) {
       $val = ord($_);
       if ($val<=0x7f) {
           $result.=chr($val);
       } elsif($val<=0x7FF) {
           $result.=chr(0xC0 |($val>>6));
           $result.=chr(0x80 |(($val>>0) & 0x3F));
       } elsif ($val<= 0xFFFF) {
           $result.=chr(0xE0 | ($val>>12));
           $result.=chr(0x80 | (($val>>6) & 0x3F));
           $result.=chr(0x80 | (($val>>0) & 0x3F));
       } elsif ($val<= 0x1FFFFF) {
           $result.=chr(0xF0 | ($val>>18));
           $result.=chr(0x80 | (($val>>12) & 0x3F));
           $result.=chr(0x80 | (($val>>6) & 0x3F));
           $result.=chr(0x80 | (($val>>0) & 0x3F));
       } elsif ($val<= 0x3FFFFFF) {
           $result.=chr(0xF8 | ($val>>24));
           $result.=chr(0x80 | (($val>>18) & 0x3F));
           $result.=chr(0x80 | (($val>>12) & 0x3F));
           $result.=chr(0x80 | (($val>>6) & 0x3F));
           $result.=chr(0x80 | (($val>>0) & 0x3F));
       } elsif ($val<= 0x7FFFFFFF) {
           $result.=chr(0xFC | ($val>>30));
           $result.=chr(0x80 | (($val>>24) & 0x3F));
           $result.=chr(0x80 | (($val>>18) & 0x3F));
           $result.=chr(0x80 | (($val>>12) & 0x3F));
           $result.=chr(0x80 | (($val>>6) & 0x3F));
           $result.=chr(0x80 | (($val>>0) & 0x3F));
       } else {
           die "Invalid wide char";
       }
     }
     return $string;
}

##########################################################################
# SUBROUTINE: shortit
# PURPOSE   : Converts a string file name to a 8.3 string
# PARAMETERS: - $string - The UTF8 string
# RETURNS   : $string -- The 8.3 name
##########################################################################
sub shortit
{
    my ($string) = @_;
    my %short;
    my ($dir, $u, $cp);

    return $string;  # For now, too much risk compared to gain
    # We should re-do that, but with new perl
    return $string unless $^O eq "MSWin32";
    $dir = dirname($string);
    local $/ = "\n";

    if (defined $short{$string}) {
        return $short{$string};
    }

    open BAT, ">" . $ENV{TEMP} . "\\ctcdirshort.bat";
    print BAT <<"EOM";
\@echo off
chcp > $ENV{TEMP}\\ctccodepage.rsp 2>NUL
chcp 65001 >NUL 2>NUL
dir /x $dir > $ENV{TEMP}\\ctcdirshort.rsp 2>NUL
EOM
    close BAT;
    system("call " . $ENV{TEMP} . "\\ctcdirshort.bat");
    open CP, $ENV{TEMP} . "\\ctccodepage.rsp";
    $cp = <CP>;
    close CP;
    $cp =~ s/\015?\012$//;
    if ($cp =~ s/.+?(\d+)/$1/) {
        system("call chcp $cp >NUL");
        if (length $dir) {
            $dir .= "\\";
        }
        open DIR, $ENV{TEMP} . "\\ctcdirshort.rsp";
        while ($u = <DIR>) {
            $u =~ s/\015?\012$//;
            if ($u =~ /\s+([A-Z]+~\d+\.[A-Z]+)\s+(.*)/) {
                $short{$dir . $2} = $dir . $1;
                $short{$dir . lc($2)} = $dir . $1;
            }
        }
        close DIR;

        if (defined $short{$string}) {
            return $short{$string};
        }

        if (defined $short{unicode2utf8($string)}) {
            $short{$string} = $short{unicode2utf8($string)};
            return $short{unicode2utf8($string)};
        }
    }
    return $string;
}

sub stripSecondCopySuffix
{
     my ($filename) = @_;
     $tmp = quotemeta($second_copy_suffix);
     $filename =~ s/$tmp//;
     return $filename;
}

##########################################################################
# SUBROUTINE: openName
# PURPOSE   : Get's a name suitable for open() on Win32
# PARAMETERS: - $string - The UTF8 string
# RETURNS   : $string
# NOTE      : 1st strategy is to get a Windows CP1252 filename
#             2nd to determine the short ASCII filename
##########################################################################
sub openName
{
     my ($file) = @_;
     my $ret;

     $file=~s/\s+\(NO\sCOMPARE,.+\)$//;
     $ret = $file;

     return $file unless $^O eq "MSWin32";
     return $file if -f $file;

     $ret = cp1252it($file);
     return $ret if -f $ret;

     $ret = shortit($file);
     return $ret if -f $ret;

     return $file;
}

##########################################################################
# SUBROUTINE: toArrow
# PURPOSE   : Replace ctcdiff's ^ and v with arrows
# PARAMETERS: - $string
# RETURNS   : $string
##########################################################################
sub toArrow
{
    my ($hits, $string, $all) = @_;
    my $short = toArrowShort(-1,$string,0);
    $string = cleandiff($string) if length $string;
    if (!length ($string)) {
	return "($hits/$all)";
    }
    my $tooltip=tooltip($string);
    $string=$short;
    $string = cleandiff($string);
    $string = ''  unless defined $input_profile1;
    
    return "<span class=\"tooltip\">($string$hits/$all)<span class=\"tooltiptext\">$tooltip</span></span>";

}

##########################################################################
# SUBROUTINE: toArrowShort
# PURPOSE   : Replace ctcdiff's [19^ + 636=; 0v] with single arrows
# PARAMETERS: - $hits
#             - $string
#             - $all
# RETURNS   : (^8/9)
##########################################################################
sub toArrowShort
{
    my ($hits, $string, $all) = @_;
    return "($hits/$all)" unless length $string;
    my $tooltip = cleandiff(tooltip($string));
    
    if (!defined $shortc) {
	$shortc=0;
    }
    $shortc++;

    if (0 && $ctcdiff_verbose > 1 ) {
	$string = cleandiff($string);
	return "($string$hits/$all)";
    }

    if ($string=~/(\d+)[^\d]+(\d+)[^\d]+(\d+)/) {
	if (!$2 && !$3) {
	    $string = $arrow{"="};
	} elsif ($2 && !$3) {
	    $string=$arrow{"^"};
	} elsif ($2 && !$3) {
	    $string=$arrow{"v"};
	} else {
	    $string=$arrow{"|"};
	}
    }
    
    $string=cleandiff($string);
    
    if ($hits==-1) {
	return $string;
    }
    
    return "<span class=\"tooltip\">($string$hits/$all)<span class=\"tooltiptext\">$tooltip</span></span>";
}

##########################################################################
# SUBROUTINE: toArrowSingle
# PURPOSE   : eg. of "123","^" -> "uparrow123", and "0","v"->"downarrow0".
#             On MC/DC also eg. "+","^"->uparrow+", "-","v"->downarray-".
# PARAMETERS: $hits (eg. 123, or [-|+]), $string (one of [ |^|v])
# RETURNS   : the single-catenated string with possible arrow
##########################################################################
sub toArrowSingle
{
    my ($hits, $string) = @_;
    my $org=$string;

    if ($ctcdiff_sub_super) { #??? what's the idea, always false...
	if ($hits) {
	    return "<sup>$hits</sup>";
	} else {
	    return "<sub>$hits</sub>";
	}
    }
    
    $string = $arrow{$string};

    if ($prefix_arrow) {
	return "$string$hits";
    } else {
	return "$hits$string";
    }
}

##########################################################################
# SUBROUTINE: updown
# PURPOSE   : Parses the digits out of [1^ + 3=; 2v]
# PARAMETERS: - $string
# RETURNS (): - New coverage (1)
#             - Same coverage (3)
#             - Lost coverage (2)
# NOTE      : Needed to calculate per directory summary
##########################################################################
sub updown
{
    my ($string) = @_;

    if (!length $string) {
	return (0,0,0);
    }
    
    $string=~/^\[(\d+).+(\d+).+(\d+)\]$/;

    return ($1, $2, $3);
}

##########################################################################
# SUBROUTINE: tooltip
# PURPOSE   : Parses ctcdiff's [1^ + 3=; 2v]
# PARAMETERS: - $string
# RETURNS   : - $string -- The tooltip itself
##########################################################################
sub tooltip {
    my ($string) = @_;
    return "" unless defined $input_profile1;
    my $back = $string;
    $string=~s/&#\d+;/ /g;
    if ($string=~/(\d+)\s+.\s*(\d+)\s+-\s*(\d+)/) {
	my ($one, $two, $three, $all) = ($1, $2, $3, $1+$2-$3);
	my $m = '';
	my $br="";;
	if (1 || (!$1 && !$2 && !$3)) {
	    	$br="";
		$m = "$input_profile1&#61;&empty;<br>";
		$m .= "$input_profile2&#61;&empty;<br>";
		$m .= "$input_profile2&#8797;$input_profile2";
	}
	#	$string="<center><code>[$1&nbsp;+&#8239;$2&nbsp;-&#8239;$3]</code></center>";
	$string="[$1&nbsp;+&#8239;$2&nbsp;-&#8239;$3]";
	$XXXstring = <<"EOM";
<DIV class=tooltiptext>
<h1>$one + $two - $three  = $all</h1>
<table class="explanation">
<tr><th>$input_profile1</th><td>$one</td></tr>
<tr><th>Increase</th><td>$two</td></tr>
<tr><th>Decrease</th><td>$three</td></tr>
<tr><th>$input_profile2</th><td>$all</td></tr>
</table>
</DIV>
EOM
	$br="";
	if (0) {
	if ($1) {
	    $string.="$input_profile1: $2 hits";
	    $br="<br>";
	}
	if ($2) {
	    $string.="$br&nbsp;$1 co&#118;erage common in both input profiles";
	    $br="<br>";
	}
	if ($3) {
	    $string.="$br&nbsp;$3v lost co&#118;erage from $input_profile1";
	}
	}
#	$string.="<hr><small><a href=http://www.testwell.fi/>This is transition off zero and positi&#118;e</a></small>";
    } else {
	$string=$back;
    }
	
    return $string;
}

##########################################################################
# SUBROUTINE: cleandiff
# PURPOSE   : Replaces ctcdiff's [1^ + 3=; 2v]
# PARAMETERS: - $string
# RETURNS   : - $string -- the string with char replacements
##########################################################################
sub cleandiff
{
    my ($string) = @_;
    return $string;
    $string =~s/=;;/=&#9475;/g;
    $string =~s/\^/$arrow{"^"}/g;
    $string =~s/v/$arrow{"v"}/g;
    $string =~s/=/$arrow{"="}/g;
    $string =~s/ /&#8239;/g;

    return $string;
}


##########################################################################
# SUBROUTINE: chooseArrow
# PURPOSE   : Changes arrow them 
# PARAMETERS: - (nothing)
# RETURNS   : - (nothing)
# MODIFIES  : The %arrow set 
##########################################################################
sub chooseArrow
{
    $ENV{ARROW}=0 unless defined $ENV{ARROW}; # Set here the default look&feel

    if ($ENV{ARROW} == 1 ) {
	# Arrows replacement for ctcdiff usage 
	$arrow{'^'} = '&#8599;';  # Up arrow
	$arrow{'v'} = '&#8600;';  # Down arrow
	$arrow{' '} = ' ';        # Space, no-op
	$arrow{'|'} = '&#8597;';  # Up-Down arrow, needed for summaries
	$arrow{'='} = '';   # All Equal To
    }  elsif ($ENV{ARROW} == 0) {
	# Arrows replacement for ctcdiff usage 
	$arrow{'^'} = '^';  # Up arrow
	$arrow{'v'} = 'v';  # Down arrow
	$arrow{' '} = ' ';        # Space, no-op
	#$arrow{'|'} = '&#8645;';  # Up-Down arrow, needed for summaries
	$arrow{'|'} = '^v';  # Up-Down arrow, needed for summaries
	$arrow{'='} = '=';   # All Equal To
    }  elsif ($ENV{ARROW} == 4) {
	# Arrows replacement for ctcdiff usage
	# http://www.fileformat.info/info/unicode/block/spacing_modifier_letters/utf8test.htm
	$arrow{'^'} = '&#708;';  # Up arrow
	$arrow{'v'} = '&#709;';  # Down arrow
	$arrow{' '} = ' ';        # Space, no-op
	#$arrow{'|'} = '&#8645;';  # Up-Down arrow, needed for summaries
	$arrow{'|'} = '&tilde;';  # Up-Down arrow, needed for summaries
	$arrow{'='} = '&#749;';   # All Equal To
    } elsif ($ENV{ARROW} == 2) {
	# Arrows replacement for ctcdiff usage 
	$arrow{'^'} = '&#8673;';  # Up arrow
	$arrow{'v'} = '&#8675;';  # Down arrow
	$arrow{' '} = ' ';        # Space, no-op
	$arrow{'|'} = '&#8645;';  # Up-Down arrow, needed for summaries
	$arrow{'='} = '=';   # All Equal To
	
    } elsif ($ENV{ARROW}==5) {
	# Arrows replacement for ctcdiff usage
	# Font coloring, ugly, will most likely not work.
	$arrow{'^'} = '<font color=yellow>&#8625;</font>';  # Up arrow
	$arrow{'v'} = '<font color=yellow>&#8627;</font>';  # Down arrow
	$arrow{' '} = ' ';        # Space, no-op
	$arrow{'|'} = '&#8645;';  # Up-Down arrow, needed for summaries
	$arrow{'='} = '';   # All Equal To
    } elsif ($ENV{ARROW}==6) {
	# Arrows replacement for ctcdiff usage 
	$arrow{'^'} = '&#8853;';  # Up arrow
	$arrow{'v'} = '&#8854;';  # Down arrow
	$arrow{' '} = ' ';        # Space, no-op
	$arrow{'|'} = '&#8856;';  # Up-Down arrow, needed for summaries
	$arrow{'='} = '&#8860;';   # All Equal To
    } else {
	# Arrows replacement for ctcdiff usage 
	$arrow{'^'} = '&#8625;';  # Up arrow
	$arrow{'v'} = '&#8627;';  # Down arrow
	$arrow{' '} = ' ';        # Space, no-op
	$arrow{'|'} = '&#8645;';  # Up-Down arrow, needed for summaries
	$arrow{'='} = '';   # All Equal To
    }
    
}

# EOF $RCSfile: ctc2html.pl $
