App-cloc

 view release on metacpan or  search on metacpan

bin/cloc  view on Meta::CPAN

                             compared to the regex.
                             Add --fullpath to compare parent directories to
                             the regex.
                             Do not include file path separators at the
                             beginning or end of the regex.
   --match-f=<regex>         Only count files whose basenames match the Perl
                             regex.  For example
                               --match-f='^[Ww]idget'
                             only counts files that start with Widget or widget.
                             Add --fullpath to include parent directories
                             in the regex instead of just the basename.
   --not-match-f=<regex>     Count all files except those whose basenames
                             match the Perl regex.  Add --fullpath to include
                             parent directories in the regex instead of just
                             the basename.
   --skip-archive=<regex>    Ignore files that end with the given Perl regular
                             expression.  For example, if given
                               --skip-archive='(zip|tar(\.(gz|Z|bz2|xz|7z))?)'
                             the code will skip files that end with .zip,
                             .tar, .tar.gz, .tar.Z, .tar.bz2, .tar.xz, and
                             .tar.7z.
   --skip-win-hidden         On Windows, ignore hidden files.

 ${BB}Debug Options${NN}
   --categorized=<file>      Save names of categorized files to <file>.
   --counted=<file>          Save names of processed source files to <file>.
   --diff-alignment=<file>   Write to <file> a list of files and file pairs
                             showing which files were added, removed, and/or
                             compared during a run with --diff.  This switch
                             forces the --diff mode on.
   --explain=<lang>          Print the filters used to remove comments for
                             language <lang> and exit.  In some cases the
                             filters refer to Perl subroutines rather than
                             regular expressions.  An examination of the
                             source code may be needed for further explanation.
   --help                    Print this usage information and exit.
   --found=<file>            Save names of every file found to <file>.
   --ignored=<file>          Save names of ignored files and the reason they
                             were ignored to <file>.
   --print-filter-stages     Print processed source code before and after
                             each filter is applied.
   --show-ext[=<ext>]        Print information about all known (or just the
                             given) file extensions and exit.
   --show-lang[=<lang>]      Print information about all known (or just the
                             given) languages and exit.
   --show-os                 Print the value of the operating system mode
                             and exit.  See also --unix, --windows.
   -v[=<n>]                  Verbose switch (optional numeric value).
   -verbose[=<n>]            Long form of -v.
   --version                 Print the version of this program and exit.
   --write-lang-def=<file>   Writes to <file> the language processing filters
                             then exits.  Useful as a first step to creating
                             custom language definitions (see also
                             --force-lang-def, --read-lang-def).

 ${BB}Output Options${NN}
   --3                       Print third-generation language output.
                             (This option can cause report summation to fail
                             if some reports were produced with this option
                             while others were produced without it.)
   --by-percent  X           Instead of comment and blank line counts, show
                             these values as percentages based on the value
                             of X in the denominator:
                                X = 'c'   -> # lines of code
                                X = 'cm'  -> # lines of code + comments
                                X = 'cb'  -> # lines of code + blanks
                                X = 'cmb' -> # lines of code + comments + blanks
                             For example, if using method 'c' and your code
                             has twice as many lines of comments as lines
                             of code, the value in the comment column will
                             be 200%.  The code column remains a line count.
   --csv                     Write the results as comma separated values.
   --csv-delimiter=<C>       Use the character <C> as the delimiter for comma
                             separated files instead of ,.  This switch forces
   --json                    Write the results as JavaScript Object Notation
                             (JSON) formatted output.
   --md                      Write the results as Markdown-formatted text.
   --out=<file>              Synonym for --report-file=<file>.
   --progress-rate=<n>       Show progress update after every <n> files are
                             processed (default <n>=100).  Set <n> to 0 to
                             suppress progress output (useful when redirecting
                             output to STDOUT).
   --quiet                   Suppress all information messages except for
                             the final report.
   --report-file=<file>      Write the results to <file> instead of STDOUT.
   --sql=<file>              Write results as SQL create and insert statements
                             which can be read by a database program such as
                             SQLite.  If <file> is -, output is sent to STDOUT.
   --sql-append              Append SQL insert statements to the file specified
                             by --sql and do not generate table creation
                             statements.  Only valid with the --sql option.
   --sql-project=<name>      Use <name> as the project identifier for the
                             current run.  Only valid with the --sql option.
   --sql-style=<style>       Write SQL statements in the given style instead
                             of the default SQLite format.  Currently, the
                             only style option is Oracle.
   --sum-one                 For plain text reports, show the SUM: output line
                             even if only one input file is processed.
   --xml                     Write the results in XML.
   --xsl=<file>              Reference <file> as an XSL stylesheet within
                             the XML output.  If <file> is 1 (numeric one),
                             writes a default stylesheet, cloc.xsl (or
                             cloc-diff.xsl if --diff is also given).
                             This switch forces --xml on.
   --yaml                    Write the results in YAML.

";
#  Help information for options not yet implemented:
#  --inline                  Process comments that appear at the end
#                            of lines containing code.
#  --html                    Create HTML files of each input file showing
#                            comment and code lines in different colors.

$| = 1;  # flush STDOUT
my $start_time = get_time();
my (
    $opt_categorized          ,
    $opt_found                ,
    @opt_force_lang           ,
    $opt_lang_no_ext          ,
    @opt_script_lang          ,
    $opt_count_diff           ,
    $opt_diff                 ,
    $opt_diff_alignment       ,
    $opt_diff_timeout         ,
    $opt_html                 ,
    $opt_ignored              ,
    $opt_counted              ,
    $opt_show_ext             ,
    $opt_show_lang            ,
    $opt_progress_rate        ,
    $opt_print_filter_stages  ,
    $opt_v                    ,
    $opt_vcs                  ,
    $opt_version              ,
    $opt_exclude_lang         ,
    $opt_exclude_list_file    ,
    $opt_exclude_dir          ,
    $opt_explain              ,
    $opt_include_lang         ,
    $opt_force_lang_def       ,
    $opt_read_lang_def        ,
    $opt_write_lang_def       ,
    $opt_strip_comments       ,
    $opt_original_dir         ,
    $opt_quiet                ,
    $opt_report_file          ,
    $opt_sdir                 ,
    $opt_sum_reports          ,
    $opt_processes            ,
    $opt_unicode              ,
    $opt_no3                  ,   # accept it but don't use it
    $opt_3                    ,
    $opt_extract_with         ,
    $opt_by_file              ,
    $opt_by_file_by_lang      ,
    $opt_by_percent           ,
    $opt_xml                  ,
    $opt_xsl                  ,
    $opt_yaml                 ,
    $opt_csv                  ,
    $opt_csv_delimiter        ,
    $opt_fullpath             ,
    $opt_json                 ,
    $opt_md                   ,
    $opt_match_f              ,
    $opt_not_match_f          ,
    $opt_match_d              ,
    $opt_not_match_d          ,
    $opt_skip_uniqueness      ,
    $opt_list_file            ,
    $opt_help                 ,
    $opt_skip_win_hidden      ,
    $opt_read_binary_files    ,
    $opt_sql                  ,
    $opt_sql_append           ,
    $opt_sql_project          ,
    $opt_sql_style            ,
    $opt_inline               ,
    $opt_exclude_ext          ,
    $opt_ignore_whitespace    ,
    $opt_ignore_case          ,
    $opt_follow_links         ,
    $opt_autoconf             ,
    $opt_sum_one              ,
    $opt_stdin_name           ,
    $opt_force_on_windows     ,
    $opt_force_on_unix        ,   # actually forces !$ON_WINDOWS
    $opt_show_os              ,
    $opt_skip_archive         ,
    $opt_max_file_size        ,   # in MB
    $opt_use_sloccount        ,
    $opt_no_autogen           ,
    $opt_force_git            ,
   );
my $getopt_success = GetOptions(
   "by_file|by-file"                         => \$opt_by_file             ,
   "by_file_by_lang|by-file-by-lang"         => \$opt_by_file_by_lang     ,
   "categorized=s"                           => \$opt_categorized         ,
   "counted=s"                               => \$opt_counted             ,
   "include_lang|include-lang=s"             => \$opt_include_lang        ,
   "exclude_lang|exclude-lang=s"             => \$opt_exclude_lang        ,
   "exclude_dir|exclude-dir=s"               => \$opt_exclude_dir         ,
   "exclude_list_file|exclude-list-file=s"   => \$opt_exclude_list_file   ,
   "explain=s"                               => \$opt_explain             ,
   "extract_with|extract-with=s"             => \$opt_extract_with        ,
   "found=s"                                 => \$opt_found               ,
   "count_and_diff|count-and-diff"           => \$opt_count_diff          ,
   "diff"                                    => \$opt_diff                ,
   "diff-alignment|diff_alignment=s"         => \$opt_diff_alignment      ,
   "diff-timeout|diff_timeout=i"             => \$opt_diff_timeout        ,
   "html"                                    => \$opt_html                ,
   "ignored=s"                               => \$opt_ignored             ,
   "quiet"                                   => \$opt_quiet               ,
   "force_lang_def|force-lang-def=s"         => \$opt_force_lang_def      ,
   "read_lang_def|read-lang-def=s"           => \$opt_read_lang_def       ,
   "show_ext|show-ext:s"                     => \$opt_show_ext            ,
   "show_lang|show-lang:s"                   => \$opt_show_lang           ,
   "progress_rate|progress-rate=i"           => \$opt_progress_rate       ,
   "print_filter_stages|print-filter-stages" => \$opt_print_filter_stages ,
   "report_file|report-file=s"               => \$opt_report_file         ,
   "out=s"                                   => \$opt_report_file         ,
   "script_lang|script-lang=s"               => \@opt_script_lang         ,
   "sdir=s"                                  => \$opt_sdir                ,
   "skip_uniqueness|skip-uniqueness"         => \$opt_skip_uniqueness     ,
   "strip_comments|strip-comments=s"         => \$opt_strip_comments      ,
   "original_dir|original-dir"               => \$opt_original_dir        ,
   "sum_reports|sum-reports"                 => \$opt_sum_reports         ,
   "processes=n"                             => \$opt_processes           ,
   "unicode"                                 => \$opt_unicode             ,
   "no3"                                     => \$opt_no3                 ,  # ignored
   "3"                                       => \$opt_3                   ,
   "v|verbose:i"                             => \$opt_v                   ,
   "vcs=s"                                   => \$opt_vcs                 ,
   "version"                                 => \$opt_version             ,
   "write_lang_def|write-lang-def=s"         => \$opt_write_lang_def      ,
   "xml"                                     => \$opt_xml                 ,
   "xsl=s"                                   => \$opt_xsl                 ,
   "force_lang|force-lang=s"                 => \@opt_force_lang          ,
   "lang_no_ext|lang-no-ext=s"               => \$opt_lang_no_ext         ,
   "yaml"                                    => \$opt_yaml                ,
   "csv"                                     => \$opt_csv                 ,
   "csv_delimeter|csv-delimiter=s"           => \$opt_csv_delimiter       ,
   "json"                                    => \$opt_json                ,
   "md"                                      => \$opt_md                  ,
   "fullpath"                                => \$opt_fullpath            ,
   "match_f|match-f=s"                       => \$opt_match_f             ,
   "not_match_f|not-match-f=s"               => \$opt_not_match_f         ,
   "match_d|match-d=s"                       => \$opt_match_d             ,
   "not_match_d|not-match-d=s"               => \$opt_not_match_d         ,
   "list_file|list-file=s"                   => \$opt_list_file           ,
   "help"                                    => \$opt_help                ,
   "skip_win_hidden|skip-win-hidden"         => \$opt_skip_win_hidden     ,
   "read_binary_files|read-binary-files"     => \$opt_read_binary_files   ,
   "sql=s"                                   => \$opt_sql                 ,
   "sql_project|sql-project=s"               => \$opt_sql_project         ,
   "sql_append|sql-append"                   => \$opt_sql_append          ,
   "sql_style|sql-style=s"                   => \$opt_sql_style           ,
   "inline"                                  => \$opt_inline              ,
   "exclude_ext|exclude-ext=s"               => \$opt_exclude_ext         ,
   "ignore_whitespace|ignore-whitespace"     => \$opt_ignore_whitespace   ,
   "ignore_case|ignore-case"                 => \$opt_ignore_case         ,
   "follow_links|follow-links"               => \$opt_follow_links        ,
   "autoconf"                                => \$opt_autoconf            ,
   "sum_one|sum-one"                         => \$opt_sum_one             ,
   "by_percent|by-percent=s"                 => \$opt_by_percent          ,
   "stdin_name|stdin-name=s"                 => \$opt_stdin_name          ,
   "windows"                                 => \$opt_force_on_windows    ,
   "unix"                                    => \$opt_force_on_unix       ,
   "show_os|show-os"                         => \$opt_show_os             ,
   "skip_archive|skip-archive=s"             => \$opt_skip_archive        ,
   "max_file_size|max-file-size=i"           => \$opt_max_file_size       ,
   "use_sloccount|use-sloccount"             => \$opt_use_sloccount       ,
   "no_autogen|no-autogen"                   => \$opt_no_autogen          ,
   "git"                                     => \$opt_force_git           ,
  );
$opt_by_file  = 1 if defined  $opt_by_file_by_lang;
my $CLOC_XSL = "cloc.xsl"; # created with --xsl
   $CLOC_XSL = "cloc-diff.xsl" if $opt_diff;
die "\n" unless $getopt_success;
print $usage and exit if $opt_help;
my %Exclude_Language = ();
   %Exclude_Language = map { $_ => 1 } split(/,/, $opt_exclude_lang)
        if $opt_exclude_lang;
my %Exclude_Dir      = ();
   %Exclude_Dir      = map { $_ => 1 } split(/,/, $opt_exclude_dir )
        if $opt_exclude_dir ;
die unless exclude_dir_validates(\%Exclude_Dir);
my %Include_Language = ();
   %Include_Language = map { $_ => 1 } split(/,/, $opt_include_lang)
        if $opt_include_lang;
# Forcibly exclude .svn, .cvs, .hg, .git, .bzr directories.  The contents of these
# directories often conflict with files of interest.
$opt_exclude_dir       = 1;
$Exclude_Dir{".svn"}   = 1;
$Exclude_Dir{".cvs"}   = 1;
$Exclude_Dir{".hg"}    = 1;
$Exclude_Dir{".git"}   = 1;
$Exclude_Dir{".bzr"}   = 1;
$Exclude_Dir{".snapshot"} = 1;  # NetApp backups
$opt_count_diff        = defined $opt_count_diff ? 1 : 0;
$opt_diff              = 1  if $opt_diff_alignment;
$opt_exclude_ext       = "" unless $opt_exclude_ext;
$opt_ignore_whitespace = 0  unless $opt_ignore_whitespace;
$opt_ignore_case       = 0  unless $opt_ignore_case;
$opt_lang_no_ext       = 0  unless $opt_lang_no_ext;
$opt_follow_links      = 0  unless $opt_follow_links;
$opt_diff_timeout      =10  unless $opt_diff_timeout;
$opt_csv               = 1  if $opt_csv_delimiter;
$ON_WINDOWS            = 1  if $opt_force_on_windows;
$ON_WINDOWS            = 0  if $opt_force_on_unix;
$opt_max_file_size     = 100 unless $opt_max_file_size;
my $HAVE_SLOCCOUNT_c_count = 0;
if (!$ON_WINDOWS and $opt_use_sloccount) {
    # Only bother doing this kludgey test is user explicitly wants
    # to use SLOCCount.  Debian based systems will hang if just doing
    #  external_utility_exists("c_count")
    # if c_count is in $PATH; c_count expects to have input.
    $HAVE_SLOCCOUNT_c_count = external_utility_exists("c_count /bin/sh");
}
if ($opt_use_sloccount) {
    if (!$HAVE_SLOCCOUNT_c_count) {
        warn "c_count could not be found; ignoring --use-sloccount\n";
        $opt_use_sloccount = 0;
    } else {
        warn "Using c_count, php_count, xml_count, pascal_count from SLOCCount\n";
        warn "--diff is disabled with --use-sloccount\n" if $opt_diff;
        warn "--count-and-diff is disabled with --use-sloccount\n" if $opt_count_diff;
        warn "--unicode is disabled with --use-sloccount\n" if $opt_unicode;
        warn "--strip-comments is disabled with --use-sloccount\n" if $opt_strip_comments;
        $opt_diff           = 0;
        $opt_count_diff     = undef;
        $opt_unicode        = 0;
        $opt_strip_comments = 0;
    }
}
$opt_vcs = 0 if $opt_force_git;

