bind9/util/update_copyrights
Ondřej Surý 9fb6d11abb Convert the documentation to Sphinx documentation format
The ARM and the manpages have been converted into Sphinx documentation
format.

Sphinx uses reStructuredText as its markup language, and many of its
strengths come from the power and straightforwardness of
reStructuredText and its parsing and translating suite, the Docutils.
2020-05-07 16:02:56 +02:00

636 lines
20 KiB
Perl

#!/usr/local/bin/perl -w
#
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
require 5.002;
# Map copyright owners to the files containing copyright messages.
# The first line of the copyright message is not in the file;
# it is constructed by this script.
#
# Usage:
#
# perl util/update_copyrights <util/copyrights
my %owner2filename = (
"" => "util/COPYRIGHT",
TOP => "util/COPYRIGHT.TOP",
"NAI" => "util/COPYRIGHT.NAI",
"NOM" => "util/COPYRIGHT.NOM",
"BSDI" => "util/COPYRIGHT.BSDI",
"BRIEF" => "util/COPYRIGHT.BRIEF",
"PORTION" => "util/COPYRIGHT.PORTION",
);
# Map each copyright owner name to a reference to an array containing
# the lines of the copyright message.
my %owner2text = ();
my $keyword_pat = '\$(Id:.*|Revision:.*|Id|Revision)\$';
foreach $owner (keys %owner2filename) {
my $f = $owner2filename{$owner};
open(COPYRIGHT, "<$f") || die "can't open $f: $!";
@copyright_text = <COPYRIGHT>;
close(COPYRIGHT);
$owner2text{$owner} = [ @copyright_text ];
}
my %file_types = ();
my %file_years = ();
my $years_list;
my $parent;
($dummy,$dummy,$dummy,$dummy,$this_month,$this_year,$dummy,$dummy,$dummy) = localtime(time());
$this_year += 1900;
while (<>) {
chomp;
($file, $type, $years) = split(/\s+/);
$file_types{$file} = $type;
$file_years{$file} = $years;
}
sub getyears {
$parent = $_[0];
$parent =~ s/PARENT://;
$years_list = $file_years{$parent};
if (defined($years_list) && $years_list =~ /^PARENT:/) {
print "BAD PARENT:$parent\n";
undefine($years_list);
}
}
sub docbook {
$parent = $_[0];
$parent =~ s/\.[^.]*$/.docbook/;
$years_list = $file_years{$parent};
}
sub copyright {
my $holder = shift;
my $result = "";
return $result unless (@_);
$result = "$result <copyright>\n";
$result = "$result <year>$_</year>\n" foreach (@_);
$result = "$result <holder>$holder</holder>\n";
$result = "$result </copyright>\n";
return $result;
}
sub copyrights {
my $a = copyright("Internet Systems Consortium, Inc. (\"ISC\")", @_);
return "$a";
}
my $ret = 0;
foreach $file (keys %file_types) {
$typeandowner = $file_types{$file};
$years_list = $file_years{$file};
if ( ! -f $file ) {
print "$file: missing\n";
$ret++;
next;
}
# print "Doing: $file";
if ($years_list =~ /PARENT:/) {
getyears($years_list);
if (!defined $years_list) {
print "$file: has bad parent $parent\n";
$ret++;
next;
}
}
# copyright notice is now generated from the source.
next if ($years_list eq "DOCBOOK");
if ($years_list eq "DOCBOOK") {
docbook($file);
if (!defined $years_list) {
print "$file: has bad parent $parent\n";
$ret++;
next;
}
}
@years = split(/,/, $years_list);
my ($type, $owner) = split(/\./, $typeandowner);
$owner = "" if !defined $owner;
$textp = $owner2text{$owner};
if (!defined $textp) {
print "$file: unknown copyright owner $owner\n";
$ret++;
next;
}
if ($file eq "./CHANGES" || $file eq "./EXCLUDED" ||
$file eq "./CHANGES.SE")
{
open(SOURCE, "<$file") || die "can't open $file: $!";
my $body = "";
while (<SOURCE>) {
# Process leading white space.
# Remove 1-7 spaces followed by a tab into a single
# tab if at start of line or proceeded by tabs.
s/^(\t*) {1,7}\t/$1\t/ while (/^\t* {1,7}\t/);
s/^(\s{0,3}\d*\.)\s(\[\w{1,5}\])\s+(\S+)/$1\t$2\t\t$3/;
s/^(\s{0,3}\d*\.)\s(\[\w{6,}\])\s+(\S+)/$1\t$2\t$3/;
# Convert 8 spaces into tabs if at start of line
# or preceded by tabs.
s/^(\t*) /$1\t/ while (/^\t* /);
# Remove trailing white space.
s/[ \t]*$//;
$body = "$body$_";
}
$_ = $body;
open(TARGET, ">$file.new") || die "can't open $file.new: $!";
print TARGET $_;
close(TARGET);
close(SOURCE);
if (system("cmp -s $file.new $file") == 0) {
unlink("$file.new");
} else {
rename("$file.new", "$file")
or die "rename($file.new, $file): $!";
}
}
next if $type eq "X" or $type eq "BAT";
$before_copyright = "";
$c_comment = 0;
$shell_comment = 0;
$m4_comment = 0;
$sgml_comment = 0;
$mkd_comment = 0;
$man_comment = 0;
$rst_comment = 0;
$python_comment = 0;
$python_bin_comment = 0;
$start_comment = "";
$end_comment = "";
$first = "";
if ($type =~ /^(C|YACC)$/) {
$c_comment = 1;
$start_comment = "/*\n";
$prefix = " * ";
$end_comment = " */\n";
} elsif ($type =~ /^(SH|PERL|TCL|MAKE|CONF-SH|RNC)$/) {
$shell_comment = 1;
$prefix = "# ";
} elsif ($type =~ /^PYTHON-BIN$/) {
$python_bin_comment = 1;
$start_comment = "############################################################################\n";
$prefix = "# ";
$end_comment = "############################################################################\n"
} elsif ($type =~ /^PYTHON$/) {
$python_comment = 1;
$start_comment = "############################################################################\n";
$prefix = "# ";
$end_comment = "############################################################################\n"
} elsif ($type eq "MAN") {
$man_comment = 1;
$prefix = ".\\\" ";
} elsif ($type eq "M4") {
$m4_comment = 1;
$prefix = "dnl ";
} elsif ($type eq "HTML" || $type eq "SGML") {
$sgml_comment = 1;
$start_comment = "<!--\n";
$prefix = " - ";
$end_comment = "-->\n";
} elsif ($type eq "MKD") {
$mkd_comment = 1;
$start_comment = "<!--\n";
$prefix = " - ";
$end_comment = "-->";
} elsif ($type eq "TXT") {
$prefix = "";
} elsif ($type eq "RST") {
$rst_comment = 1;
$start_comment = ".. \n";
$prefix = " ";
$end_comment = "";
} else {
print "$file: type '$type' not supported yet; skipping\n";
$ret++;
next;
}
($nonspaceprefix = $prefix) =~ s/\s+$//;
open(SOURCE, "<:crlf", $file) || die "can't open $file: $!";
$_ = <SOURCE>;
if ($type eq "YACC") {
unless ($_ eq "%{\n") {
print "$file: unexpected yacc file start ",
"(expected \"%{\\n\")\n";
close(SOURCE);
$ret++;
next;
}
$before_copyright = "$_";
$_ = <SOURCE>;
}
if ($c_comment && /^\/\*/) {
$_ = <SOURCE>;
if ($_ !~ /[Cc]opyright/) {
print "$file: non-copyright comment\n";
close(SOURCE);
$ret++;
next;
}
if ($_ !~ /\*\//) {
while (<SOURCE>) {
last if $_ =~ /\*\//;
}
}
} elsif ($shell_comment) {
if (/^\#\!/) {
$before_copyright = "$_#\n";
$_ = <SOURCE>;
$_ = <SOURCE> if $_ eq "#\n";
}
if (/^\#/) {
if ($_ !~ /[Cc]opyright/) {
print "$file: non-copyright comment\n";
close(SOURCE);
$ret++;
next;
}
while (<SOURCE>) {
if ($_ !~ /^\#/) {
$first = $_;
last;
}
}
} else {
$first = $_;
}
} elsif ($python_comment || $python_bin_comment) {
if ($python_bin_comment && /^\#\!/) {
$before_copyright = "$_";
$_ = <SOURCE>;
$_ = <SOURCE> if $_ eq "#\n";
$_ = <SOURCE> if $_ eq "############################################################################\n";
} elsif ($python_comment && /^\#/) {
$_ = <SOURCE> if $_ eq "#\n";
$_ = <SOURCE> if $_ eq "############################################################################\n";
}
if (/^\#/) {
if ($_ !~ /[Cc]opyright/) {
print "$file: non-copyright comment\n";
close(SOURCE);
$ret++;
next;
}
while (<SOURCE>) {
if ($_ !~ /^\#/) {
$first = $_;
last;
}
}
} else {
$first = $_;
}
} elsif (($m4_comment || $man_comment) &&
/^\Q$nonspaceprefix\E/) {
while (/^\Q$nonspaceprefix\E\s*$/) {
$_ = <SOURCE>;
}
if ($_ !~ /[Cc]opyright/) {
print "$file: non-copyright comment\n";
close(SOURCE);
$ret++;
next;
}
while (<SOURCE>) {
if ($_ !~ /^\Q$nonspaceprefix\E/ ||
$_ =~ /$keyword_pat/) {
$first = $_;
last;
}
}
} elsif ($sgml_comment) {
$before_copyright = "";
while (/^<!DOCTYPE/ || /^<!ENTITY/ || /^<\?xml-stylesheet/ || /^<\?xml /) {
# print "SGML: $_";
$before_copyright = "$before_copyright$_";
if (/\]>$/ ) {
$_ = <SOURCE>;
close(SOURCE) if (eof(SOURCE));
next;
}
if (/^<!DOCTYPE.*\[$/) {
while (!eof(SOURCE)) {
$_ = <SOURCE>;
next if (eof(SOURCE));
$before_copyright =
"$before_copyright$_";
if (/]>$/) {
$_ = <SOURCE>;
last;
}
}
close(SOURCE) if (eof(SOURCE));
next;
}
if (/>$/ ) {
$_ = <SOURCE>;
close(SOURCE) if (eof(SOURCE));
next;
}
$_ = <SOURCE>;
while (!eof(SOURCE) && ! /^<!/ ) {
$before_copyright = "$before_copyright$_";
$_ = <SOURCE>;
}
if (eof(SOURCE)) {
close(SOURCE);
next;
}
}
if (/^<!--/) {
$_ = <SOURCE> if $_ eq "<!--\n";
if ($_ !~ /[Cc]opyright/) {
print "$file: non-copyright comment\n";
close(SOURCE);
$ret++;
next;
}
while (defined($_)) {
last if s/.*-->//;
$_ = <SOURCE>;
}
print "$file: unterminated comment\n"
unless defined($_);
if ($_ ne "\n") {
$first = $_;
} else {
$first = <SOURCE>;
}
} else {
$first = $_;
}
} elsif ($mkd_comment) {
$before_copyright = "";
if (/^<!/) {
$_ = <SOURCE> if $_ eq "<!--\n";
if ($_ !~ /[Cc]opyright/) {
print "$file: non-copyright comment\n";
close(SOURCE);
$ret++;
next;
}
while (defined($_)) {
last if s/.*-->//;
$_ = <SOURCE>;
}
print "$file: unterminated comment\n"
unless defined($_);
if ($_ ne "\n") {
$first = $_;
} else {
$first = <SOURCE>;
}
} else {
$first = $_;
}
} elsif ($rst_comment) {
if ($_ =~ /\.\. \n/) {
$_ = <SOURCE>;
if ($_ !~ /[Cc]opyright/) {
print "$file: non-copyright comment\n";
close(SOURCE);
$ret++;
next;
}
while (<SOURCE>) {
if ($_ !~ /^ /) {
last;
}
}
}
$first = $_;
} elsif ($type eq "TXT") {
if ($_ =~ /[Cc]opyright/) {
$/ = ""; # paragraph at a time
while (<SOURCE>) {
# Not very maintainable, but ok enough for now.
last if /Portions of this code/;
last unless
/[Cc]opyright/ ||
/This Source Code Form is subject to the terms of the Mozilla Public/ ||
/If a copy of the MPL was not distributed with this/ ||
/You can obtain one at http:\/\/mozilla.org\/MPL\/2.0\// ||
/See COPYRIGHT in the source root/ ||
/Permission to use, copy, modify, and / ||
/THE SOFTWARE IS PROVIDED "AS IS" AND /;
}
$/ = "\n";
}
$first = $_;
} else {
$first = $_;
}
$first = "" if ! defined($first);
open(TARGET, ">$file.new") || die "can't open $file.new: $!";
print TARGET $before_copyright if $before_copyright;
print TARGET $start_comment if $start_comment;
$sysyears = "";
$nomyears = "";
#
# Nominum: up to 2001.
#
$last_year = 0;
$anchor_year = 0;
$years = "";
foreach $year (@years) {
if ($year >= 2002) { next; }
if ($last_year != 0 && $year == $last_year + 1) {
if ($year > $anchor_year + 1) {
substr($years, $anchor_end) = "-$year";
} else {
$years .= ", $year";
}
} else {
$years .= $last_year == 0 ? "$year" : ", $year";
$anchor_year = $year;
$anchor_end = length($years);
}
$last_year = $year;
}
$nomyears = $years;
$last_year = 0;
$anchor_year = 0;
$years = "";
$anchor_end = length($years);
my $andor = 0;
my $noid = 0;
foreach $year (@years) {
$andor = 1 if ($year >= 2007);
$noid = 1 if ($year > 2012 || ($year == 2012 && $this_month >= 5) );
if ($last_year != 0 && $year == $last_year + 1) {
if ($year > $anchor_year + 1) {
substr($years, $anchor_end) = "-$year";
} else {
$years .= ", $year";
}
} else {
$years .= $last_year == 0 ? "$year" : ", $year";
#if ($anchor_year != 0) {
# print "$file: noncontiguous year: ",
# "$year != $last_year + 1\n";
#}
$anchor_year = $year;
$anchor_end = length($years);
}
$last_year = $year;
}
$sysyears = $years;
# make a copy
@lines = @$textp;
foreach $_ (@lines) {
next if (/\@SYSYEARS\@/ && $sysyears eq "");
s:modify, and distribute:modify, and/or distribute: if ($andor);
if ($type eq "RST") {
print TARGET $prefix;
} else {
print TARGET (/^$/ ? $nonspaceprefix : $prefix);
}
s/\@SYSYEARS\@/$sysyears/;
s/\@NOMYEARS\@/$nomyears/;
print TARGET "$_";
}
print TARGET $end_comment if $end_comment;
if ($first eq "") {
$first = <SOURCE>;
}
if (defined($first)) {
if ($type eq 'MAN') {
print TARGET "$nonspaceprefix\n";
} else {
print TARGET "\n";
}
if (($type eq "C") &&
$sysyears =~ /$this_year/) {
my $body = "";
while (<SOURCE>) {
# Process leading white space.
# Remove 1-7 spaces followed by a tab into a single
# tab if at start of line or proceeded by tabs.
# s/^(\t*) {1,7}\t/$1\t/ while (/^\t* {1,7}\t/);
# Convert 8 spaces into tabs if at start of line
# or preceded by tabs.
# s/^(\t*) {8}/$1\t/ while (/^\t* {8}/);
# Remove trailing white space.
s/[ \t]*$//;
$body = "$body$_";
}
$_ = $body;
} elsif (($type eq "SGML" || $type eq "HTML" ||
$type eq "MAKE") &&
$sysyears =~ /$this_year/) {
my $body = "";
while (<SOURCE>) {
# Remove trailing white space.
s/[ \t]*$//;
$body = "$body$_";
}
$_ = $body;
} else {
undef $/;
$_ = <SOURCE>;
$/ = "\n";
}
if ($type eq 'SGML' && m:<articleinfo>.*?</articleinfo>:s) {
# print "docinfo: $file\n";
my $r = copyrights(@years);
s:<articleinfo>.*?</articleinfo>:<articleinfo>\n$r </articleinfo>:s;
}
if ($type eq 'SGML' && m:<docinfo>.*?</docinfo>:s) {
# print "docinfo: $file\n";
my $r = copyrights(@years);
s:<docinfo>.*?</docinfo>:<docinfo>\n$r </docinfo>:s;
}
if ($type eq 'SGML' && m:<bookinfo>.*?</bookinfo>:s) {
# print "bookinfo: $file\n";
my $r = copyrights(@years);
$r .= " <xi:include href=\"releaseinfo.xml\"/>\n";
s:<bookinfo>.*?</bookinfo>:<bookinfo>\n$r </bookinfo>:s;
}
if ($type eq 'SGML' && m:<!-- insert copyright start -->.*?<!-- insert copyright end -->:s) {
my $r = copyrights(@years);
s:<!-- insert copyright start -->.*?<!-- insert copyright end -->:<!-- insert copyright start -->\n$r <!-- insert copyright end -->:s;
}
my ($start, $end);
if ($type =~ /^PYTHON(|-BIN)$/) {
($start = $prefix) =~ s/\s*\n//;
$end = "\n";
} elsif ($start_comment ne "") {
($start = $start_comment) =~ s/\s*\n/ /;
($end = $end_comment) =~ s/^\s*(.*)\n/ $1\n/;
} elsif ($prefix ne "") {
($start = $prefix) =~ s/\s*\n//;
$end = "\n";
} else {
$start = "";
$end = "\n";
}
if (!$noid && $first !~ /$keyword_pat/ &&
(!defined($_) || $_ !~ /$keyword_pat/)) {
$end = "\n$nonspaceprefix" if ($type eq "MAN");
print TARGET "$start\$";
print TARGET "Id";
print TARGET "\$$end\n";
}
print TARGET $first if $first !~ /^\s*$/;
print TARGET $_ if (defined($_));
}
close(TARGET);
close(SOURCE);
$mode = (stat $file)[2]&511;
chmod $mode, "$file.new";
if (system("cmp -s $file.new $file") == 0) {
unlink("$file.new");
} else {
rename("$file.new", "$file")
or die "rename($file.new, $file): $!";
}
}
exit $ret;