IAP GITLAB

Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • AirShowerPhysics/corsika
  • rulrich/corsika
  • AAAlvesJr/corsika
  • Andre/corsika
  • arrabito/corsika
  • Nikos/corsika
  • olheiser73/corsika
  • AirShowerPhysics/papers/corsika
  • pranav/corsika
9 results
Show changes
.TH lcov 1 "LCOV 1.14" 2019\-02\-28 "User Manuals"
.SH NAME
lcov \- a graphical GCOV front\-end
.SH SYNOPSIS
.B lcov
.BR \-c | \-\-capture
.RS 5
.br
.RB [ \-d | \-\-directory
.IR directory ]
.RB [ \-k | \-\-kernel\-directory
.IR directory ]
.br
.RB [ \-o | \-\-output\-file
.IR tracefile ]
.RB [ \-t | \-\-test\-name
.IR testname ]
.br
.RB [ \-b | \-\-base\-directory
.IR directory ]
.RB [ \-i | \-\-initial ]
.RB [ \-\-gcov\-tool
.IR tool ]
.br
.RB [ \-\-checksum ]
.RB [ \-\-no\-checksum ]
.RB [ \-\-no\-recursion ]
.RB [ \-f | \-\-follow ]
.br
.RB [ \-\-compat\-libtool ]
.RB [ \-\-no\-compat\-libtool ]
.RB [ \-\-ignore\-errors
.IR errors ]
.br
.RB [ \-\-to\-package
.IR package ]
.RB [ \-\-from\-package
.IR package ]
.RB [ \-q | \-\-quiet ]
.br
.RB [ \-\-no\-markers ]
.RB [ \-\-external ]
.RB [ \-\-no\-external ]
.br
.RB [ \-\-config\-file
.IR config\-file ]
.RB [ \-\-rc
.IR keyword = value ]
.br
.RB [ \-\-compat
.IR mode =on|off|auto]
.br
.RB [ \-\-include
.IR pattern ]
.RB [ \-\-exclude
.IR pattern ]
.br
.RE
.B lcov
.BR \-z | \-\-zerocounters
.RS 5
.br
.RB [ \-d | \-\-directory
.IR directory ]
.RB [ \-\-no\-recursion ]
.RB [ \-f | \-\-follow ]
.br
.RB [ \-q | \-\-quiet ]
.br
.RE
.B lcov
.BR \-l | \-\-list
.I tracefile
.RS 5
.br
.RB [ \-q | \-\-quiet ]
.RB [ \-\-list\-full\-path ]
.RB [ \-\-no\-list\-full\-path ]
.br
.RB [ \-\-config\-file
.IR config\-file ]
.RB [ \-\-rc
.IR keyword = value ]
.br
.RE
.B lcov
.BR \-a | \-\-add\-tracefile
.I tracefile
.RS 5
.br
.RB [ \-o | \-\-output\-file
.IR tracefile ]
.RB [ \-\-checksum ]
.RB [ \-\-no\-checksum ]
.br
.RB [ \-q | \-\-quiet ]
.RB [ \-\-config\-file
.IR config\-file ]
.RB [ \-\-rc
.IR keyword = value ]
.br
.RE
.B lcov
.BR \-e | \-\-extract
.I tracefile pattern
.RS 5
.br
.RB [ \-o | \-\-output\-file
.IR tracefile ]
.RB [ \-\-checksum ]
.RB [ \-\-no\-checksum ]
.br
.RB [ \-q | \-\-quiet ]
.RB [ \-\-config\-file
.IR config\-file ]
.RB [ \-\-rc
.IR keyword = value ]
.br
.RE
.B lcov
.BR \-r | \-\-remove
.I tracefile pattern
.RS 5
.br
.RB [ \-o | \-\-output\-file
.IR tracefile ]
.RB [ \-\-checksum ]
.RB [ \-\-no\-checksum ]
.br
.RB [ \-q | \-\-quiet ]
.RB [ \-\-config\-file
.IR config\-file ]
.RB [ \-\-rc
.IR keyword = value ]
.br
.RE
.B lcov
.BR \-\-diff
.IR "tracefile diff"
.RS 5
.br
.RB [ \-o | \-\-output\-file
.IR tracefile ]
.RB [ \-\-checksum ]
.RB [ \-\-no\-checksum ]
.br
.RB [ \-\-convert\-filenames ]
.RB [ \-\-strip
.IR depth ]
.RB [ \-\-path
.IR path ]
.RB [ \-q | \-\-quiet ]
.br
.RB [ \-\-config\-file
.IR config\-file ]
.RB [ \-\-rc
.IR keyword = value ]
.br
.RE
.B lcov
.BR \-\-summary
.I tracefile
.RS 5
.br
.RB [ \-q | \-\-quiet ]
.br
.RE
.B lcov
.RB [ \-h | \-\-help ]
.RB [ \-v | \-\-version ]
.RS 5
.br
.RE
.SH DESCRIPTION
.B lcov
is a graphical front\-end for GCC's coverage testing tool gcov. It collects
line, function and branch coverage data for multiple source files and creates
HTML pages containing the source code annotated with coverage information.
It also adds overview pages for easy navigation within the file structure.
Use
.B lcov
to collect coverage data and
.B genhtml
to create HTML pages. Coverage data can either be collected from the
currently running Linux kernel or from a user space application. To do this,
you have to complete the following preparation steps:
For Linux kernel coverage:
.RS
Follow the setup instructions for the gcov\-kernel infrastructure:
.I http://ltp.sourceforge.net/coverage/gcov.php
.br
.RE
For user space application coverage:
.RS
Compile the application with GCC using the options
"\-fprofile\-arcs" and "\-ftest\-coverage".
.RE
Please note that this man page refers to the output format of
.B lcov
as ".info file" or "tracefile" and that the output of GCOV
is called ".da file".
Also note that when printing percentages, 0% and 100% are only printed when
the values are exactly 0% and 100% respectively. Other values which would
conventionally be rounded to 0% or 100% are instead printed as nearest
non-boundary value. This behavior is in accordance with that of the
.BR gcov (1)
tool.
.SH OPTIONS
.B \-a
.I tracefile
.br
.B \-\-add\-tracefile
.I tracefile
.br
.RS
Add contents of
.IR tracefile .
Specify several tracefiles using the \-a switch to combine the coverage data
contained in these files by adding up execution counts for matching test and
filename combinations.
The result of the add operation will be written to stdout or the tracefile
specified with \-o.
Only one of \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
specified at a time.
.RE
.B \-b
.I directory
.br
.B \-\-base\-directory
.I directory
.br
.RS
.RI "Use " directory
as base directory for relative paths.
Use this option to specify the base directory of a build\-environment
when lcov produces error messages like:
.RS
ERROR: could not read source file /home/user/project/subdir1/subdir2/subdir1/subdir2/file.c
.RE
In this example, use /home/user/project as base directory.
This option is required when using lcov on projects built with libtool or
similar build environments that work with a base directory, i.e. environments,
where the current working directory when invoking the compiler is not the same
directory in which the source code file is located.
Note that this option will not work in environments where multiple base
directories are used. In that case use configuration file setting
.B geninfo_auto_base=1
(see
.BR lcovrc (5)).
.RE
.B \-c
.br
.B \-\-capture
.br
.RS
Capture coverage data.
By default captures the current kernel execution counts and writes the
resulting coverage data to the standard output. Use the \-\-directory
option to capture counts for a user space program.
The result of the capture operation will be written to stdout or the tracefile
specified with \-o.
Only one of \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
specified at a time.
.RE
.B \-\-checksum
.br
.B \-\-no\-checksum
.br
.RS
Specify whether to generate checksum data when writing tracefiles.
Use \-\-checksum to enable checksum generation or \-\-no\-checksum to
disable it. Checksum generation is
.B disabled
by default.
When checksum generation is enabled, a checksum will be generated for each
source code line and stored along with the coverage data. This checksum will
be used to prevent attempts to combine coverage data from different source
code versions.
If you don't work with different source code versions, disable this option
to speed up coverage data processing and to reduce the size of tracefiles.
.RE
.B \-\-compat
.IR mode = value [, mode = value ,...]
.br
.RS
Set compatibility mode.
Use \-\-compat to specify that lcov should enable one or more compatibility
modes when capturing coverage data. You can provide a comma-separated list
of mode=value pairs to specify the values for multiple modes.
Valid
.I values
are:
.B on
.RS
Enable compatibility mode.
.RE
.B off
.RS
Disable compatibility mode.
.RE
.B auto
.RS
Apply auto-detection to determine if compatibility mode is required. Note that
auto-detection is not available for all compatibility modes.
.RE
If no value is specified, 'on' is assumed as default value.
Valid
.I modes
are:
.B libtool
.RS
Enable this mode if you are capturing coverage data for a project that
was built using the libtool mechanism. See also
\-\-compat\-libtool.
The default value for this setting is 'on'.
.RE
.B hammer
.RS
Enable this mode if you are capturing coverage data for a project that
was built using a version of GCC 3.3 that contains a modification
(hammer patch) of later GCC versions. You can identify a modified GCC 3.3
by checking the build directory of your project for files ending in the
extension '.bbg'. Unmodified versions of GCC 3.3 name these files '.bb'.
The default value for this setting is 'auto'.
.RE
.B split_crc
.RS
Enable this mode if you are capturing coverage data for a project that
was built using a version of GCC 4.6 that contains a modification
(split function checksums) of later GCC versions. Typical error messages
when running lcov on coverage data produced by such GCC versions are
\'out of memory' and 'reached unexpected end of file'.
The default value for this setting is 'auto'
.RE
.RE
.B \-\-compat\-libtool
.br
.B \-\-no\-compat\-libtool
.br
.RS
Specify whether to enable libtool compatibility mode.
Use \-\-compat\-libtool to enable libtool compatibility mode or \-\-no\-compat\-libtool
to disable it. The libtool compatibility mode is
.B enabled
by default.
When libtool compatibility mode is enabled, lcov will assume that the source
code relating to a .da file located in a directory named ".libs" can be
found in its parent directory.
If you have directories named ".libs" in your build environment but don't use
libtool, disable this option to prevent problems when capturing coverage data.
.RE
.B \-\-config\-file
.I config\-file
.br
.RS
Specify a configuration file to use.
When this option is specified, neither the system\-wide configuration file
/etc/lcovrc, nor the per\-user configuration file ~/.lcovrc is read.
This option may be useful when there is a need to run several
instances of
.B lcov
with different configuration file options in parallel.
.RE
.B \-\-convert\-filenames
.br
.RS
Convert filenames when applying diff.
Use this option together with \-\-diff to rename the file names of processed
data sets according to the data provided by the diff.
.RE
.B \-\-diff
.I tracefile
.I difffile
.br
.RS
Convert coverage data in
.I tracefile
using source code diff file
.IR difffile .
Use this option if you want to merge coverage data from different source code
levels of a program, e.g. when you have data taken from an older version
and want to combine it with data from a more current version.
.B lcov
will try to map source code lines between those versions and adjust the coverage
data respectively.
.I difffile
needs to be in unified format, i.e. it has to be created using the "\-u" option
of the
.B diff
tool.
Note that lines which are not present in the old version will not be counted
as instrumented, therefore tracefiles resulting from this operation should
not be interpreted individually but together with other tracefiles taken
from the newer version. Also keep in mind that converted coverage data should
only be used for overview purposes as the process itself introduces a loss
of accuracy.
The result of the diff operation will be written to stdout or the tracefile
specified with \-o.
Only one of \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
specified at a time.
.RE
.B \-d
.I directory
.br
.B \-\-directory
.I directory
.br
.RS
Use .da files in
.I directory
instead of kernel.
If you want to work on coverage data for a user space program, use this
option to specify the location where the program was compiled (that's
where the counter files ending with .da will be stored).
Note that you may specify this option more than once.
.RE
.B \-\-exclude
.I pattern
.br
.RS
Exclude source files matching
.IR pattern .
Use this switch if you want to exclude coverage data for a particular set
of source files matching any of the given patterns. Multiple patterns can be
specified by using multiple
.B --exclude
command line switches. The
.I patterns
will be interpreted as shell wildcard patterns (note that they may need to be
escaped accordingly to prevent the shell from expanding them first).
Can be combined with the
.B --include
command line switch. If a given file matches both the include pattern and the
exclude pattern, the exclude pattern will take precedence.
.RE
.B \-\-external
.br
.B \-\-no\-external
.br
.RS
Specify whether to capture coverage data for external source files.
External source files are files which are not located in one of the directories
specified by \-\-directory or \-\-base\-directory. Use \-\-external to include
external source files while capturing coverage data or \-\-no\-external to
ignore this data.
Data for external source files is
.B included
by default.
.RE
.B \-e
.I tracefile
.I pattern
.br
.B \-\-extract
.I tracefile
.I pattern
.br
.RS
Extract data from
.IR tracefile .
Use this switch if you want to extract coverage data for only a particular
set of files from a tracefile. Additional command line parameters will be
interpreted as shell wildcard patterns (note that they may need to be
escaped accordingly to prevent the shell from expanding them first).
Every file entry in
.I tracefile
which matches at least one of those patterns will be extracted.
The result of the extract operation will be written to stdout or the tracefile
specified with \-o.
Only one of \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
specified at a time.
.RE
.B \-f
.br
.B \-\-follow
.br
.RS
Follow links when searching for .da files.
.RE
.B \-\-from\-package
.I package
.br
.RS
Use .da files in
.I package
instead of kernel or directory.
Use this option if you have separate machines for build and test and
want to perform the .info file creation on the build machine. See
\-\-to\-package for more information.
.RE
.B \-\-gcov\-tool
.I tool
.br
.RS
Specify the location of the gcov tool.
.RE
.B \-h
.br
.B \-\-help
.br
.RS
Print a short help text, then exit.
.RE
.B \-\-include
.I pattern
.br
.RS
Include source files matching
.IR pattern .
Use this switch if you want to include coverage data for only a particular set
of source files matching any of the given patterns. Multiple patterns can be
specified by using multiple
.B --include
command line switches. The
.I patterns
will be interpreted as shell wildcard patterns (note that they may need to be
escaped accordingly to prevent the shell from expanding them first).
.RE
.B \-\-ignore\-errors
.I errors
.br
.RS
Specify a list of errors after which to continue processing.
Use this option to specify a list of one or more classes of errors after which
lcov should continue processing instead of aborting.
.I errors
can be a comma\-separated list of the following keywords:
.B gcov:
the gcov tool returned with a non\-zero return code.
.B source:
the source code file for a data set could not be found.
.B graph:
the graph file could not be found or is corrupted.
.RE
.B \-i
.br
.B \-\-initial
.RS
Capture initial zero coverage data.
Run lcov with \-c and this option on the directories containing .bb, .bbg
or .gcno files before running any test case. The result is a "baseline"
coverage data file that contains zero coverage for every instrumented line.
Combine this data file (using lcov \-a) with coverage data files captured
after a test run to ensure that the percentage of total lines covered is
correct even when not all source code files were loaded during the test.
Recommended procedure when capturing data for a test case:
1. create baseline coverage data file
.RS
# lcov \-c \-i \-d appdir \-o app_base.info
.br
.RE
2. perform test
.RS
# appdir/test
.br
.RE
3. create test coverage data file
.RS
# lcov \-c \-d appdir \-o app_test.info
.br
.RE
4. combine baseline and test coverage data
.RS
# lcov \-a app_base.info \-a app_test.info \-o app_total.info
.br
.RE
.RE
.B \-k
.I subdirectory
.br
.B \-\-kernel\-directory
.I subdirectory
.br
.RS
Capture kernel coverage data only from
.IR subdirectory .
Use this option if you don't want to get coverage data for all of the
kernel, but only for specific subdirectories. This option may be specified
more than once.
Note that you may need to specify the full path to the kernel subdirectory
depending on the version of the kernel gcov support.
.RE
.B \-l
.I tracefile
.br
.B \-\-list
.I tracefile
.br
.RS
List the contents of the
.IR tracefile .
Only one of \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
specified at a time.
.RE
.B \-\-list\-full\-path
.br
.B \-\-no\-list\-full\-path
.br
.RS
Specify whether to show full paths during list operation.
Use \-\-list\-full\-path to show full paths during list operation
or \-\-no\-list\-full\-path to show shortened paths. Paths are
.B shortened
by default.
.RE
.B \-\-no\-markers
.br
.RS
Use this option if you want to get coverage data without regard to exclusion
markers in the source code file. See
.BR "geninfo " (1)
for details on exclusion markers.
.RE
.B \-\-no\-recursion
.br
.RS
Use this option if you want to get coverage data for the specified directory
only without processing subdirectories.
.RE
.B \-o
.I tracefile
.br
.B \-\-output\-file
.I tracefile
.br
.RS
Write data to
.I tracefile
instead of stdout.
Specify "\-" as a filename to use the standard output.
By convention, lcov\-generated coverage data files are called "tracefiles" and
should have the filename extension ".info".
.RE
.B \-\-path
.I path
.br
.RS
Strip path from filenames when applying diff.
Use this option together with \-\-diff to tell lcov to disregard the specified
initial path component when matching between tracefile and diff filenames.
.RE
.B \-q
.br
.B \-\-quiet
.br
.RS
Do not print progress messages.
This option is implied when no output filename is specified to prevent
progress messages to mess with coverage data which is also printed to
the standard output.
.RE
.B \-\-rc
.IR keyword = value
.br
.RS
Override a configuration directive.
Use this option to specify a
.IR keyword = value
statement which overrides the corresponding configuration statement in
the lcovrc configuration file. You can specify this option more than once
to override multiple configuration statements.
See
.BR lcovrc (5)
for a list of available keywords and their meaning.
.RE
.B \-r
.I tracefile
.I pattern
.br
.B \-\-remove
.I tracefile
.I pattern
.br
.RS
Remove data from
.IR tracefile .
Use this switch if you want to remove coverage data for a particular
set of files from a tracefile. Additional command line parameters will be
interpreted as shell wildcard patterns (note that they may need to be
escaped accordingly to prevent the shell from expanding them first).
Every file entry in
.I tracefile
which matches at least one of those patterns will be removed.
The result of the remove operation will be written to stdout or the tracefile
specified with \-o.
Only one of \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
specified at a time.
.RE
.B \-\-strip
.I depth
.br
.RS
Strip path components when applying diff.
Use this option together with \-\-diff to tell lcov to disregard the specified
number of initial directories when matching tracefile and diff filenames.
.RE
.B \-\-summary
.I tracefile
.br
.RS
Show summary coverage information for the specified tracefile.
Note that you may specify this option more than once.
Only one of \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
specified at a time.
.RE
.B \-t
.I testname
.br
.B \-\-test\-name
.I testname
.br
.RS
Specify test name to be stored in the tracefile.
This name identifies a coverage data set when more than one data set is merged
into a combined tracefile (see option \-a).
Valid test names can consist of letters, decimal digits and the underscore
character ("_").
.RE
.B \-\-to\-package
.I package
.br
.RS
Store .da files for later processing.
Use this option if you have separate machines for build and test and
want to perform the .info file creation on the build machine. To do this,
follow these steps:
On the test machine:
.RS
.br
\- run the test
.br
\- run lcov \-c [\-d directory] \-\-to-package
.I file
.br
\- copy
.I file
to the build machine
.RE
.br
On the build machine:
.RS
.br
\- run lcov \-c \-\-from-package
.I file
[\-o and other options]
.RE
.br
This works for both kernel and user space coverage data. Note that you might
have to specify the path to the build directory using \-b with
either \-\-to\-package or \-\-from-package. Note also that the package data
must be converted to a .info file before recompiling the program or it will
become invalid.
.RE
.B \-v
.br
.B \-\-version
.br
.RS
Print version number, then exit.
.RE
.B \-z
.br
.B \-\-zerocounters
.br
.RS
Reset all execution counts to zero.
By default tries to reset kernel execution counts. Use the \-\-directory
option to reset all counters of a user space program.
Only one of \-z, \-c, \-a, \-e, \-r, \-l, \-\-diff or \-\-summary may be
specified at a time.
.RE
.SH FILES
.I /etc/lcovrc
.RS
The system\-wide configuration file.
.RE
.I ~/.lcovrc
.RS
The per\-user configuration file.
.RE
.SH AUTHOR
Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
.SH SEE ALSO
.BR lcovrc (5),
.BR genhtml (1),
.BR geninfo (1),
.BR genpng (1),
.BR gendesc (1),
.BR gcov (1)
.TH lcovrc 5 "LCOV 1.14" 2019\-02\-28 "User Manuals"
.SH NAME
lcovrc \- lcov configuration file
.SH DESCRIPTION
The
.I lcovrc
file contains configuration information for the
.B lcov
code coverage tool (see
.BR lcov (1)).
.br
The system\-wide configuration file is located at
.IR /etc/lcovrc .
To change settings for a single user, place a customized copy of this file at
location
.IR ~/.lcovrc .
Where available, command\-line options override configuration file settings.
Lines in a configuration file can either be:
.IP " *"
empty lines or lines consisting only of white space characters. These lines are
ignored.
.IP " *"
comment lines which start with a hash sign ('#'). These are treated like empty
lines and will be ignored.
.IP " *"
statements in the form
.RI ' key " = " value '.
A list of valid statements and their description can be found in
section 'OPTIONS' below.
.PP
.B Example configuration:
.IP
#
.br
# Example LCOV configuration file
.br
#
.br
# External style sheet file
.br
#genhtml_css_file = gcov.css
.br
# Coverage rate limits
.br
genhtml_hi_limit = 90
.br
genhtml_med_limit = 75
.br
# Width of line coverage field in source code view
.br
genhtml_line_field_width = 12
.br
# Width of branch coverage field in source code view
.br
genhtml_branch_field_width = 16
.br
# Width of overview image
.br
genhtml_overview_width = 80
.br
# Resolution of overview navigation
.br
genhtml_nav_resolution = 4
.br
# Offset for source code navigation
.br
genhtml_nav_offset = 10
.br
# Do not remove unused test descriptions if non\-zero
.br
genhtml_keep_descriptions = 0
.br
# Do not remove prefix from directory names if non\-zero
.br
genhtml_no_prefix = 0
.br
# Do not create source code view if non\-zero
.br
genhtml_no_source = 0
.br
# Specify size of tabs
.br
genhtml_num_spaces = 8
.br
# Highlight lines with converted\-only data if non\-zero
.br
genhtml_highlight = 0
.br
# Include color legend in HTML output if non\-zero
.br
genhtml_legend = 0
.br
# Include HTML file at start of HTML output
.br
#genhtml_html_prolog = prolog.html
.br
# Include HTML file at end of HTML output
.br
#genhtml_html_epilog = epilog.html
.br
# Use custom HTML file extension
.br
#genhtml_html_extension = html
.br
# Compress all generated html files with gzip.
.br
#genhtml_html_gzip = 1
.br
# Include sorted overview pages
.br
genhtml_sort = 1
.br
# Include function coverage data display
.br
#genhtml_function_coverage = 1
.br
# Include branch coverage data display
.br
#genhtml_branch_coverage = 1
.br
# Specify the character set of all generated HTML pages
.br
genhtml_charset=UTF\-8
.br
# Allow HTML markup in test case description text if non\-zero
.br
genhtml_desc_html=0
.br
# Specify the precision for coverage rates
.br
#genhtml_precision=1
.br
# Show missed counts instead of hit counts
.br
#genhtml_missed=1
.br
# Demangle C++ symbols
.br
#genhtml_demangle_cpp=1
.br
# Location of the gcov tool
.br
#geninfo_gcov_tool = gcov
.br
# Adjust test names if non\-zero
.br
#geninfo_adjust_testname = 0
.br
# Calculate a checksum for each line if non\-zero
.br
geninfo_checksum = 0
.br
# Enable libtool compatibility mode if non\-zero
.br
geninfo_compat_libtool = 0
.br
# Specify whether to capture coverage data for external source
.br
# files
.br
#geninfo_external = 1
.br
# Use gcov's --all-blocks option if non-zero
.br
#geninfo_gcov_all_blocks = 1
.br
# Specify compatiblity modes (same as \-\-compat option
.br
# of geninfo)
.br
#geninfo_compat = libtool=on, hammer=auto, split_crc=auto
.br
# Adjust path to source files by removing or changing path
.br
# components that match the specified pattern (Perl regular
.br
# expression format)
.br
#geninfo_adjust_src_path = /tmp/build => /usr/src
# Specify if geninfo should try to automatically determine
.br
# the base-directory when collecting coverage data.
.br
geninfo_auto_base = 1
.br
# Directory containing gcov kernel files
.br
lcov_gcov_dir = /proc/gcov
.br
# Location for temporary directories
.br
lcov_tmp_dir = /tmp
.br
# Show full paths during list operation if non\-zero
.br
lcov_list_full_path = 0
.br
# Specify the maximum width for list output. This value is
.br
# ignored when lcov_list_full_path is non\-zero.
.br
lcov_list_width = 80
.br
# Specify the maximum percentage of file names which may be
.br
# truncated when choosing a directory prefix in list output.
.br
# This value is ignored when lcov_list_full_path is non\-zero.
.br
lcov_list_truncate_max = 20
# Specify if function coverage data should be collected and
.br
# processed.
.br
lcov_function_coverage = 1
.br
# Specify if branch coverage data should be collected and
.br
# processed.
.br
lcov_branch_coverage = 0
.br
.PP
.SH OPTIONS
.BR genhtml_css_file " ="
.I filename
.IP
Specify an external style sheet file. Use this option to modify the appearance of the HTML output as generated by
.BR genhtml .
During output generation, a copy of this file will be placed in the output
directory.
.br
This option corresponds to the \-\-css\-file command line option of
.BR genhtml .
.br
By default, a standard CSS file is generated.
.PP
.BR genhtml_hi_limit " ="
.I hi_limit
.br
.BR genhtml_med_limit " ="
.I med_limit
.br
.IP
Specify coverage rate limits for classifying file entries. Use this option to
modify the coverage rates (in percent) for line, function and branch coverage at
which a result is classified as high, medium or low coverage. This
classification affects the color of the corresponding entries on the overview
pages of the HTML output:
.br
High: hi_limit <= rate <= 100 default color: green
.br
Medium: med_limit <= rate < hi_limit default color: orange
.br
Low: 0 <= rate < med_limit default color: red
.br
Defaults are 90 and 75 percent.
.PP
.BR genhtml_line_field_width " ="
.I number_of_characters
.IP
Specify the width (in characters) of the source code view column containing
line coverage information.
.br
Default is 12.
.PP
.BR genhtml_branch_field_width " ="
.I number_of_characters
.IP
Specify the width (in characters) of the source code view column containing
branch coverage information.
.br
Default is 16.
.PP
.BR genhtml_overview_width " ="
.I pixel_size
.IP
Specify the width (in pixel) of the overview image created when generating HTML
output using the \-\-frames option of
.BR genhtml .
.br
Default is 80.
.PP
.BR genhtml_nav_resolution " ="
.I lines
.IP
Specify the resolution of overview navigation when generating HTML output using
the \-\-frames option of
.BR genhtml .
This number specifies the maximum difference in lines between the position a
user selected from the overview and the position the source code window is
scrolled to.
.br
Default is 4.
.PP
.BR genhtml_nav_offset " ="
.I lines
.IP
Specify the overview navigation line offset as applied when generating HTML
output using the \-\-frames option of
.BR genhtml.
.br
Clicking a line in the overview image should show the source code view at
a position a bit further up, so that the requested line is not the first
line in the window. This number specifies that offset.
.br
Default is 10.
.PP
.BR genhtml_keep_descriptions " ="
.IR 0 | 1
.IP
If non\-zero, keep unused test descriptions when generating HTML output using
.BR genhtml .
.br
This option corresponds to the \-\-keep\-descriptions option of
.BR genhtml .
.br
Default is 0.
.PP
.BR genhtml_no_prefix " ="
.IR 0 | 1
.IP
If non\-zero, do not try to find and remove a common prefix from directory names.
.br
This option corresponds to the \-\-no\-prefix option of
.BR genhtml .
.br
Default is 0.
.PP
.BR genhtml_no_source " ="
.IR 0 | 1
.IP
If non\-zero, do not create a source code view when generating HTML output using
.BR genhtml .
.br
This option corresponds to the \-\-no\-source option of
.BR genhtml .
.br
Default is 0.
.PP
.BR genhtml_num_spaces " ="
.I num
.IP
Specify the number of spaces to use as replacement for tab characters in the
HTML source code view as generated by
.BR genhtml .
.br
This option corresponds to the \-\-num\-spaces option of
.BR genthml .
.br
Default is 8.
.PP
.BR genhtml_highlight " ="
.IR 0 | 1
.IP
If non\-zero, highlight lines with converted\-only data in
HTML output as generated by
.BR genhtml .
.br
This option corresponds to the \-\-highlight option of
.BR genhtml .
.br
Default is 0.
.PP
.BR genhtml_legend " ="
.IR 0 | 1
.IP
If non\-zero, include a legend explaining the meaning of color coding in the HTML
output as generated by
.BR genhtml .
.br
This option corresponds to the \-\-legend option of
.BR genhtml .
.br
Default is 0.
.PP
.BR genhtml_html_prolog " ="
.I filename
.IP
If set, include the contents of the specified file at the beginning of HTML
output.
This option corresponds to the \-\-html\-prolog option of
.BR genhtml .
.br
Default is to use no extra prolog.
.PP
.BR genhtml_html_epilog " ="
.I filename
.IP
If set, include the contents of the specified file at the end of HTML output.
This option corresponds to the \-\-html\-epilog option of
.BR genhtml .
.br
Default is to use no extra epilog.
.PP
.BR genhtml_html_extension " ="
.I extension
.IP
If set, use the specified string as filename extension for generated HTML files.
This option corresponds to the \-\-html\-extension option of
.BR genhtml .
.br
Default extension is "html".
.PP
.BR genhtml_html_gzip " ="
.IR 0 | 1
.IP
If set, compress all html files using gzip.
This option corresponds to the \-\-html\-gzip option of
.BR genhtml .
.br
Default extension is 0.
.PP
.BR genhtml_sort " ="
.IR 0 | 1
.IP
If non\-zero, create overview pages sorted by coverage rates when generating
HTML output using
.BR genhtml .
.br
This option can be set to 0 by using the \-\-no\-sort option of
.BR genhtml .
.br
Default is 1.
.PP
.BR genhtml_function_coverage " ="
.IR 0 | 1
.IP
If non\-zero, include function coverage data when generating HTML output using
.BR genhtml .
.br
This option can be set to 0 by using the \-\-no\-function\-coverage option of
.BR genhtml .
.br
Default is 1.
.PP
.BR genhtml_branch_coverage " ="
.IR 0 | 1
.IP
If non\-zero, include branch coverage data when generating HTML output using
.BR genhtml .
.br
This option can be set to 0 by using the \-\-no\-branch\-coverage option of
.BR genhtml .
.br
Default is 1.
.PP
.BR genhtml_charset " ="
.I charset
.IP
Specify the character set of all generated HTML pages.
.br
Use this option if the source code contains characters which are not
part of the default character set. Note that this option is ignored
when a custom HTML prolog is specified (see also
.BR genhtml_html_prolog ).
.br
Default is UTF-8.
.PP
.BR genhtml_demangle_cpp " ="
.IR 0 | 1
.IP
If non-zero, demangle C++ function names in function overviews.
Set this option to one if you want to convert C++ internal function
names to human readable format for display on the HTML function overview
page. This option requires that the c++filt tool is installed (see
.BR c++filt(1)
).
.br
This option corresponds to the \-\-demangle\-cpp command line option of
.BR genhtml .
.br
Default is 0.
.PP
.BR genhtml_desc_html " ="
.IR 0 | 1
.IP
If non-zero, test case descriptions may contain HTML markup.
Set this option to one if you want to embed HTML markup (for example to
include links) in test case descriptions. When set to zero, HTML markup
characters will be escaped to show up as plain text on the test case
description page.
.br
Default is 0.
.PP
.BR genhtml_precision " ="
.IR 1 | 2 | 3 | 4
.IP
Specify how many digits after the decimal-point should be used for
displaying coverage rates.
.br
Default is 1.
.PP
.BR genhtml_missed " ="
.IR 0 | 1
.IP
If non-zero, the count of missed lines, functions, or branches is shown
as negative numbers in overview pages.
.br
Default is 0.
.PP
.
.BR geninfo_gcov_tool " ="
.I path_to_gcov
.IP
Specify the location of the gcov tool (see
.BR gcov (1))
which is used to generate coverage information from data files.
.br
Default is 'gcov'.
.PP
.BR geninfo_adjust_testname " ="
.IR 0 | 1
.IP
If non\-zero, adjust test names to include operating system information
when capturing coverage data.
.br
Default is 0.
.PP
.BR geninfo_checksum " ="
.IR 0 | 1
.IP
If non\-zero, generate source code checksums when capturing coverage data.
Checksums are useful to prevent merging coverage data from incompatible
source code versions but checksum generation increases the size of coverage
files and the time used to generate those files.
.br
This option corresponds to the \-\-checksum and \-\-no\-checksum command line
option of
.BR geninfo .
.br
Default is 0.
.PP
.BR geninfo_compat_libtool " ="
.IR 0 | 1
.IP
If non\-zero, enable libtool compatibility mode. When libtool compatibility
mode is enabled, lcov will assume that the source code relating to a .da file
located in a directory named ".libs" can be found in its parent directory.
.br
This option corresponds to the \-\-compat\-libtool and \-\-no\-compat\-libtool
command line option of
.BR geninfo .
.br
Default is 1.
.PP
.BR geninfo_external " ="
.IR 0 | 1
.IP
If non\-zero, capture coverage data for external source files.
External source files are files which are not located in one of the directories
(including sub-directories)
specified by the \-\-directory or \-\-base\-directory options of
.BR lcov / geninfo .
Default is 1.
.PP
.BR geninfo_gcov_all_blocks " ="
.IR 0 | 1
.IP
If non\-zero, call the gcov tool with option --all-blocks.
Using --all-blocks will produce more detailed branch coverage information for
each line. Set this option to zero if you do not need detailed branch coverage
information to speed up the process of capturing code coverage or to work
around a bug in some versions of gcov which will cause it to endlessly loop
when analysing some files.
Default is 1.
.PP
.BR geninfo_compat " ="
.IR mode = value [, mode = value ,...]
.IP
Specify that geninfo should enable one or more compatibility modes
when capturing coverage data.
This option corresponds to the \-\-compat command line option of
.BR geninfo .
Default is 'libtool=on, hammer=auto, split_crc=auto'.
.PP
.BR geninfo_adjust_src_path " ="
.IR pattern " => " replacement
.br
.BR geninfo_adjust_src_path " ="
.I pattern
.IP
Adjust source paths when capturing coverage data.
Use this option in situations where geninfo cannot find the correct
path to source code files of a project. By providing a
.I pattern
in Perl regular expression format (see
.BR perlre (1))
and an optional replacement string, you can instruct geninfo to
remove or change parts of the incorrect source path.
.B Example:
.br
1. When geninfo reports that it cannot find source file
.br
/path/to/src/.libs/file.c
.br
while the file is actually located in
.br
/path/to/src/file.c
.br
use the following parameter:
.br
geninfo_adjust_src_path = /.libs
This will remove all "/.libs" strings from the path.
2. When geninfo reports that it cannot find source file
.br
/tmp/build/file.c
.br
while the file is actually located in
.br
/usr/src/file.c
.br
use the following parameter:
.br
geninfo_adjust_src_path = /tmp/build => /usr/src
.br
This will change all "/tmp/build" strings in the path to "/usr/src".
.PP
.BR geninfo_auto_base " ="
.IR 0 | 1
.IP
If non\-zero, apply a heuristic to determine the base directory when
collecting coverage data.
.br
Use this option when using geninfo on projects built with libtool or
similar build environments that work with multiple base directories,
i.e. environments, where the current working directory when invoking the
compiler ist not the same directory in which the source code file is
located, and in addition, is different between files of the same project.
.br
Default is 1.
.PP
.BR lcov_gcov_dir " ="
.I path_to_kernel_coverage_data
.IP
Specify the path to the directory where kernel coverage data can be found
or leave undefined for auto-detection.
.br
Default is auto-detection.
.PP
.BR lcov_tmp_dir " ="
.I temp
.IP
Specify the location of a directory used for temporary files.
.br
Default is '/tmp'.
.PP
.BR lcov_list_full_path " ="
.IR 0 | 1
.IP
If non-zero, print the full path to source code files during a list operation.
.br
This option corresponds to the \-\-list\-full\-path option of
.BR lcov .
.br
Default is 0.
.PP
.BR lcov_list_max_width " ="
.IR width
.IP
Specify the maximum width for list output. This value is ignored when
lcov_list_full_path is non\-zero.
.br
Default is 80.
.PP
.BR lcov_list_truncate_max
.B " ="
.IR percentage
.IP
Specify the maximum percentage of file names which may be truncated when
choosing a directory prefix in list output. This value is ignored when
lcov_list_full_path is non\-zero.
.br
Default is 20.
.PP
.BR lcov_function_coverage " ="
.IR 0 | 1
.IP
Specify whether lcov should handle function coverage data.
.br
Setting this option to 0 can reduce memory and CPU time consumption
when lcov is collecting and processing coverage data, as well as
reduce the size of the resulting data files. Note that setting
.B genhtml_function_coverage
will override this option for HTML generation.
.br
Default is 1.
.PP
.BR lcov_branch_coverage " ="
.IR 0 | 1
.IP
Specify whether lcov should handle branch coverage data.
.br
Setting this option to 0 can reduce memory and CPU time consumption
when lcov is collecting and processing coverage data, as well as
reduce the size of the resulting data files. Note that setting
.B genhtml_branch_coverage
will override this option for HTML generation.
.br
Default is 0.
.PP
.BR lcov_excl_line " ="
.I expression
.IP
Specify the regular expression of lines to exclude.
.br
Default is 'LCOV_EXCL_LINE'.
.PP
.BR lcov_excl_br_line " ="
.I expression
.IP
Specify the regular expression of lines to exclude from branch coverage.
.br
Default is 'LCOV_EXCL_BR_LINE'.
.PP
.SH FILES
.TP
.I /etc/lcovrc
The system\-wide
.B lcov
configuration file.
.TP
.I ~/.lcovrc
The individual per\-user configuration file.
.PP
.SH SEE ALSO
.BR lcov (1),
.BR genhtml (1),
.BR geninfo (1),
.BR gcov (1)
Summary: A graphical GCOV front-end
Name: lcov
Version: 1.14
Release: 1
License: GPLv2+
Group: Development/Tools
URL: http://ltp.sourceforge.net/coverage/lcov.php
Source0: http://downloads.sourceforge.net/ltp/%{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-root
BuildArch: noarch
Requires: perl >= 5.8.8
%description
LCOV is a graphical front-end for GCC's coverage testing tool gcov. It collects
gcov data for multiple source files and creates HTML pages containing the
source code annotated with coverage information. It also adds overview pages
for easy navigation within the file structure.
%prep
%setup -q -n %{name}-%{version}
%build
exit 0
%install
rm -rf $RPM_BUILD_ROOT
make install DESTDIR=$RPM_BUILD_ROOT PREFIX=/usr CFG_DIR=/etc
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
/usr/bin/*
/usr/share/man/man*/*
%config /etc/*
%changelog
* Mon Aug 22 2016 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
- updated "make install" call to work with PREFIX Makefile changes
* Mon May 07 2012 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
- added dependency on perl 5.8.8 for >>& open mode support
* Wed Aug 13 2008 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
- changed description + summary text
* Mon Aug 20 2007 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
- fixed "Copyright" tag
* Mon Jul 14 2003 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
- removed variables for version/release to support source rpm building
- added initial rm command in install section
* Mon Apr 7 2003 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
- implemented variables for version/release
* Fri Oct 18 2002 Peter Oberparleiter (Peter.Oberparleiter@de.ibm.com)
- created initial spec file
include common.mak
TESTDIRS := $(sort $(patsubst %/,%,$(dir $(wildcard */Makefile))))
help: info
info:
echo "Available make targets:"
echo " test : perform self-tests"
echo " clean : remove all temporary files"
echo ""
echo "Available make variables:"
echo " SIZE : specify size of test data (small, medium, large)"
echo " V : specify level of verbosity (0, 1, 2)"
test:
for TEST in $(TESTDIRS) ; do \
make -C $$TEST test ; \
done
clean:
rm -rf *.info *.counts test.log src/
for TEST in $(TESTDIRS) ; do \
make -C $$TEST clean ; \
done
.PHONY: help info test clean
function elapsed_to_ms()
{
local ELAPSED=$1
local IFS=:.
local MS
set -- $ELAPSED
if [ $# -eq 3 ] ; then
let MS=${3#0}*10+${2#0}*1000+$1*60000
else
let MS=${4#0}*10+${3#0}*1000+${2#0}*60000+$1*3600000
fi
echo $MS
}
function t_timestamp()
{
date +"%Y-%m-%d %H:%M:%S %z"
}
function t_marker()
{
echo
echo "======================================================================"
}
function t_detail()
{
local KEY=$1
local VALUE=$2
local DOTS=" ............"
printf "%-.12s: %s\n" "$KEY$DOTS" "$VALUE"
}
function t_announce()
{
local TESTNAME="$1"
printf "$BOLD%-.30s$RESET " "$TESTNAME .............................."
t_marker >> "$LOGFILE"
t_detail "DATE" "$(t_timestamp)" >> "$LOGFILE"
t_detail "TESTNAME" "$TESTNAME" >> "$LOGFILE"
}
function t_result()
{
local COLOR="$1"
local TEXT="$2"
printf "[$COLOR$TEXT$RESET]"
}
function t_pass()
{
local TESTNAME="$1"
t_result "$GREEN" "pass"
echo "pass $TESTNAME" >> "$COUNTFILE"
}
function t_fail()
{
local TESTNAME="$1"
t_result "$RED" "fail"
echo "fail $TESTNAME" >> "$COUNTFILE"
}
function t_kill()
{
local TESTNAME="$1"
t_result "$RED" "kill"
echo "fail $TESTNAME" >> "$COUNTFILE"
}
function t_skip()
{
local TESTNAME="$1"
t_result "$BLUE" "skip"
echo "skip $TESTNAME" >> "$COUNTFILE"
}
function t_indent()
{
sed -e 's/^/ /'
}
LOGFILE="$TOPDIR/test.log"
COUNTFILE="$TOPDIR/test.counts"
TIMEFILE="$TOPDIR/test.time"
if [ -t 1 ] ; then
RED="\e[31m"
GREEN="\e[32m"
BLUE="\e[34m"
BOLD="\e[1m"
DEFAULT="\e[39m"
RESET="\e[0m"
fi
#!/usr/bin/env perl
#
# Copyright IBM Corp. 2017
#
# Usage: mkinfo <config_file> [-o <output_dir>] [--seed <seed>]
# [<key>=<value>...]
#
# Create a fake lcov code coverage data file and optionally the corresponding
# source tree. DATA_FILE contains all specifications for creating the data
# file. Directives can be overridden using KEY=VALUE specifications with KEY
# being in the form SECTION.KEY. SEED specifies the number used to initialize
# the pseudo random number generator.
#
# Example:
# mkinfo profiles/small -o src files.numfiles=12
#
use strict;
use warnings;
use Getopt::Long;
use Cwd qw(abs_path getcwd);
use File::Path qw(make_path);
use File::Basename;
use Data::Dumper;
my $MAX_TAKEN = 1000;
my $use_colors = -t STDIN;
my $BOLD = $use_colors ? "\033[1m" : "";
my $RESET = $use_colors ? "\033[0m" : "";
sub usage()
{
print(<<EOF)
Usage: $0 <config_file> [-o <output_dir>] [--seed <seed>] [<key>=<value>...]
Create a fake lcov code coverage data file and optionally the corresponding
source tree. DATA_FILE contains all specifications for creating the data
file. Directives can be overridden using KEY=VALUE specifications with KEY
being in the form SECTION.KEY. SEED specifies the number used to initialize
the pseudo random number generator.
Example:
$0 profiles/small -o src files.numfiles=12
EOF
}
sub read_config($)
{
my ($filename) = @_;
my $fd;
my %config;
my $section;
open($fd, "<", $filename) or die("Could not open $filename: $!\n");
while (my $line = <$fd>) {
my ($key, $value);
$line =~ s/(^\s*|\s*$)//g;
next if ($line eq "" || $line =~ /^#/);
if ($line =~ /^\[\s*(\S+)\s*]$/) {
$section = $1;
next;
}
if ($line !~ /^(\S+)\s*=\s*(.*)$/) {
die("$filename:$.: Unknown line format: $line\n");
}
($key, $value) = ($1, $2);
if (!defined($section)) {
die("$filename:$.: Directive outside of section\n");
}
$config{$section}->{$1} = $2;
}
close($fd);
return \%config;
}
sub apply_config($$)
{
my ($config, $directive) = @_;
for my $dir (@$directive) {
if ($dir !~ /^([^\.]+)\.([^=]+)=(.*)$/) {
die("Unknown directive format: $dir\n");
}
$config->{$1}->{$2} = $3;
}
}
sub get_value($$;$)
{
my ($config, $dir, $default) = @_;
my ($section, $key, $value);
if ($dir !~ /^([^\.]+)\.([^=]+)$/) {
die("$0: Internal error: Unknown key format: $key\n");
}
($section, $key) = ($1, $2);
$value = $config->{$section}->{$key};
if (!defined($value)) {
if (!defined($default)) {
die("$0: Missing config value for $dir\n");
}
$value = $default;
}
return $value;
}
sub get_int($$;$$$)
{
my ($config, $dir, $default, $min, $max) = @_;
my $value = get_value($config, $dir, $default);
if ($value !~ /^\d+$/) {
die("$0: Config value $dir must be an integer: $value\n");
}
$value = int($value);
if (defined($min) && $value < $min) {
die("$0: Config value $dir is too low (min $min): $value\n");
}
if (defined($max) && $value > $max) {
die("$0: Config value $dir is too high (max $max): $value\n");
}
return int($value);
}
sub get_list($$;$)
{
my ($config, $dir, $default) = @_;
my $value = get_value($config, $dir, $default);
my @list = split(/\s+/, $value);
return \@list;
}
sub randlist($)
{
my ($list) = @_;
return "" if (!@$list);
return $list->[int(rand(scalar(@$list)))];
}
sub randbool()
{
return int(rand(2));
}
# Reduce LIST to PERCENTAGE of its former size.
sub reduce_list_per($$)
{
my ($list, $percentage) = @_;
my $remove;
$remove = int((100 - $percentage) * scalar(@$list) / 100);
for (my $i = 0; $i < $remove; $i++) {
splice(@$list, int(rand(scalar(@$list))), 1);
}
}
# Reduce LIST to NUM items.
sub reduce_list_num($$)
{
my ($list, $num) = @_;
my $remove;
$remove = scalar(@$list) - $num;
for (my $i = 0; $i < $remove; $i++) {
splice(@$list, int(rand(scalar(@$list))), 1);
}
}
sub _gen_filename($$)
{
my ($c, $root) = @_;
my $ltop = get_list($c, "files.top", "");
my $lsub = get_list($c, "files.sub", "");
my $lsubsub = get_list($c, "files.subsub", "");
my $lprefix = get_list($c, "files.prefix");
my $lsuffix = get_list($c, "files.suffix", "");
my $lext = get_list($c, "files.ext");
my ($top, $sub, $subsub, $prefix, $suffix, $ext) =
("", "", "", "", "", "");
my $filename = "";
$top = randlist($ltop) if (randbool());
$sub = randlist($lsub) if (randbool());
$subsub = randlist($lsubsub) if (randbool());
$prefix = randlist($lprefix);
$suffix = randlist($lsuffix) if (randbool());
$ext = randlist($lext);
$filename = $root;
$filename .= "/".$top if ($top ne "");
$filename .= "/".$sub if ($sub ne "");
$filename .= "/".$subsub if ($subsub ne "");
$filename .= "/".$prefix;
$filename .= "_".$suffix if ($suffix ne "");
$filename .= $ext;
$filename =~ s#^//#/#;
return $filename;
}
sub gen_filename($$$)
{
my ($c, $root, $filenames) = @_;
my $filename;
do {
$filename = _gen_filename($c, $root);
} while ($filenames->{$filename});
$filenames->{$filename} = 1;
return $filename;
}
sub gen_lines($$)
{
my ($c, $length) = @_;
my @lines = 1 .. $length;
my $percent = get_int($c, "lines.instrumented", undef, 0, 100);
reduce_list_per(\@lines, $percent);
return \@lines;
}
sub gen_fnname($$)
{
my ($c, $hash) = @_;
my $lverb = get_list($c, "functions.verb");
my $ladj = get_list($c, "functions.adj", "");
my $lnoun = get_list($c, "functions.noun", "");
my ($verb, $adj, $noun) = ("", "", "");
my $fnname;
$verb = randlist($lverb);
$adj = randlist($ladj) if (randbool());
$noun = randlist($lnoun) if (randbool());
$fnname = $verb;
$fnname .= "_".$adj if ($adj ne "");
$fnname .= "_".$noun if ($noun ne "");
if (exists($hash->{$fnname})) {
my $i = 2;
while (exists($hash->{$fnname.$i})) {
$i++;
}
$fnname .= $i;
}
$hash->{$fnname} = 1;
return $fnname;
}
sub gen_functions($$)
{
my ($c, $lines) = @_;
my @fnlines;
my @functions;
my %names;
my $percent = get_int($c, "functions.perinstrumented", undef, 0, 100);
@fnlines = @$lines;
reduce_list_per(\@fnlines, $percent);
foreach my $fnline (@fnlines) {
push(@functions, [ $fnline, gen_fnname($c, \%names) ]);
}
return \@functions;
}
# Returns a value distribution object. This object can be used to randomly
# choose one element from a list of elements with a given relative distribution.
#
# dist: [ sumprob, probs]
# sumprob: Sum of all probabilities
# probs: [ prob1, prob2, ... ]
# prob: [ num, x ]
# num: Value
sub get_dist($$;$)
{
my ($c, $dir, $default) = @_;
my $list = get_list($c, $dir, $default);
my $sumprob = 0;
my @probs;
foreach my $spec (@$list) {
my ($n, $p);
if ($spec =~ /^(\d+):(\d+)$/) {
($n, $p) = ($1, $2);
} elsif ($spec =~ /^(\d+)$/) {
$n = $1;
$p = 1;
} else {
die("$0: Config value $dir must be a distribution ".
"list (a:p1 b:p2 ...)\n");
}
$sumprob += $p;
push(@probs, [ $n, $sumprob ]);
}
return [ $sumprob, \@probs ];
}
sub rand_dist($)
{
my ($dist) = @_;
my ($sumprob, $probs) = @$dist;
my $r = int(rand($sumprob));
foreach my $prob (@$probs) {
my ($num, $x) = @$prob;
return $num if ($r < $x);
}
die("Internal error: Incomplete distribution list\n");
}
sub gen_branches($$)
{
my ($c, $lines) = @_;
my $percent = get_int($c, "branches.perinstrumented", undef, 0, 100);
my @allblocks = @{get_list($c, "branches.blocks", "0")};
my $branchdist = get_dist($c, "branches.branchdist", "2");
my @brlines;
my @branches;
@brlines = @$lines;
reduce_list_per(\@brlines, $percent);
foreach my $brline (@brlines) {
my @blocks = @allblocks;
my $numblocks = int(rand(scalar(@blocks))) + 1;
reduce_list_num(\@blocks, $numblocks);
foreach my $block (@blocks) {
my $numbranch = rand_dist($branchdist);
for (my $branch = 0; $branch < $numbranch; $branch++) {
push(@branches, [ $brline, $block, $branch]);
}
}
}
return \@branches;
}
sub gen_filesrc($)
{
my ($c) = @_;
my ($length, $lines, $functions, $branches);
my $do_ln = get_int($c, "lines.enabled");
my $do_fn = get_int($c, "functions.enabled");
my $do_br = get_int($c, "branches.enabled");
$length = 1 + int(rand(get_int($c, "lines.maxlines")));
$lines = gen_lines($c, $length);
$functions = gen_functions($c, $lines) if ($do_fn);
$branches = gen_branches($c, $lines) if ($do_br);
return [ $length, $lines, $functions, $branches ];
}
# Generate fake source tree.
#
# returns: [ files, numlns, numfns, numbrs ]
# files: filename -> filesrc
# filesrc: [ length, lines, functions, branches ]
# length: Total number of lines in file
#
# lines: [ line1, line2, ... ]
#
# functions: [ fn1, fn2, ... ]
# fn: [ fnline, fnname ]
# fnline: Starting line of function
# fnname: Function name
#
# branches: [ brdata1, brdata2, ...]
# brdata: [ brline, block, branch ]
# brline: Line number containing branches
# block: Block ID
# branch: Branch ID
#
sub gen_src($$)
{
my ($c, $root) = @_;
my %files;
my $numfiles = get_int($c, "files.numfiles");
my %filenames;
my ($numlns, $numfns, $numbrs) = (0, 0, 0);
for (my $i = 0; $i < $numfiles; $i++) {
my $filename = gen_filename($c, $root, \%filenames);
my $filesrc = gen_filesrc($c);
$files{$filename} = $filesrc;
$numlns += scalar(@{$filesrc->[1]}) if (defined($filesrc->[1]));
$numfns += scalar(@{$filesrc->[2]}) if (defined($filesrc->[2]));
$numbrs += scalar(@{$filesrc->[3]}) if (defined($filesrc->[3]));
}
return [ \%files, $numlns, $numfns, $numbrs ];
}
sub write_src($)
{
my ($src) = @_;
my ($files, $numlns, $numfns, $numbrs) = @$src;
foreach my $filename (sort(keys(%{$files}))) {
my $filesrc = $files->{$filename};
my $length = $filesrc->[0];
my $dir = dirname($filename);
my $fd;
if (!-d $dir) {
make_path($dir) or
die("Could not create directory $dir\n");
}
open($fd, ">", $filename) or
die("Could not create file $filename: $!\n");
for (my $i = 0; $i < $length; $i++) {
print($fd "\n");
}
close($fd);
}
}
sub write_branches($$$$)
{
my ($fd, $branches, $brhits, $iref) = @_;
my ($found, $hit) = (0, 0);
# Line coverage data
foreach my $brdata (@$branches) {
my $brhit = $brhits->[$$iref++];
my ($brline, $block, $branch) = @$brdata;
$found++;
$hit++ if ($brhit ne "-" && $brhit > 0);
print($fd "BRDA:$brline,$block,$branch,$brhit\n");
}
if ($found > 0) {
print($fd "BRF:$found\n");
print($fd "BRH:$hit\n");
}
}
sub write_lines($$$$)
{
my ($fd, $lines, $lnhist, $iref) = @_;
my ($found, $hit) = (0, 0);
# Line coverage data
foreach my $line (@$lines) {
my $lnhit = $lnhist->[$$iref++];
$found++;
$hit++ if ($lnhit > 0);
print($fd "DA:$line,$lnhit\n");
}
print($fd "LF:$found\n");
print($fd "LH:$hit\n");
}
sub write_functions($$$$)
{
my ($fd, $functions, $fnhits, $iref) = @_;
my ($found, $hit) = (0, 0);
# Function coverage data
foreach my $fn (@$functions) {
my ($fnline, $fnname) = @$fn;
print($fd "FN:$fnline,$fnname\n");
}
foreach my $fn (@$functions) {
my ($fnline, $fnname) = @$fn;
my $fnhit = $fnhits->[$$iref++];
$found++;
$hit++ if ($fnhit > 0);
print($fd "FNDA:$fnhit,$fnname\n");
}
print($fd "FNF:$found\n");
print($fd "FNH:$hit\n");
}
sub write_filesrc($$$$$)
{
my ($c, $fd, $filesrc, $hits, $iter) = @_;
my ($length, $lines, $functions, $branches) = @$filesrc;
my $do_ln = get_int($c, "lines.enabled");
my $do_fn = get_int($c, "functions.enabled");
my $do_br = get_int($c, "branches.enabled");
write_functions($fd, $functions, $hits->[1], \$iter->[1]) if ($do_fn);
write_branches($fd, $branches, $hits->[2], \$iter->[2]) if ($do_br);
write_lines($fd, $lines, $hits->[0], \$iter->[0]) if ($do_ln);
}
sub write_info($$$$)
{
my ($c, $filename, $src, $hits) = @_;
my $files = $src->[0];
my $fd;
my %iters;
foreach my $testname (keys(%{$hits})) {
$iters{$testname} = [ 0, 0, 0 ];
}
open($fd, ">", $filename) or die("Could not create $filename: $!\n");
foreach my $filename (sort(keys(%{$files}))) {
my $filesrc = $files->{$filename};
foreach my $testname (sort(keys(%{$hits}))) {
my $testhits = $hits->{$testname};
my $iter = $iters{$testname};
print($fd "TN:$testname\n");
print($fd "SF:$filename\n");
write_filesrc($c, $fd, $filesrc, $testhits, $iter);
print($fd "end_of_record\n");
}
}
close($fd);
}
sub get_hit_found($)
{
my ($list) = @_;
my ($hit, $found) = (0, 0);
foreach my $e (@$list) {
$hit++ if ($e ne "-" && $e > 0);
$found++;
}
return ($hit, $found);
}
sub write_counts($$)
{
my ($filename, $hits) = @_;
my $fd;
my (@tlnhits, @tfnhits, @tbrhits);
foreach my $testname (keys(%{$hits})) {
my $testhits = $hits->{$testname};
my ($lnhits, $fnhits, $brhits) = @$testhits;
for (my $i = 0; $i < scalar(@$lnhits); $i++) {
$tlnhits[$i] += $lnhits->[$i];
}
for (my $i = 0; $i < scalar(@$fnhits); $i++) {
$tfnhits[$i] += $fnhits->[$i];
}
for (my $i = 0; $i < scalar(@$brhits); $i++) {
my $h = $brhits->[$i];
$h = 0 if ($h eq "-");
$tbrhits[$i] += $h;
}
}
open($fd, ">", $filename) or die("Could not create $filename: $!\n");
print($fd join(" ", get_hit_found(\@tlnhits), get_hit_found(\@tfnhits),
get_hit_found(\@tbrhits))."\n");
close($fd);
}
# A branch hit value for a block that was not hit must be "-". A branch hit
# value for a block that was hit cannot be "-", but must be "0" if not hit.
sub sanitize_brhits($)
{
my ($brhits) = @_;
my $block_hit = 0;
foreach my $brhit_ref (@$brhits) {
if ($$brhit_ref ne "-" && $$brhit_ref > 0) {
$block_hit = 1;
last;
}
}
foreach my $brhit_ref (@$brhits) {
if (!$block_hit) {
$$brhit_ref = "-";
} elsif ($$brhit_ref eq "-") {
$$brhit_ref = 0;
}
}
}
# Ensure coverage rate interdependencies are met
sub sanitize_hits($$)
{
my ($src, $hits) = @_;
my $files = $src->[0];
foreach my $hits (values(%{$hits})) {
my $brhits = $hits->[2];
my $i = 0;
foreach my $filename (sort(keys(%{$files}))) {
my $filesrc = $files->{$filename};
my $branches = $filesrc->[3];
my $lastblock;
my $lastline;
my @blist;
foreach my $brdata (@$branches) {
my ($brline, $block, $branch) = @$brdata;
if (!defined($lastblock) ||
$block != $lastblock ||
$brline != $lastline) {
sanitize_brhits(\@blist);
@blist = ();
$lastblock = $block;
$lastline = $brline;
}
push(@blist, \$brhits->[$i++]);
}
sanitize_brhits(\@blist);
}
}
}
# Generate random coverage data
#
# returns: testname -> testhits
# testhits: [ lnhits, fnhits, brhits ]
# lnhits: [ ln1hit, ln2hit, ... ]
# lnhit: Number of times a line was hit by a specific test
# fnhits: [ fn1hit, fn2hit, ... ]
# fnhit: Number of times a function was hit by a specific test
# brhits: [ br1hit, br2hit, ... ]
# brhit: Number of times a branch was hit by a specific test
sub gen_hits($$)
{
my ($c, $src) = @_;
my (@lnhits, @fnhits, @brhits);
my ($files, $numlns, $numfns, $numbrs) = @$src;
my $testnames = get_list($c, "tests.names", "");
my %hits;
$testnames = [ "" ] if (!@$testnames);
foreach my $testname (@$testnames) {
my (@lnhits, @fnhits, @brhits);
for (my $i = 0; $i < $numlns; $i++) {
push(@lnhits, 1 + int(rand($MAX_TAKEN)));
}
for (my $i = 0; $i < $numfns; $i++) {
push(@fnhits, 1 + int(rand($MAX_TAKEN)));
}
for (my $i = 0; $i < $numbrs; $i++) {
push(@brhits, 1 + int(rand($MAX_TAKEN)));
}
$hits{$testname} = [ \@lnhits, \@fnhits, \@brhits ];
}
sanitize_hits($src, \%hits);
return \%hits;
}
# Return a hash containing RATE percent of indices [0..NUM-1].
sub gen_filter($$)
{
my ($num, $rate) = @_;
my @list = (0 .. ($num - 1));
my %hash;
reduce_list_per(\@list, $rate);
foreach my $i (@list) {
$hash{$i} = 1;
}
return \%hash;
}
# Zero all entries in LIST identified by the indices in FILTER.
sub zero_by_filter($$)
{
my ($list, $filter) = @_;
foreach my $i (keys(%{$filter})) {
$list->[$i] = 0;
}
}
# Add a random number of indices between [0..NUM-1] to FILTER.
sub widen_filter($$)
{
my ($filter, $num) = @_;
my @list;
for (my $i = 0; $i < $num; $i++) {
push(@list, $i) if (!exists($filter->{$i}));
}
reduce_list_per(\@list, int(rand(101)));
foreach my $i (@list) {
$filter->{$i} = 1;
}
}
# Zero coverage data in HITS until the combined coverage rates reach the
# specified RATEs.
sub reduce_hits($$$$$)
{
my ($src, $hits, $lnrate, $fnrate, $brrate) = @_;
my ($files, $numlns, $numfns, $numbrs) = @$src;
my ($lnfilter, $fnfilter, $brfilter);
$lnfilter = gen_filter($numlns, 100 - $lnrate);
$fnfilter = gen_filter($numfns, 100 - $fnrate);
$brfilter = gen_filter($numbrs, 100 - $brrate);
foreach my $testhits (values(%{$hits})) {
my ($lnhits, $fnhits, $brhits) = @$testhits;
zero_by_filter($lnhits, $lnfilter);
zero_by_filter($fnhits, $fnfilter);
zero_by_filter($brhits, $brfilter);
# Provide some variation between tests
widen_filter($lnfilter, $numlns);
widen_filter($fnfilter, $numfns);
widen_filter($brfilter, $numbrs);
}
sanitize_hits($src, $hits);
}
sub zero_list($)
{
my ($list) = @_;
foreach my $i (@$list) {
$i = 0;
}
}
# Zero all coverage in HITS.
sub zero_hits($$)
{
my ($src, $hits) = @_;
foreach my $testhits (values(%{$hits})) {
my ($lnhits, $fnhits, $brhits) = @$testhits;
zero_list($lnhits);
zero_list($fnhits);
zero_list($brhits);
}
sanitize_hits($src, $hits);
}
# Distribute items from LIST to A and B depending on whether the index for
# an item is found in FILTER.
sub split_by_filter($$$$)
{
my ($list, $filter, $a, $b) = @_;
for (my $i = 0; $i < scalar(@$list); $i++) {
if (exists($filter->{$i})) {
push(@$a, $list->[$i]);
push(@$b, 0);
} else {
push(@$a, 0);
push(@$b, $list->[$i]);
}
}
}
sub split_hits($$$)
{
my ($c, $src, $hits) = @_;
my ($files, $numlns, $numfns, $numbrs) = @$src;
my ($lnsplit, $fnsplit, $brsplit);
my (%a, %b);
$lnsplit = gen_filter($numlns, int(rand(101)));
$fnsplit = gen_filter($numfns, int(rand(101)));
$brsplit = gen_filter($numbrs, int(rand(101)));
foreach my $testname (keys(%{$hits})) {
my $testhits = $hits->{$testname};
my ($lnhits, $fnhits, $brhits) = @$testhits;
my (@lnhitsa, @fnhitsa, @brhitsa);
my (@lnhitsb, @fnhitsb, @brhitsb);
split_by_filter($lnhits, $lnsplit, \@lnhitsa, \@lnhitsb);
split_by_filter($fnhits, $fnsplit, \@fnhitsa, \@fnhitsb);
split_by_filter($brhits, $brsplit, \@brhitsa, \@brhitsb);
$a{$testname} = [ \@lnhitsa, \@fnhitsa, \@brhitsa ];
$b{$testname} = [ \@lnhitsb, \@fnhitsb, \@brhitsb ];
}
sanitize_hits($src, \%a);
sanitize_hits($src, \%b);
return (\%a, \%b);
}
sub plural($$$)
{
my ($num, $sing, $plur) = @_;
return $num <= 1 ? $sing : $plur;
}
sub print_intro($)
{
my ($c) = @_;
my $numtests = scalar(@{get_list($c, "tests.names")});
my $numfiles = get_int($c, "files.numfiles");
$numtests = 1 if ($numtests < 1);
print($BOLD."Creating coverage files ($numtests ".
plural($numtests, "test", "tests").", $numfiles ".
plural($numfiles, "source file", "source files").")\n".$RESET);
}
sub main()
{
my $opt_help;
my $opt_output;
my $opt_configfile;
my $opt_seed = 0;
my $c;
my $src;
my $hits;
my $root;
my $enum;
my ($a, $b);
# Parse options
if (!GetOptions("output|o=s" => \$opt_output,
"seed=s" => \$opt_seed,
"help|h" => \$opt_help,
)) {
print(STDERR "Use $0 --help to get usage information\n");
exit(2);
}
if ($opt_help) {
usage();
exit(0);
}
$opt_configfile = shift(@ARGV);
if (!defined($opt_configfile)) {
print(STDERR "Please specify a config file\n");
exit(2);
}
if (defined($opt_output)) {
if (! -d $opt_output) {
mkdir($opt_output) or
die("$0: Could not create directory ".
"$opt_output: $!\n");
}
$root = abs_path($opt_output)
} else {
$root = "/";
}
srand($opt_seed);
# Get config
$c = read_config($opt_configfile);
apply_config($c, \@ARGV) if (@ARGV);
print_intro($c);
# Show lines on STDOUT without newline
$| = 1;
# Create source tree
print(" Source tree ......... ");
$src = gen_src($c, $root);
# Write out source code if requested
write_src($src) if (defined($opt_output));
print("done (");
print($src->[1]." lines, ");
print($src->[2]." functions, ");
print($src->[3]." branches)\n");
# Write out full-coverage data files
print(" Full coverage ....... ");
$hits = gen_hits($c, $src);
write_info($c, "full.info", $src, $hits);
write_counts("full.counts", $hits);
print("done\n");
# Write out data files with target coverage rates
print(" Target coverage ..... ");
reduce_hits($src, $hits, get_int($c, "lines.covered"),
get_int($c, "functions.covered"),
get_int($c, "branches.covered"));
write_info($c, "target.info", $src, $hits);
write_counts("target.counts", $hits);
print("done\n");
# Write out partial data files
print(" Partial coverage .... ");
($a, $b) = split_hits($c, $src, $hits);
write_info($c, "part1.info", $src, $a);
write_counts("part1.counts", $a);
write_info($c, "part2.info", $src, $b);
write_counts("part2.counts", $b);
print("done\n");
# Write out zero-coverage data files
print(" Zero coverage ....... ");
zero_hits($src, $hits);
write_info($c, "zero.info", $src, $hits);
write_counts("zero.counts", $hits);
print("done\n");
}
main();
exit(0);
#!/usr/bin/env perl
#
# Copyright IBM Corp. 2017
#
# Usage: norminfo <coverage-data-file> [<multiplier>]
#
# Normalize coverage data file (ensure stable order), perform some sanity
# checks, and apply optional multiplier to execution counts.
#
use strict;
use warnings;
sub ferr($$$)
{
my ($pos, $filename, $msg) = @_;
if (defined($pos)) {
$pos .= ":";
} else {
$pos = "";
}
die("$0:$filename:$pos $msg");
}
sub print_sorted($$$)
{
my ($fd, $info, $multi) = @_;
my (%fn, %fns, %fnda, %brda, %da);
my ($fnf, $fnh, $brf, $brh, $lf, $lh);
while (my $line = <$fd>) {
$line =~ s/(^\s*|\s*$)//g;
if ($line =~ /^end_of_record$/) {
last;
} elsif ($line =~ /^FN:(\d+),(.*)$/) {
my ($lineno, $fnname) = ($1, $2);
if (exists($fn{$lineno})) {
ferr($., $info, "Duplicate FN: entry\n");
}
$fn{$lineno} = $fnname;
if (exists($fns{$fnname})) {
ferr($., $info, "Duplicate function name\n");
}
$fns{$fnname} = $lineno;
} elsif ($line =~ /^FNDA:(\d+),(.*)$/) {
my ($count, $fnname) = ($1, $2);
if (exists($fnda{$fnname})) {
ferr($., $info, "Duplicate FNDA: entry\n");
}
$fnda{$fnname} = int($count * $multi);
} elsif ($line =~ /^FNF:(\d+)$/) {
if (defined($fnf)) {
ferr($., $info, "Duplicate FNF: entry\n");
}
$fnf = $1;
} elsif ($line =~ /^FNH:(\d+)$/) {
if (defined($fnh)) {
ferr($., $info, "Duplicate FNH: entry\n");
}
$fnh = $1;
} elsif ($line =~ /^BRDA:(\d+),(\d+),(\d+),(\d+|-)$/) {
my ($lineno, $block, $branch, $count) = ($1, $2, $3, $4);
if (exists($brda{$lineno}->{$block}->{$branch})) {
ferr($., $info, "Duplicate BRDA: entry\n");
}
$count = int($count * $multi) if ($count ne "-");
$brda{$lineno}->{$block}->{$branch} = $count;
} elsif ($line =~ /^BRF:(\d+)$/) {
if (defined($brf)) {
ferr($., $info, "Duplicate BRF: entry\n");
}
$brf = $1;
} elsif ($line =~ /^BRH:(\d+)$/) {
if (defined($brh)) {
ferr($., $info, "Duplicate BRH: entry\n");
}
$brh = $1;
} elsif ($line =~ /^DA:(\d+),(\d+)$/) {
my ($lineno, $count) = ($1, $2);
if (exists($da{$lineno})) {
ferr($., $info, "Duplicate FNDA: entry\n");
}
$da{$lineno} = int($count * $multi);
} elsif ($line =~ /^LF:(\d+)$/) {
if (defined($lf)) {
ferr($., $info, "Duplicate LF: entry\n");
}
$lf = $1;
} elsif ($line =~ /^LH:(\d+)$/) {
if (defined($lh)) {
ferr($., $info, "Duplicate LH: entry\n");
}
$lh = $1;
} else {
ferr($., $info, "Unknown line: $line\n");
}
}
# FN:<line>,<fnname>
foreach my $lineno (sort({ $a <=> $b } keys(%fn))) {
my $fnname = $fn{$lineno};
print("FN:$lineno,$fnname\n");
}
# FNDA:<counts>,<fnname>
foreach my $fnname (keys(%fnda)) {
if (!exists($fns{$fnname})) {
ferr(undef, $info, "FNDA entry without FN: $fnname\n");
}
}
foreach my $fnname (sort({ $fns{$a} <=> $fns{$b} } keys(%fnda))) {
my $count = $fnda{$fnname};
print("FNDA:$count,$fnname\n");
}
# FNF:<counts>
print("FNF:$fnf\n") if (defined($fnf));
# FNH:<counts>
if (defined($fnh)) {
$fnh = 0 if ($multi == 0);
print("FNH:$fnh\n");
}
# BRDA:<line>,<block>,<branch>,<count>
foreach my $lineno (sort({ $a <=> $b } keys(%brda))) {
my $blocks = $brda{$lineno};
foreach my $block (sort({ $a <=> $b } keys(%{$blocks}))) {
my $branches = $blocks->{$block};
foreach my $branch (sort({ $a <=> $b }
keys(%{$branches}))) {
my $count = $branches->{$branch};
$count = "-" if ($multi == 0);
print("BRDA:$lineno,$block,$branch,$count\n");
}
}
}
# BRF:<counts>
print("BRF:$brf\n") if (defined($brf));
# BRH:<counts>
if (defined($brh)) {
$brh = 0 if ($multi == 0);
print("BRH:$brh\n");
}
# DA:<line>,<counts>
foreach my $lineno (sort({ $a <=> $b } keys(%da))) {
my $count = $da{$lineno};
print("DA:$lineno,$count\n");
}
# LF:<counts>
print("LF:$lf\n") if (defined($lf));
# LH:<count>
if (defined($lh)) {
$lh = 0 if ($multi == 0);
print("LH:$lh\n");
}
}
sub main()
{
my $infofile = $ARGV[0];
my $multi = $ARGV[1];
# info: testname -> files
# files: infofile -> data
# data: [ starting offset, starting line ]
my %info;
my $fd;
my $tn = "";
my %allfiles;
$multi = 1 if (!defined($multi));
if (!defined($infofile)) {
$infofile = "standard input";
warn("$0: Reading data from standard input\n");
open($fd, "<&STDIN") or
die("$0: Could not duplicated stdin: $!\n");
} else {
open($fd, "<", $infofile) or
die("$0: Could not open $infofile: $!\n");
}
# Register starting positions of data sets
while (my $line = <$fd>) {
if ($line =~ /^TN:(.*)$/) {
$tn = $1;
} elsif ($line =~ /^SF:(.*)$/) {
my $sf = $1;
my $pos = tell($fd);
die("$0: Could not get file position: $!\n")
if ($pos == -1);
if (exists($info{$tn}->{$sf})) {
ferr($., $infofile,
"Duplicate entry for $tn:$sf\n");
}
$info{$tn}->{$sf} = [ $pos, $. ];
$allfiles{$sf} = 1;
}
}
# Print data sets in normalized order
foreach my $filename (sort(keys(%allfiles))) {
foreach my $testname (sort(keys(%info))) {
my $pos = $info{$testname}->{$filename};
my ($cpos, $lpos) = @$pos;
next if (!defined($pos));
if (seek($fd, $cpos, 0) != 1) {
die("$0: Could not seek in $infofile: $!\n");
}
printf("TN:$testname\n");
printf("SF:$filename\n");
$. = $lpos;
print_sorted($fd, $infofile, $multi);
printf("end_of_record\n");
}
}
foreach my $testname (sort(keys(%info))) {
my $files = $info{$testname};
foreach my $filename (sort(keys(%{$files}))) {
}
}
close($fd);
}
main();
exit(0);