my @COUNT_DIFF_ARGV        = undef;
my $COUNT_DIFF_report_file = undef;
if ($opt_count_diff) {
    die "--count-and-diff requires two arguments; got ", scalar @ARGV, "\n"
        if scalar @ARGV != 2;
    # prefix with a dummy term so that $opt_count_diff is the
    # index into @COUNT_DIFF_ARGV to work on at each pass
    @COUNT_DIFF_ARGV = (undef, $ARGV[0],
                               $ARGV[1],
                              [$ARGV[0], $ARGV[1]]);  # 3rd pass: diff them
    $COUNT_DIFF_report_file = $opt_report_file if $opt_report_file;
}

# Options defaults:
$opt_quiet         =   1 if ($opt_md or $opt_json) and !defined $opt_report_file;
$opt_progress_rate = 100 unless defined $opt_progress_rate;
$opt_progress_rate =   0 if     defined $opt_quiet;
if (!defined $opt_v) {
    $opt_v  = 0;
} elsif (!$opt_v) {
    $opt_v  = 1;
}
if (defined $opt_xsl) {
    $opt_xsl = $CLOC_XSL if $opt_xsl eq "1";
    $opt_xml = 1;
}
my $skip_generate_report = 0;
$opt_sql_style = 0 unless defined $opt_sql_style;
$opt_sql = 0 unless $opt_sql_style or defined $opt_sql;
if ($opt_sql eq "-" || $opt_sql eq "1") { # stream SQL output to STDOUT
    $opt_quiet            = 1;
    $skip_generate_report = 1;
    $opt_by_file          = 1;
    $opt_sum_reports      = 0;
    $opt_progress_rate    = 0;
} elsif ($opt_sql)  { # write SQL output to a file
    $opt_by_file          = 1;
    $skip_generate_report = 1;
    $opt_sum_reports      = 0;
}
if ($opt_sql_style) {
    $opt_sql_style = lc $opt_sql_style;
    if (!grep { lc $_ eq $opt_sql_style } qw ( Oracle )) {
        die "'$opt_sql_style' is not a recognized SQL style.\n";
    }
}
$opt_by_percent = '' unless defined $opt_by_percent;
if ($opt_by_percent and $opt_by_percent !~ m/^(c|cm|cb|cmb)$/i) {
    die "--by-percent must be either 'c', 'cm', 'cb', or 'cmb'\n";
}
$opt_by_percent = lc $opt_by_percent;

if (defined $opt_vcs) {
    if      ($opt_vcs eq "git") {
        $opt_vcs = "git ls-files";
        my @submodules = invoke_generator('git submodule status');
        foreach my $SM (@submodules) {
            $SM =~ s/^\s+//;        # may have leading space
            $SM =~ s/\(\S+\)\s*$//; # may end with something like (heads/master)
			my ($checksum, $dir) = split(' ', $SM, 2);
            $dir =~ s/\s+$//;
            $Exclude_Dir{$dir} = 1;
        }
    } elsif ($opt_vcs eq "svn") {
        $opt_vcs = "svn list -R";
    }
}

my $list_no_autogen = 0;
if (defined $opt_no_autogen and scalar @ARGV == 1 and $ARGV[0] eq "list") {
    $list_no_autogen = 1;
}

die $brief_usage unless defined $opt_version         or
                        defined $opt_show_lang       or
                        defined $opt_show_ext        or
                        defined $opt_show_os         or
                        defined $opt_write_lang_def  or
                        defined $opt_list_file       or
                        defined $opt_vcs             or
                        defined $opt_xsl             or
                        defined $opt_explain         or
                        $list_no_autogen             or
                        scalar @ARGV >= 1;
die "--diff requires two arguments; got ", scalar @ARGV, "\n"
    if $opt_diff and scalar @ARGV != 2;
if ($opt_version) {
    printf "$VERSION\n";
    exit;
}
replace_git_hash_with_tarfile(\@ARGV);
# 1}}}
# Step 1:  Initialize global constants.        {{{1
#
my $nFiles_Found = 0;  # updated in make_file_list
my (%Language_by_Extension, %Language_by_Script,
    %Filters_by_Language, %Not_Code_Extension, %Not_Code_Filename,
    %Language_by_File, %Scale_Factor, %Known_Binary_Archives,
    %EOL_Continuation_re,
   );
my $ALREADY_SHOWED_HEADER = 0;
my $ALREADY_SHOWED_XML_SECTION = 0;
my %Error_Codes = ( 'Unable to read'                => -1,
                    'Neither file nor directory'    => -2,
                    'Diff error (quoted comments?)' => -3,
                    'Diff error, exceeded timeout'  => -4,
                    'Line count, exceeded timeout'  => -5,
                  );
my @Autogen_to_ignore = no_autogen_files($list_no_autogen);
if ($opt_force_lang_def) {
    # replace cloc's definitions

bin/cloc  view on Meta::CPAN

               },
        '4' => { 'xml' => 'blank="%d" comment="%d" code="%d" ',
                 'txt' => "\%${spacing_2}d \%${spacing_2}d \%${spacing_2}d",
               },
        '5' => { 'xml' => 'blank="%.2f" comment="%.2f" code="%d" ',
                 'txt' => "\%3.2f \%3.2f \%${spacing_2}d",
               },
        '6' => { 'xml' => 'factor="%.2f" scaled="%.2f" ',
                 'txt' => ' x %6.2f = %14.2f',
               },
    );
    my $Style = "txt";
       $Style = "xml" if $opt_xml ;
       $Style = "xml" if $opt_yaml;  # not a typo; just set to anything but txt
       $Style = "xml" if $opt_json;  # not a typo; just set to anything but txt
       $Style = "xml" if $opt_csv ;  # not a typo; just set to anything but txt

    my $hyphen_line = sprintf "%s", '-' x (79 + $column_1_offset);
       $hyphen_line = sprintf "%s", '-' x (68 + $column_1_offset)
            if (!$opt_3) and (68 + $column_1_offset) > 79;
    my $data_line  = "";
    my $first_column;
    my $BY_LANGUAGE = 0;
    my $BY_FILE     = 0;
    if      ($report_type eq "by language") {
        $first_column = "Language";
        $BY_LANGUAGE  = 1;
    } elsif ($report_type eq "by file")     {
        $first_column = "File";
        $BY_FILE      = 1;
    } else {
        $first_column = "Report File";
    }

    my $header_line  = sprintf "%s v %s", $URL, $version;
    my $sum_files    = 1;
    my $sum_lines    = 1;
       $header_line .= sprintf("  T=%.2f s (%.1f files/s, %.1f lines/s)",
                        $elapsed_sec           ,
                        $sum_files/$elapsed_sec,
                        $sum_lines/$elapsed_sec) unless $opt_sum_reports;
    if ($Style eq "txt") {
        push @results, output_header($header_line, $hyphen_line, $BY_FILE);
    } elsif ($Style eq "csv") {
        die "csv";
    }

    # column headers
    if (!$opt_3 and $BY_FILE) {
        my $spacing_n = $spacing_1 - 11;
        $data_line  = sprintf "%-${spacing_n}s" , $first_column;
    } else {
        $data_line  = sprintf "%-${spacing_1}s ", $first_column;
    }
    if ($BY_FILE) {
        $data_line .= sprintf "%${spacing_2}s"   , ""     ;
    } else {
        $data_line .= sprintf "%${spacing_2}s "  , "files";
    }
    my $PCT_symbol = "";
       $PCT_symbol = " \%" if $opt_by_percent;
    $data_line .= sprintf "%${spacing_2}s %${spacing_2}s %${spacing_2}s",
        "blank${PCT_symbol}"         ,
        "comment${PCT_symbol}"       ,
        "code";

    if ($Style eq "txt") {
        push @results, $data_line;
        push @results, $hyphen_line;
    }

####foreach my $lang_or_file (keys %{$rhhh_count}) {
####    $rhhh_count->{$lang_or_file}{'code'} = 0 unless
####        defined $rhhh_count->{$lang_or_file}{'code'};
####}
    foreach my $lang_or_file (sort {
                                 $rhhh_count->{$b}{'code'} <=>
                                 $rhhh_count->{$a}{'code'}
                               }
                          keys %{$rhhh_count}) {

        if ($BY_FILE) {
            push @results, rm_leading_tempdir($lang_or_file, \%TEMP_DIR);
        } else {
            push @results, $lang_or_file;
        }
        foreach my $S (qw(same modified added removed)) {
            my $indent = $spacing_1 - 2;
            my $line .= sprintf " %-${indent}s", $S;
            if ($BY_FILE) {
                $line .= sprintf "   ";
            } else {
                $line .= sprintf "  %${spacing_2}s", $rhhh_count->{$lang_or_file}{'nFiles'}{$S};
            }
            if ($opt_by_percent) {
                my $DEN = compute_denominator($opt_by_percent  ,
                    $rhhh_count->{$lang_or_file}{'code'}{$S}   ,
                    $rhhh_count->{$lang_or_file}{'comment'}{$S},
                    $rhhh_count->{$lang_or_file}{'blank'}{$S}  );
                if ($rhhh_count->{$lang_or_file}{'code'}{$S} > 0) {
                    $line .= sprintf " %14.2f %14.2f %${spacing_2}s",
                        $rhhh_count->{$lang_or_file}{'blank'}{$S}   / $DEN * 100,
                        $rhhh_count->{$lang_or_file}{'comment'}{$S} / $DEN * 100,
                        $rhhh_count->{$lang_or_file}{'code'}{$S}    ;
                } else {
                    $line .= sprintf " %14.2f %14.2f %${spacing_2}s",
                        0.0, 0.0, $rhhh_count->{$lang_or_file}{'code'}{$S}    ;
                }
            } else {
                $line .= sprintf " %${spacing_2}s %${spacing_2}s %${spacing_2}s",
                    $rhhh_count->{$lang_or_file}{'blank'}{$S}   ,
                    $rhhh_count->{$lang_or_file}{'comment'}{$S} ,
                    $rhhh_count->{$lang_or_file}{'code'}{$S}    ;
            }
            push @results, $line;
        }
    }
    push @results, $hyphen_line;
    push @results, "SUM:";
    foreach my $S (qw(same modified added removed)) {
        my $indent = $spacing_1 - 2;
        my $line .= sprintf " %-${indent}s", $S;
            if ($BY_FILE) {
                $line .= sprintf "   ";
            } else {
                $line .= sprintf "  %${spacing_2}s", $sum{'nFiles'}{$S};
            }
        if ($opt_by_percent) {
            my $DEN = compute_denominator($opt_by_percent,
                $sum{'code'}{$S}, $sum{'comment'}{$S}, $sum{'blank'}{$S});
            if ($sum{'code'}{$S} > 0) {
                $line .= sprintf " %14.2f %14.2f %${spacing_2}s",
                    $sum{'blank'}{$S}   / $DEN * 100,
                    $sum{'comment'}{$S} / $DEN * 100,
                    $sum{'code'}{$S}    ;
            } else {
                $line .= sprintf " %14.2f %14.2f %${spacing_2}s",
                    0.0, 0.0, $sum{'code'}{$S}    ;
            }
        } else {
            $line .= sprintf " %${spacing_2}s %${spacing_2}s %${spacing_2}s",
                $sum{'blank'}{$S}   ,
                $sum{'comment'}{$S} ,
                $sum{'code'}{$S}    ;
        }
        push @results, $line;
    }
    push @results, $hyphen_line;
    write_xsl_file() if $opt_xsl and $opt_xsl eq $CLOC_XSL;
    print "<- diff_report\n" if $opt_v > 2;

    return @results;
} # 1}}}
sub xml_yaml_or_json_header {                # {{{1
    my ($URL, $version, $elapsed_sec, $sum_files, $sum_lines, $by_file) = @_;
    print "-> xml_yaml_or_json_header\n" if $opt_v > 2;
    my $header      = "";
    my $file_rate   = $sum_files/$elapsed_sec;
    my $line_rate   = $sum_lines/$elapsed_sec;
    my $type        = "";
       $type        = "diff_" if $opt_diff;
    my $report_file = "";
    if ($opt_report_file) {
        if ($opt_sum_reports) {
            if ($by_file) {
                $report_file = "  <report_file>$opt_report_file.file</report_file>"
            } else {
                $report_file = "  <report_file>$opt_report_file.lang</report_file>"
            }
        } else {
            $report_file = "  <report_file>$opt_report_file</report_file>"
        }
    }
    if ($opt_xml) {
        $header = "<?xml version=\"1.0\"?>";
        $header .= "\n<?xml-stylesheet type=\"text/xsl\" href=\"" . $opt_xsl . "\"?>" if $opt_xsl;
        $header .= "<${type}results>
<header>
  <cloc_url>$URL</cloc_url>
  <cloc_version>$version</cloc_version>
  <elapsed_seconds>$elapsed_sec</elapsed_seconds>
  <n_files>$sum_files</n_files>
  <n_lines>$sum_lines</n_lines>
  <files_per_second>$file_rate</files_per_second>
  <lines_per_second>$line_rate</lines_per_second>";
        $header .= "\n$report_file"
            if $opt_report_file;
        $header .= "\n</header>";
    } elsif ($opt_yaml or $opt_json) {

bin/cloc  view on Meta::CPAN

            }
        }
    }

    my $BY_LANGUAGE = 0;
    my $BY_FILE     = 0;
    if      ($report_type eq "by language") {
        $BY_LANGUAGE  = 1;
    } elsif ($report_type eq "by file")     {
        $BY_FILE      = 1;
    }
    return $sum_lines, $sum_files, $BY_FILE, $BY_LANGUAGE;
} # 1}}}
sub diff_xml_report {                        # {{{1
    # returns an array of lines containing the results
    my ($version    , # in
        $elapsed_sec, # in
        $report_type, # in  "by language" | "by report file" | "by file"
        $rhhh_count , # in  count{TYPE}{nFiles|code|blank|comment}{a|m|r|s}
        $rh_scale   , # in
       ) = @_;
    print "-> diff_xml_report\n" if $opt_v > 2;
    my ($Q, $open_B, $close_B, $start, $C) = yaml_to_json_separators();

#print "diff_report: ", Dumper($rhhh_count), "\n";
    $elapsed_sec = 0.5 unless $elapsed_sec;
    my @results       = ();
    my %sum           = ();
    my $languages     = ();

    my ($sum_lines, $sum_files, $BY_FILE, $BY_LANGUAGE) =
        diff_header_sum($report_type, $rhhh_count, \%sum);

    my $data_line   = "";

    if (!$ALREADY_SHOWED_HEADER) {
        push @results,
              xml_yaml_or_json_header($URL, $version, $elapsed_sec,
                                 $sum_files, $sum_lines, $BY_FILE);
        $ALREADY_SHOWED_HEADER = 1;
    }

    foreach my $S (qw(same modified added removed)) {
        push @results, "  <$S>";
        foreach my $lang_or_file (sort {
                                     $rhhh_count->{$b}{'code'} <=>
                                     $rhhh_count->{$a}{'code'}
                                   }
                              keys %{$rhhh_count}) {
            my $L = "";

            if ($BY_FILE) {
                $L .= sprintf "    <file name=\"%s\" files_count=\"1\" ",
                    xml_metachars(
                        rm_leading_tempdir($lang_or_file, \%TEMP_DIR));
            } else {
                $L .= sprintf "    <language name=\"%s\" files_count=\"%d\" ",
                        $lang_or_file ,
                        $rhhh_count->{$lang_or_file}{'nFiles'}{$S};
            }
            if ($opt_by_percent) {
              my $DEN = compute_denominator($opt_by_percent            ,
                            $rhhh_count->{$lang_or_file}{'code'}{$S}   ,
                            $rhhh_count->{$lang_or_file}{'comment'}{$S},
                            $rhhh_count->{$lang_or_file}{'blank'}{$S}  );
              foreach my $T (qw(blank comment)) {
                  if ($rhhh_count->{$lang_or_file}{'code'}{$S} > 0) {
                    $L .= sprintf "%s=\"%.2f\" ",
                            $T, $rhhh_count->{$lang_or_file}{$T}{$S} / $DEN * 100;
                  } else {
                    $L .= sprintf "%s=\"0.0\" ", $T;
                  }
              }
              foreach my $T (qw(code)) {
                  $L .= sprintf "%s=\"%d\" ",
                          $T, $rhhh_count->{$lang_or_file}{$T}{$S};
              }
            } else {
              foreach my $T (qw(blank comment code)) {
                  $L .= sprintf "%s=\"%d\" ",
                          $T, $rhhh_count->{$lang_or_file}{$T}{$S};
              }
            }
            push @results, $L . "/>";
        }


        my $L = sprintf "    <total sum_files=\"%d\" ", $sum{'nFiles'}{$S};
        if ($opt_by_percent) {
          my $DEN = compute_denominator($opt_by_percent,
                        $sum{'code'}{$S}   ,
                        $sum{'comment'}{$S},
                        $sum{'blank'}{$S}  );
          foreach my $V (qw(blank comment)) {
              if ($sum{'code'}{$S} > 0) {
                  $L .= sprintf "%s=\"%.2f\" ", $V, $sum{$V}{$S} / $DEN * 100;
              } else {
                  $L .= sprintf "%s=\"0.0\" ", $V;
              }
          }
          foreach my $V (qw(code)) {
              $L .= sprintf "%s=\"%d\" ", $V, $sum{$V}{$S};
          }
        } else {
          foreach my $V (qw(blank comment code)) {
              $L .= sprintf "%s=\"%d\" ", $V, $sum{$V}{$S};
          }
        }
        push @results, $L . "/>";
        push @results, "  </$S>";
    }

    push @results, "</diff_results>";
    write_xsl_file() if $opt_xsl and $opt_xsl eq $CLOC_XSL;
    print "<- diff_xml_report\n" if $opt_v > 2;
    return @results;
} # 1}}}
sub diff_csv_report {                        # {{{1
    # returns an array of lines containing the results
    my ($version    , # in
        $elapsed_sec, # in
        $report_type, # in  "by language" | "by report file" | "by file"
        $rhhh_count , # in  count{TYPE}{nFiles|code|blank|comment}{a|m|r|s}
        $rh_scale   , # in  unused
       ) = @_;
    print "-> diff_csv_report\n" if $opt_v > 2;

#use Data::Dumper;
#print "diff_csv_report: ", Dumper($rhhh_count), "\n";
#die;
    my @results       = ();
    my $languages     = ();

    my $data_line   = "";
    my $BY_LANGUAGE = 0;
    my $BY_FILE     = 0;
    if      ($report_type eq "by language") {
        $BY_LANGUAGE  = 1;
    } elsif ($report_type eq "by file")     {
        $BY_FILE      = 1;
    }
    my $DELIM = ",";
       $DELIM = $opt_csv_delimiter if defined $opt_csv_delimiter;

    $elapsed_sec = 0.5 unless $elapsed_sec;

    my $line = "Language${DELIM} ";
       $line = "File${DELIM} " if $BY_FILE;
    foreach my $item (qw(files blank comment code)) {
        next if $BY_FILE and $item eq 'files';
        foreach my $symbol ( '==', '!=', '+', '-', ) {
            $line .= "$symbol $item${DELIM} ";
        }
    }
    $line .= "\"$URL v $version T=$elapsed_sec s\"";
    push @results, $line;

    foreach my $lang_or_file (keys %{$rhhh_count}) {
        $rhhh_count->{$lang_or_file}{'code'}{'added'} = 0 unless
            defined $rhhh_count->{$lang_or_file}{'code'};
    }
    foreach my $lang_or_file (sort {
                                 $rhhh_count->{$b}{'code'} <=>
                                 $rhhh_count->{$a}{'code'}
                               }
                          keys %{$rhhh_count}) {
        if ($BY_FILE) {
            $line = rm_leading_tempdir($lang_or_file, \%TEMP_DIR) . "$DELIM ";
        } else {
            $line = $lang_or_file . "${DELIM} ";
        }
        if ($opt_by_percent) {
          foreach my $item (qw(nFiles)) {
              next if $BY_FILE and $item eq 'nFiles';
              foreach my $symbol (qw(same modified added removed)) {
                  if (defined $rhhh_count->{$lang_or_file}{$item}{$symbol}) {
                      $line .= "$rhhh_count->{$lang_or_file}{$item}{$symbol}${DELIM} ";
                  } else {
                      $line .= "0${DELIM} ";
                  }
              }
          }
          foreach my $item (qw(blank comment)) {
              foreach my $symbol (qw(same modified added removed)) {
                  if (defined $rhhh_count->{$lang_or_file}{$item}{$symbol} and
                      defined $rhhh_count->{$lang_or_file}{'code'}{$symbol} and
                      $rhhh_count->{$lang_or_file}{'code'}{$symbol} > 0) {
                      $line .= sprintf("%.2f", $rhhh_count->{$lang_or_file}{$item}{$symbol} / $rhhh_count->{$lang_or_file}{'code'}{$symbol} * 100).${DELIM};
                  } else {
                      $line .= "0.00${DELIM} ";
                  }
              }
          }
          foreach my $item (qw(code)) {
              foreach my $symbol (qw(same modified added removed)) {
                  if (defined $rhhh_count->{$lang_or_file}{$item}{$symbol}) {
                      $line .= "$rhhh_count->{$lang_or_file}{$item}{$symbol}${DELIM} ";
                  } else {
                      $line .= "0${DELIM} ";
                  }
              }
          }
        } else {
          foreach my $item (qw(nFiles blank comment code)) {
              next if $BY_FILE and $item eq 'nFiles';
              foreach my $symbol (qw(same modified added removed)) {
                  if (defined $rhhh_count->{$lang_or_file}{$item}{$symbol}) {
                      $line .= "$rhhh_count->{$lang_or_file}{$item}{$symbol}${DELIM} ";
                  } else {
                      $line .= "0${DELIM} ";
                  }
              }
          }
        }
        push @results, $line;
    }

    print "<- diff_csv_report\n" if $opt_v > 2;
    return @results;
} # 1}}}
sub rm_leading_tempdir {                     # {{{1
    my ($in_file, $rh_temp_dirs, ) = @_;
    my $clean_filename = $in_file;
    foreach my $temp_d (keys %{$rh_temp_dirs}) {
        if ($ON_WINDOWS) {
        # \ -> / necessary to allow the next if test's
        # m{} to work in the presence of spaces in file names
            $temp_d         =~ s{\\}{/}g;
            $clean_filename =~ s{\\}{/}g;
        }
        if ($clean_filename =~ m{^$temp_d/}) {
            $clean_filename =~ s{^$temp_d/}{};

bin/cloc  view on Meta::CPAN

       $Style = "xml" if $opt_json;  # not a typo; just set to anything but txt
       $Style = "xml" if $opt_csv ;  # not a typo; just set to anything but txt

    my $hyphen_line = sprintf "%s", '-' x (79 + $column_1_offset);
       $hyphen_line = sprintf "%s", '-' x (68 + $column_1_offset)
            if (!$opt_sum_reports) and (!$opt_3) and (68 + $column_1_offset) > 79;
    my $data_line  = "";
    my $first_column;
    my $BY_LANGUAGE = 0;
    my $BY_FILE     = 0;
    if      ($report_type eq "by language") {
        $first_column = "Language";
        $BY_LANGUAGE  = 1;
    } elsif ($report_type eq "by file")     {
        $first_column = "File";
        $BY_FILE      = 1;
    } elsif ($report_type eq "by report file")     {
        $first_column = "File";
    } else {
        $first_column = "Report File";
    }

    my $header_line  = sprintf "%s v %s", $URL, $version;
       $header_line .= sprintf("  T=%.2f s (%.1f files/s, %.1f lines/s)",
                        $elapsed_sec           ,
                        $sum_files/$elapsed_sec,
                        $sum_lines/$elapsed_sec) unless $opt_sum_reports;
    if ($opt_xml or $opt_yaml or $opt_json) {
        if (!$ALREADY_SHOWED_HEADER) {
            push @results, xml_yaml_or_json_header($URL, $version, $elapsed_sec,
                                                   $sum_files, $sum_lines, $BY_FILE);
            $ALREADY_SHOWED_HEADER = 1 unless $opt_sum_reports;
            # --sum-reports yields two xml or yaml files, one by
            # language and one by report file, each of which needs a header
        }
        if ($opt_xml) {
            if ($BY_FILE or ($report_type eq "by report file")) {
                push @results, "<files>";
            } else {
                push @results, "<languages>";
            }
        }
    } else {
        push @results, output_header($header_line, $hyphen_line, $BY_FILE);
    }

    if ($Style eq "txt") {
        # column headers
        if (!$opt_3 and $BY_FILE) {
            my $spacing_n = $spacing_1 - 11;
            $data_line  = sprintf "%-${spacing_n}s ", $first_column;
        } else {
            $data_line  = sprintf "%-${spacing_1}s ", $first_column;
        }
        if ($BY_FILE) {
            $data_line .= sprintf "%${spacing_2}s "  , " "    ;
        } else {
            $data_line .= sprintf "%${spacing_2}s "  , "files";
        }
        my $PCT_symbol = "";
           $PCT_symbol = " \%" if $opt_by_percent;
        $data_line .= sprintf "%${spacing_2}s %${spacing_2}s %${spacing_2}s",
            "blank${PCT_symbol}"   ,
            "comment${PCT_symbol}" ,
            "code";
        $data_line .= sprintf " %8s   %14s",
            "scale"         ,
            "3rd gen. equiv"
              if $opt_3;
        if ($opt_md) {
            my @col_header  = ();
            if ($data_line =~ m{\s%}) {
                $data_line =~ s{\s%}{_%}g;
                foreach my $w ( split(' ', $data_line) ) {
                    $w =~ s{_%}{ %};
                    push @col_header, $w;
                }
            } else {
                push @col_header, split(' ', $data_line);
            }
            my @col_hyphens    = ( '-------:') x scalar(@col_header);
               $col_hyphens[0] =   ':-------'; # first column left justified
            push @results, join("|", @col_header );
            push @results, join("|", @col_hyphens);
        } else {
            push @results, $data_line;
            push @results, $hyphen_line;
        }
    }

    if ($opt_csv)  {
        my $header2;
        if ($BY_FILE) {
            $header2 = "language${DELIM}filename";
        } else {
            $header2 = "files${DELIM}language";
        }
        $header2 .= "${DELIM}blank${DELIM}comment${DELIM}code";
        $header2 .= "${DELIM}scale${DELIM}3rd gen. equiv" if $opt_3;
        $header2 .= ${DELIM} . '"' . $header_line . '"';
        push @results, $header2;
    }

    my $sum_scaled = 0;
####foreach my $lang_or_file (keys %{$rhh_count}) {
####    $rhh_count->{$lang_or_file}{'code'} = 0 unless
####        defined $rhh_count->{$lang_or_file}{'code'};
####}
    foreach my $lang_or_file (sort {
                                 $rhh_count->{$b}{'code'} <=>
                                 $rhh_count->{$a}{'code'}
                               }
                          keys %{$rhh_count}) {
        next if $lang_or_file eq "by report file";
        my ($factor, $scaled);
        if ($BY_LANGUAGE or $BY_FILE) {
            $factor = 1;
            if ($BY_LANGUAGE) {
                if (defined $rh_scale->{$lang_or_file}) {
                    $factor = $rh_scale->{$lang_or_file};
                } else {
                    warn "No scale factor for $lang_or_file; using 1.00";
                }
            } else { # by individual code file
                if ($report_type ne "by report file") {
                    next unless defined $rhh_count->{$lang_or_file}{'lang'};
                    next unless defined $rh_scale->{$rhh_count->{$lang_or_file}{'lang'}};
                    $factor = $rh_scale->{$rhh_count->{$lang_or_file}{'lang'}};
                }
            }
            $scaled = $factor*$rhh_count->{$lang_or_file}{'code'};
        } else {
            if (!defined $rhh_count->{$lang_or_file}{'scaled'}) {
                $opt_3 = 0;
                # If we're summing together files previously generated
                # with --no3 then rhh_count->{$lang_or_file}{'scaled'}
                # this variable will be undefined.  That should only
                # happen when summing together by file however.
            } elsif ($BY_LANGUAGE) {
                warn "Missing scaled language info for $lang_or_file\n";
            }
            if ($opt_3) {
                $scaled =         $rhh_count->{$lang_or_file}{'scaled'};
                $factor = $scaled/$rhh_count->{$lang_or_file}{'code'};
            }
        }

        if ($BY_FILE) {
            my $clean_filename = rm_leading_tempdir($lang_or_file, \%TEMP_DIR);
               $clean_filename = xml_metachars($clean_filename) if $opt_xml;
            $data_line  = sprintf $Format{'1'}{$Style}, $clean_filename;
        } else {
            $data_line  = sprintf $Format{'2'}{$Style}, $lang_or_file;
        }
        $data_line .= sprintf $Format{3}{$Style}  ,
                        $rhh_count->{$lang_or_file}{'nFiles'} unless $BY_FILE;
        if ($opt_by_percent) {
          my $DEN = compute_denominator($opt_by_percent       ,
                        $rhh_count->{$lang_or_file}{'code'}   ,
                        $rhh_count->{$lang_or_file}{'comment'},
                        $rhh_count->{$lang_or_file}{'blank'}  );
          $data_line .= sprintf $Format{5}{$Style}  ,
              $rhh_count->{$lang_or_file}{'blank'}   / $DEN * 100,
              $rhh_count->{$lang_or_file}{'comment'} / $DEN * 100,
              $rhh_count->{$lang_or_file}{'code'}   ;
        } else {
          $data_line .= sprintf $Format{4}{$Style}  ,
              $rhh_count->{$lang_or_file}{'blank'}  ,
              $rhh_count->{$lang_or_file}{'comment'},
              $rhh_count->{$lang_or_file}{'code'}   ;
        }
        $data_line .= sprintf $Format{6}{$Style}  ,
            $factor                               ,
            $scaled if $opt_3;
        $sum_scaled  += $scaled if $opt_3;

        if ($opt_xml) {
            if (defined $rhh_count->{$lang_or_file}{'lang'}) {
                my $lang = $rhh_count->{$lang_or_file}{'lang'};
                if (!defined $languages->{$lang}) {
                    $languages->{$lang} = $lang;
                }
                $data_line.=' language="' . $lang . '" ';
            }
            if ($BY_FILE or ($report_type eq "by report file")) {
                push @results, "  <file " . $data_line . "/>";
            } else {
                push @results, "  <language " . $data_line . "/>";
            }
        } elsif ($opt_yaml or $opt_json) {
            my ($Q, $open_B, $close_B, $start, $C) = yaml_to_json_separators();
            push @results,"${Q}" . rm_leading_tempdir($lang_or_file, \%TEMP_DIR). "${Q} :$open_B";
            push @results,"  ${Q}nFiles${Q}: " . $rhh_count->{$lang_or_file}{'nFiles'} . $C
                unless $BY_FILE;
            if ($opt_by_percent) {
              my $DEN = compute_denominator($opt_by_percent       ,
                            $rhh_count->{$lang_or_file}{'code'}   ,
                            $rhh_count->{$lang_or_file}{'comment'},
                            $rhh_count->{$lang_or_file}{'blank'}  );
              push @results,"  ${Q}blank_pct${Q}: "   .
                sprintf("%3.2f", $rhh_count->{$lang_or_file}{'blank'} / $DEN * 100) . $C;
              push @results,"  ${Q}comment_pct${Q}: " .
                sprintf("%3.2f", $rhh_count->{$lang_or_file}{'comment'} / $DEN * 100) . $C;
              push @results,"  ${Q}code${Q}: "    . $rhh_count->{$lang_or_file}{'code'}  . $C;
            } else {
              push @results,"  ${Q}blank${Q}: "   . $rhh_count->{$lang_or_file}{'blank'}   . $C;
              push @results,"  ${Q}comment${Q}: " . $rhh_count->{$lang_or_file}{'comment'} . $C;
              push @results,"  ${Q}code${Q}: "    . $rhh_count->{$lang_or_file}{'code'}    . $C;
            }
            push @results,"  ${Q}language${Q}: "  . $Q . $rhh_count->{$lang_or_file}{'lang'} . $Q . $C
                if $BY_FILE;
            if ($opt_3) {
                push @results, "  ${Q}scaled${Q}: " . $scaled . $C;
                push @results, "  ${Q}factor${Q}: " . $factor . $C;
            }
            if ($opt_json) { # replace the trailing comma with }, on the last line
                $results[-1] =~ s/,\s*$/},/;
            }
        } elsif ($opt_csv or $opt_md) {
            my $extra_3 = "";
               $extra_3 = "${DELIM}$factor${DELIM}$scaled" if $opt_3;
            my $first_column = undef;
            my $clean_name   = $lang_or_file;
            my $str;
            if ($opt_csv) {
                if ($BY_FILE) {
                    $first_column = $rhh_count->{$lang_or_file}{'lang'};
                    $clean_name   = rm_leading_tempdir($lang_or_file, \%TEMP_DIR);
                } else {
                    $first_column = $rhh_count->{$lang_or_file}{'nFiles'};
                }
                $str = $first_column   . ${DELIM} .
                       $clean_name     . ${DELIM};
            } else {
                if ($BY_FILE) {
                    $first_column = $rhh_count->{$lang_or_file}{'lang'};
                    $clean_name   = rm_leading_tempdir($lang_or_file, \%TEMP_DIR);
                    $str = $clean_name . ${DELIM};
                } else {
                    $first_column = $rhh_count->{$lang_or_file}{'nFiles'};
                    $str = $clean_name     . ${DELIM} .
                           $first_column   . ${DELIM};
                }
            }
            if ($opt_by_percent) {
              my $DEN = compute_denominator($opt_by_percent               ,
                            $rhh_count->{$lang_or_file}{'code'}   ,
                            $rhh_count->{$lang_or_file}{'comment'},
                            $rhh_count->{$lang_or_file}{'blank'}  );
              $str .= sprintf("%3.2f", $rhh_count->{$lang_or_file}{'blank'}   / $DEN * 100) . ${DELIM} .
                      sprintf("%3.2f", $rhh_count->{$lang_or_file}{'comment'} / $DEN * 100) . ${DELIM} .
                      $rhh_count->{$lang_or_file}{'code'};
            } else {
              $str .= $rhh_count->{$lang_or_file}{'blank'}  . ${DELIM} .
                      $rhh_count->{$lang_or_file}{'comment'}. ${DELIM} .
                      $rhh_count->{$lang_or_file}{'code'};
            }
            $str .= $extra_3;
            push @results, $str;

        } else {
            push @results, $data_line;
        }
    }

    my $avg_scale = 1;  # weighted average of scale factors
       $avg_scale = sprintf("%.2f", $sum_scaled / $sum_code)
            if $sum_code and $opt_3;

    if ($opt_xml) {
        $data_line = "";
        if (!$BY_FILE) {
            $data_line .= sprintf "sum_files=\"%d\" ", $sum_files;
        }
        if ($opt_by_percent) {
          my $DEN = compute_denominator($opt_by_percent    ,
                        $sum_code, $sum_comment, $sum_blank);
          $data_line .= sprintf $Format{'5'}{$Style},
              $sum_blank   / $DEN * 100,
              $sum_comment / $DEN * 100,
              $sum_code    ;
        } else {
          $data_line .= sprintf $Format{'4'}{$Style},
              $sum_blank   ,
              $sum_comment ,
              $sum_code    ;
        }
        $data_line .= sprintf $Format{'6'}{$Style},
            $avg_scale   ,
            $sum_scaled  if $opt_3;
        push @results, "  <total " . $data_line . "/>";

        if ($BY_FILE or ($report_type eq "by report file")) {
            push @results, "</files>";
        } else {
            foreach my $language (keys %{$languages}) {
                push @results, '  <language name="' . $language . '"/>';
            }
            push @results, "</languages>";
        }

        if (!$opt_by_file_by_lang or $ALREADY_SHOWED_XML_SECTION) {
            push @results, "</results>";
        } else {
            $ALREADY_SHOWED_XML_SECTION = 1;
        }
    } elsif ($opt_yaml or $opt_json) {
        my ($Q, $open_B, $close_B, $start, $C) = yaml_to_json_separators();
        push @results, "${Q}SUM${Q}: ${open_B}";
        if ($opt_by_percent) {
          my $DEN = compute_denominator($opt_by_percent    ,
                        $sum_code, $sum_comment, $sum_blank);
          push @results, "  ${Q}blank${Q}: "  . sprintf("%.2f", $sum_blank   / $DEN * 100) . $C;
          push @results, "  ${Q}comment${Q}: ". sprintf("%.2f", $sum_comment / $DEN * 100) . $C;
          push @results, "  ${Q}code${Q}: "   . $sum_code    . $C;
        } else {
          push @results, "  ${Q}blank${Q}: "  . $sum_blank   . $C;
          push @results, "  ${Q}comment${Q}: ". $sum_comment . $C;
          push @results, "  ${Q}code${Q}: "   . $sum_code    . $C;
        }
        push @results, "  ${Q}nFiles${Q}: " . $sum_files   . $C;
        if ($opt_3) {
            push @results, "  ${Q}scaled${Q}: " . $sum_scaled . $C;
            push @results, "  ${Q}factor${Q}: " . $avg_scale  . $C;
        }
        if ($opt_json) {
            $results[-1] =~ s/,\s*$/} }/;
        }
    } elsif ($opt_csv) {
        # do nothing
    } else {

        if ($BY_FILE) {
            $data_line  = sprintf "%-${spacing_0}s ", "SUM:"  ;
        } else {
            $data_line  = sprintf "%-${spacing_1}s ", "SUM:"  ;
            $data_line .= sprintf "%${spacing_2}d ", $sum_files;
        }
        if ($opt_by_percent) {
          my $DEN = compute_denominator($opt_by_percent    ,
                        $sum_code, $sum_comment, $sum_blank);
          $data_line .= sprintf $Format{'5'}{$Style},
              $sum_blank   / $DEN * 100,
              $sum_comment / $DEN * 100,
              $sum_code    ;
        } else {
          $data_line .= sprintf $Format{'4'}{$Style},
              $sum_blank   ,
              $sum_comment ,
              $sum_code    ;
        }
        $data_line .= sprintf $Format{'6'}{$Style},
            $avg_scale   ,
            $sum_scaled if $opt_3;
        if ($opt_md) {
            my @words = split(' ', $data_line);
            my $n_cols = scalar(@words);
#           my $n_cols = scalar(split(' ', $data_line));  # deprecated
            $data_line =~ s/\s+/\|/g;
            my @col_hyphens    = ( '--------') x $n_cols;
            push @results, join("|", @col_hyphens);
            push @results, $data_line   if $sum_files > 1 or $opt_sum_one;
            unshift @results, ( "cloc|$header_line", "--- | ---", "", );
        } else {
            push @results, $hyphen_line if $sum_files > 1 or $opt_sum_one;
            push @results, $data_line   if $sum_files > 1 or $opt_sum_one;
            push @results, $hyphen_line;
        }
    }
    write_xsl_file() if $opt_xsl and $opt_xsl eq $CLOC_XSL;
    print "<- generate_report\n" if $opt_v > 2;
    return @results;
} # 1}}}
sub print_errors {                           # {{{1
    my ($rh_Error_Codes, # in
        $raa_errors    , # in
       ) = @_;

    print "-> print_errors\n" if $opt_v > 2;
    my %error_string = reverse(%{$rh_Error_Codes});
    my $nErrors      = scalar @{$raa_errors};
    warn sprintf "\n%d error%s:\n", plural_form(scalar @Errors);
    for (my $i = 0; $i < $nErrors; $i++) {
        warn sprintf "%s:  %s\n",
                     $error_string{ $raa_errors->[$i][0] },
                     $raa_errors->[$i][1] ;
    }
    print "<- print_errors\n" if $opt_v > 2;

} # 1}}}
sub write_lang_def {                         # {{{1
    my ($file                     ,
        $rh_Language_by_Extension , # in
        $rh_Language_by_Script    , # in
        $rh_Language_by_File      , # in
        $rhaa_Filters_by_Language , # in
        $rh_Not_Code_Extension    , # in
        $rh_Not_Code_Filename     , # in
        $rh_Scale_Factor          , # in
        $rh_EOL_Continuation_re   , # in

bin/cloc  view on Meta::CPAN

                    config.h.in
                    config.rpath
                    config.status
                    config.sub
                    configure
                    configure.in
                    depcomp
                    gendocs.sh
                    gitlog-to-changelog
                    git-version-gen
                    gnupload
                    gnu-web-doc-update
                    install-sh
                    libtool
                    libtool.m4
                    link-warning.h
                    ltmain.sh
                    lt~obsolete.m4
                    ltoptions.m4
                    ltsugar.m4
                    ltversion.in
                    ltversion.m4
                    Makefile.in
                    mdate-sh
                    missing
                    mkinstalldirs
                    test-driver
                    texinfo.tex
                    update-copyright
                    useless-if-before-free
                    vc-list-files
                    ylwrap
                   );

    if ($print) {
        printf "cloc will ignore these %d files with --no-autogen:\n", scalar @files;
        foreach my $F (@files) {
            print "    $F\n";
        }
        print "Additionally, Go files with '// Code generated by .* DO NOT EDIT.'\n";
        print "on the first line are ignored.\n";
    }
    print "<- no_autogen()\n" if $opt_v > 2;
    return @files;
} # 1}}}
# subroutines copied from SLOCCount
my %lex_files    = ();  # really_is_lex()
my %expect_files = ();  # really_is_expect()
my %php_files    = ();  # really_is_php()
sub really_is_lex {                          # {{{1
# Given filename, returns TRUE if its contents really is lex.
# lex file must have "%%", "%{", and "%}".
# In theory, a lex file doesn't need "%{" and "%}", but in practice
# they all have them, and requiring them avoid mislabeling a
# non-lexfile as a lex file.

 my $filename = shift;
 chomp($filename);

 my $is_lex = 0;      # Value to determine.
 my $percent_percent = 0;
 my $percent_opencurly = 0;
 my $percent_closecurly = 0;

 # Return cached result, if available:
 if ($lex_files{$filename}) { return $lex_files{$filename};}

 open(LEX_FILE, "<$filename") ||
      die "Can't open $filename to determine if it's lex.\n";
 while(<LEX_FILE>) {
   $percent_percent++     if (m/^\s*\%\%/);
   $percent_opencurly++   if (m/^\s*\%\{/);
   $percent_closecurly++   if (m/^\s*\%\}/);
 }
 close(LEX_FILE);

 if ($percent_percent && $percent_opencurly && $percent_closecurly)
          {$is_lex = 1;}

 $lex_files{$filename} = $is_lex; # Store result in cache.

 return $is_lex;
} # 1}}}
sub really_is_expect {                       # {{{1
# Given filename, returns TRUE if its contents really are Expect.
# Many "exp" files (such as in Apache and Mesa) are just "export" data,
# summarizing something else # (e.g., its interface).
# Sometimes (like in RPM) it's just misc. data.
# Thus, we need to look at the file to determine
# if it's really an "expect" file.

 my $filename = shift;
 chomp($filename);

# The heuristic is as follows: it's Expect _IF_ it:
# 1. has "load_lib" command and either "#" comments or {}.
# 2. {, }, and one of: proc, if, [...], expect

 my $is_expect = 0;      # Value to determine.

 my $begin_brace = 0;  # Lines that begin with curly braces.
 my $end_brace = 0;    # Lines that begin with curly braces.
 my $load_lib = 0;     # Lines with the Load_lib command.
 my $found_proc = 0;
 my $found_if = 0;
 my $found_brackets = 0;
 my $found_expect = 0;
 my $found_pound = 0;

 # Return cached result, if available:
 if ($expect_files{$filename}) { return expect_files{$filename};}

 open(EXPECT_FILE, "<$filename") ||
      die "Can't open $filename to determine if it's expect.\n";
 while(<EXPECT_FILE>) {

   if (m/#/) {$found_pound++; s/#.*//;}
   if (m/^\s*\{/) { $begin_brace++;}
   if (m/\{\s*$/) { $begin_brace++;}
   if (m/^\s*\}/) { $end_brace++;}
   if (m/\};?\s*$/) { $end_brace++;}
   if (m/^\s*load_lib\s+\S/) { $load_lib++;}
   if (m/^\s*proc\s/) { $found_proc++;}
   if (m/^\s*if\s/) { $found_if++;}
   if (m/\[.*\]/) { $found_brackets++;}
   if (m/^\s*expect\s/) { $found_expect++;}
 }
 close(EXPECT_FILE);

 if ($load_lib && ($found_pound || ($begin_brace && $end_brace)))
          {$is_expect = 1;}
 if ( $begin_brace && $end_brace &&
      ($found_proc || $found_if || $found_brackets || $found_expect))
          {$is_expect = 1;}

 $expect_files{$filename} = $is_expect; # Store result in cache.

bin/cloc  view on Meta::CPAN

Print cloc's internal usage information and exit.

=item B<--found=FILE>

Save names of every file found to FILE.

=item B<--ignored=FILE>

Save names of ignored files and the reason they were ignored to FILE.

=item B<--print-filter-stages>

Print to I<STDOUT> processed source code before and after each filter is
applied.

=item B<--show-ext[=EXT]>

Print information about all known (or just the given) file extensions
and exit.

=item B<--show-lang[=LANG]>

Print information about all known (or just the given) languages and
exit.

=item B<--show-os>

Print the value of the operating system mode and exit.  See also
B<--unix>, B<--windows>.

=item B<-v[=N]>

Turn on verbose with optional numeric value.

=item B<--verbose[=N]>

Long form of B<-v>.

=item B<--version>

Print the version of this program and exit.

=item B<--write-lang-def=FILE>

Writes to FILE the language processing filters then exits. Useful as a
first step to creating custom language definitions. See also
B<--force-lang-def>, B<--read-lang-def>.

=back

=head2 Output Options

=over 4

=item B<--3>

Print third-generation language output.  (This option can cause report
summation to fail if some reports were produced with this option while
others were produced without it.)

=item B<--by-percent X>

Instead of comment and blank line counts, show
these values as percentages based on the
value of X in the denominator:

    X = 'c'   -> # lines of code
    X = 'cm'  -> # lines of code + comments
    X = 'cb'  -> # lines of code + blanks
    X = 'cmb' -> # lines of code + comments + blanks

For example, if using method 'c' and your code
has twice as many lines of comments as lines
of code, the value in the comment column will
be 200%.  The code column remains a line count.

=item B<--csv>

Write the results as comma separated values.

=item B<--csv-delimiter=C>

Use the character C as the delimiter for comma separated files
instead of ,.  This switch forces B<--csv> to be on.

=item B<--json>

Write the results in JavaScript Object Notation (JSON).

=item B<--md>

Write the results as Markdown-formatted text.

=item B<--out=FILE>

Synonym for B<--report-file=FILE>.

=item B<--progress-rate=N>

Show progress update after every N files are processed (default
N=100). Set N to 0 to suppress progress output; useful when
redirecting output to I<STDOUT>.

=item B<--quiet>

Suppress all information messages except for the final report.

=item B<--report-file=FILE>

Write the results to FILE instead of standard output.

=item B<--sql=FILE>

Write results as SQL CREATE and INSERT statements which can be read by
a database program such as SQLite. If FILE is B<->, output is sent to
I<STDOUT>.

=item B<--sql-append>

Append SQL insert statements to the file specified by B<--sql> and
do not generate table creation option.

=item B<--sql-project=NAME>



( run in 3.022 seconds using v1.01-cache-2.11-cpan-0bb4e1dffa6 )