Files
pkgsrc-ng/pkgtools/pkglint/files/PkgLint/FileUtil.pm
2013-09-26 17:14:40 +02:00

168 lines
3.7 KiB
Perl

package PkgLint::FileUtil;
#==========================================================================
# This package provides subroutines for loading and saving line-oriented
# files. The load_file() subroutine loads a file completely into memory,
# optionally handling continuation line folding. The load_lines() subrou-
# tine is an abbreviation for the common case of loading files without
# continuation lines. The save_autofix_changes() subroutine examines an
# array of lines if some of them have changed. It then saves the modified
# files.
#==========================================================================
use strict;
use warnings;
BEGIN {
use Exporter;
use vars qw(@ISA @EXPORT_OK);
@ISA = qw(Exporter);
@EXPORT_OK = qw(
load_file load_lines
save_autofix_changes
);
import PkgLint::Util qw(
false true
);
import PkgLint::Logging qw(
NO_LINE_NUMBER
log_error log_note
);
}
sub load_physical_lines($) {
my ($fname) = @_;
my ($physlines, $line, $lineno);
$physlines = [];
open(F, "< $fname") or return undef;
$lineno = 0;
while (defined($line = <F>)) {
$lineno++;
push(@{$physlines}, [$lineno, $line]);
}
close(F) or return undef;
return $physlines;
}
sub get_logical_line($$$) {
my ($fname, $lines, $ref_lineno) = @_;
my ($value, $lineno, $first, $firstlineno, $lastlineno, $physlines);
$value = "";
$first = true;
$lineno = ${$ref_lineno};
$firstlineno = $lines->[$lineno]->[0];
$physlines = [];
for (; $lineno <= $#{$lines}; $lineno++) {
if ($lines->[$lineno]->[1] =~ m"^([ \t]*)(.*?)([ \t]*)(\\?)\n?$") {
my ($indent, $text, $outdent, $cont) = ($1, $2, $3, $4);
if ($first) {
$value .= $indent;
$first = false;
}
$value .= $text;
push(@{$physlines}, $lines->[$lineno]);
if ($cont eq "\\") {
$value .= " ";
} else {
$value .= $outdent;
last;
}
}
}
if ($lineno > $#{$lines}) {
# The last line in the file is a continuation line
$lineno--;
}
$lastlineno = $lines->[$lineno]->[0];
${$ref_lineno} = $lineno + 1;
return PkgLint::Line->new($fname,
$firstlineno == $lastlineno
? $firstlineno
: "$firstlineno--$lastlineno",
$value,
$physlines);
}
sub load_lines($$) {
my ($fname, $fold_backslash_lines) = @_;
my ($physlines, $seen_newline, $loglines);
$physlines = load_physical_lines($fname);
if (!$physlines) {
return false;
}
$seen_newline = true;
$loglines = [];
if ($fold_backslash_lines) {
for (my $lineno = 0; $lineno <= $#{$physlines}; ) {
push(@{$loglines}, get_logical_line($fname, $physlines, \$lineno));
}
} else {
foreach my $physline (@{$physlines}) {
my $text = $physline->[1];
$text =~ s/\n$//;
push(@{$loglines}, PkgLint::Line->new($fname, $physline->[0], $text, [$physline]));
}
}
if (0 <= $#{$physlines} && $physlines->[-1]->[1] !~ m"\n$") {
log_error($fname, $physlines->[-1]->[0], "File must end with a newline.");
}
return $loglines;
}
sub load_file($) {
my ($fname) = @_;
return load_lines($fname, false);
}
sub save_autofix_changes($) {
my ($lines) = @_;
my (%changed, %physlines);
foreach my $line (@{$lines}) {
if ($line->is_changed) {
$changed{$line->fname}++;
}
push(@{$physlines{$line->fname}}, @{$line->physlines});
}
foreach my $fname (sort(keys(%changed))) {
my $new = "${fname}.pkglint.tmp";
if (!open(F, ">", $new)) {
log_error($new, NO_LINE_NUMBER, "$!");
next;
}
foreach my $physline (@{$physlines{$fname}}) {
print F ($physline->[1]);
}
if (!close(F)) {
log_error($new, NO_LINE_NUMBER, "$!");
next;
}
if (!rename($new, $fname)) {
log_error($fname, NO_LINE_NUMBER, "$!");
next;
}
log_note($fname, NO_LINE_NUMBER, "Has been autofixed. Please re-run pkglint.");
}
}
#== End of PkgLint::FileUtil ==============================================
1;