#!/usr/bin/perl -0777 -pi # Update an FSF copyright year list to include the current year. my $VERSION = '2009-07-31.12:44'; # UTC # Copyright (C) 2009 Free Software Foundation # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Written by Jim Meyering # The arguments to this script should be names of files that contain FSF # copyright statements to be updated. For example, you may wish to # place a target like the following in the top-level makefile in your # project: # # .PHONY: update-copyright # update-copyright: # if test -d .git; then \ # git grep -l -w Copyright \ # | grep -v -E '(^|/)(COPYING|ChangeLog)' \ # | xargs $(srcdir)/build-aux/$@; \ # fi # # In the second grep, you can build a list of files to skip within your # project. # # Iff an FSF copyright statement is discovered in a file and the final # year is not the current year, the statement is updated for the new # year and reformatted to fit within 72 columns. A warning is printed # for every file for which no FSF copyright statement is discovered. # # Each file's FSF copyright statement must be formated correctly in # order to be recognized, and it must appear before other text that # looks like the start of a copyright statement. For example, each of # these by itself is fine: # # Copyright (C) 1990-2005, 2007-2009 Free Software Foundation, # Inc. # # # Copyright (C) 1990-2005, 2007-2009 Free Software # # Foundation, Inc. # # /* # * Copyright (C) 90,2005,2007-2009 Free Software # * Foundation, Inc. # */ # # However, the following format is not recognized because the line # prefix changes after the first line: # # /* Copyright (C) 1990-2005, 2007-2009 Free Software # * Foundation, Inc. */ # # The following copyright statement is not recognized because the # copyright holder is not the FSF: # # Copyright (C) 1990-2005, 2007-2009 Acme, Inc. # # Moreover, any FSF copyright statement following either of the previous # copyright statements might not be recognized. # # The exact conditions that a file's FSF copyright statement must meet # to be recognized are listed below. They may seem slightly complex, # but you need not worry if some file in your project accidentally # breaks one. The worst that can happen is that a file is not updated # and a warning is issued. # # 1. The format is "Copyright (C)" (where "(C)" can be "(c)"), then a # list of copyright years, and then the name of the copyright # holder, which is "Free Software Foundation, Inc.". # 2. "Copyright (C)" appears at the beginning of a line except that it # may be prefixed by any sequence (e.g., a comment) of no more than # 5 characters. # 3. The prefix of "Copyright (C)" is the same as the prefix on the # file's first occurrence of "Copyright (C)" that matches condition # #2. Stated more simply, if something that looks like the start # of a copyright statement appears earlier than the FSF copyright # statement, the FSF copyright statement might not be recognized. # This condition might be removed in the future. # 4. Iff a prefix is present before "Copyright (C)", the same prefix # appears at the beginning of each remaining line within the FSF # copyright statement. # 5. Blank lines, even if preceded by the prefix, do not appear # within the FSF copyright statement. # 6. Each copyright year is 2 or 4 digits, and years are separated by # commas or dashes. Whitespace may occur after commas. use strict; use warnings; my ($sec, $min, $hour, $mday, $month, $year) = localtime (time()); my $this_year = $year + 1900; my $copyright = 'Copyright \([cC]\)'; my $holder = 'Free Software Foundation, Inc.'; my $prefix_max = 5; my $margin = 72; my $tab_width = 8; # Unless the file consistently uses "\r\n" as the EOL, use "\n" instead. my $eol = /(?:^|[^\r])\n/ ? "\n" : "\r\n"; my $leading; my $prefix; my $ws; my $old; if (/(^|\n)(.{0,$prefix_max})$copyright/) { $leading = $1; $prefix = $2; $ws = '[ \t\r\f]'; # \s without \n $ws = "(?:$ws*(?:$ws|\\n" . quotemeta($prefix) . ")$ws*)"; $holder =~ s/\s/$ws/g; $old = quotemeta("$leading$prefix") . "($copyright$ws" . "(?:(?:\\d\\d)?\\d\\d(,$ws?|-))*" . "((?:\\d\\d)?\\d\\d)$ws$holder)"; } if (defined($old) && /$old/) { my $new = $1; my $sep = $2 ? $2 : ""; my $last_c_year = $3; # Handle two-digit year numbers like "98" and "99". $last_c_year <= 99 and $last_c_year += 1900; if ($last_c_year != $this_year) { # Update the year. if ($sep eq '-' && $last_c_year + 1 == $this_year) { $new =~ s/$last_c_year/$this_year/; } elsif ($sep ne '-' && $last_c_year + 1 == $this_year) { $new =~ s/$last_c_year/$last_c_year-$this_year/; } else { $new =~ s/$last_c_year/$last_c_year, $this_year/; } # Normalize all whitespace including newline-prefix sequences. $new =~ s/$ws/ /g; # Put spaces after commas. $new =~ s/, ?/, /g; # Format within margin. my $new_wrapped; my $text_margin = $margin - length($prefix); if ($prefix =~ /^(\t+)/) { $text_margin -= length($1) * ($tab_width-1); } while (length($new)) { if (($new =~ s/^(.{1,$text_margin})(?: |$)//) || ($new =~ s/^([\S]+)(?: |$)//)) { my $line = $1; $new_wrapped .= $new_wrapped ? $eol : $leading; $new_wrapped .= "$prefix$line"; } else { # Should be unreachable, but we don't want an infinite # loop if it can be reached. die; } } # Replace the old copyright statement. s/$old/$new_wrapped/; } } else { print STDERR "$ARGV: warning: FSF copyright statement not found\n"; } # Local variables: # indent-tabs-mode: nil # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "my $VERSION = '" # time-stamp-format: "%:y-%02m-%02d.%02H:%02M" # time-stamp-time-zone: "UTC" # time-stamp-end: "'; # UTC" # End: