#!/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 preceeded 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;
        $zone_comment = 0;
        $man_comment = 0;
        $python_comment = 0;
        $python_bin_comment = 0;
        $start_comment = "";
        $end_comment = "";
        $first = "";
        if ($type =~ /^(C|YACC|CONF-C)$/) {
                $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 "ZONE" || $type eq "MC") {
                $zone_comment = 1;
                $prefix = "; ";
        } 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 = "";
        } else {
                print "$file: type '$type' not supported yet; skipping\n";
		$ret++;
                next;
        }

        ($nonspaceprefix = $prefix) =~ s/\s+$//;

        open(SOURCE, "<$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 || $zone_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 ($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);
                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" || $type eq "CONF-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 preceeded 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;
