blob: a034fd49ce2a245c576959b812845cbcb8ec5d7a [file] [log] [blame]
#!/usr/bin/perl
use warnings;
use strict;
my $basedir = "docs/log-message-tags";
my $serial_file = "$basedir/next-number";
my $serial = read_serial($serial_file);
my $orig_serial = $serial;
my %tags;
foreach my $file (@ARGV) {
if ($file !~ /\.c$/) {
print STDERR "Skipping non-C file $file\n";
next;
}
process($file);
}
write_file($serial_file, "$serial\n") if $serial != $orig_serial;
my $list = "";
foreach my $tag (sort keys %tags) {
my $d = $tags{$tag};
$list .= "$tag: $d->{file}:$d->{line}: $d->{msg}\n";
}
write_file("$basedir/list", $list);
exit 0;
sub process
{
my $file = shift;
open(my $fh, "<", $file) or die "open $file: $!";
#print STDERR "processing $file\n";
my $line = <$fh>;
my $modified;
my $result = "";
while (defined $line) {
if ($line =~ s{APLOGNO\(\),?}{gen_tag($file)}e) {
$modified = 1;
}
if ($line =~ /APLOGNO\(\s*(\d{5})\s*\)/ ) {
my $lineno = $.;
my $tag = $1;
while (1) {
if ($line =~ s/.*?
APLOGNO\(\s*
(\d+)
\s*\)
(
(?: [\s\n]*
(?:"
(?:\\"|[^"])+ # a string constant
"
|
\w+ # things like APR_SIZE_T_FMT
)
)* # zero or more string fragments. We allow
# zero because some logging constructs may
# use things like:
# logno=APLOGNO(...);
# ap_log_...(..., "%s...", logno, ...)
)
[\s\n]*
[,);:\\] # the "," before the next argument,
# or the closing brace of ap_log...(),
# or the end of a statement (if used
# outside of ap_log_...),
# or ":" in things like:
# cond ? "msg1" : "msg2",
# or "\" at the end of a macro line
//xs) {
my $match = $&;
note_tag($file, $lineno, $1, $2);
$result .= $match;
last;
}
else {
my $next = <$fh>;
defined $next or die "can't find end of format string in $file:$lineno";
$line .= $next;
if ($next =~ /^#/) {
# log format inside preprocessor #if, that's too complicated
note_tag($file, $lineno, $tag, "");
$result .= $line;
$line = "";
last;
}
}
};
}
else {
$result .= $line;
$line = <$fh>;
}
}
close $fh;
write_file($file, $result) if $modified;
}
sub gen_tag
{
my $file = shift;
my $msg = shift;
my $tag = sprintf('%05d', $serial++);
return "APLOGNO($tag)";
}
sub note_tag
{
my $file = shift;
my $lineno = shift;
my $tag = shift;
my $msg = shift;
my $oneline = "";
while (length $msg) {
$msg =~ s/^[\s\n]+//s;
if ($msg =~ s{^"((?:\\"|[^"])+)"}{}) {
$oneline .= $1;
}
if ($msg =~ s{^(\w+)}{}) {
$oneline .= $1;
}
}
if (exists $tags{$tag}) {
print STDERR "WARNING: Duplicate tag $tag at $tags{$tag}->{file}:$tags{$tag}->{line} and $file:$lineno\n";
}
if ($tag >= $serial) {
print STDERR "WARNING: next-number $serial inconsistent with tag $tag at $file:$lineno, adjusting\n";
$serial = $tag + 1;
}
$tags{$tag} = { file => $file, line => $lineno, msg => $oneline };
}
sub write_file
{
my $file = shift;
my $data = shift;
my $tmpname = "$file.$$.tmp";
open(my $fh, ">", $tmpname) or die "open $tmpname: $!";
print $fh $data or die "write $tmpname: $!";
close($fh) or die "close $tmpname: $!";
rename($tmpname, $file) or die "rename $tmpname -> $file: $!";
print STDERR "Updated $file\n";
}
sub read_serial
{
my $name = shift;
open(my $fh, "<", $name) or die "can't open $name, need to be started in the top source dir";
my $num = <$fh>;
chomp $num;
$num =~ /^\d+$/ or die "invalid serial in $name: $num";
return $num;
}