#!/usr/bin/perl # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # $Source: src/build/tools/addCopyright.pl $ # # IBM CONFIDENTIAL # # COPYRIGHT International Business Machines Corp. 2011 # # p1 # # Object Code Only (OCO) source materials # Licensed Internal Code Source Materials # IBM HostBoot Licensed Internal Code # # The source code for this program is not published or other- # wise divested of its trade secrets, irrespective of what has # been deposited with the U.S. Copyright Office. # # Origin: 30 # # IBM_PROLOG_END # Forked from: # Author: Mark Jerde (mjerde@us.ibm.com) # Date: Fri Mar 19 17:40:32 2010 UTC # # CVS Information: # $Revision: 1.55 $ # $Date: 2011/01/10 19:23:05 $ # $RCSfile: addCopyright.pl,v $ use strict; use warnings; #################################### ABOUT #################################### # addCopyright.pl will automatically insert appropriate copyright statements # # in source files following the IBM copyright guidelines (and templates) # # referenced below : # # FSP ClearCase Architecture # # Version 1.9 # # 10/12/2010 # # Editor: Alan Hlava # # # # Section 3.14.1 has templates for different files # # # # NOTE: FSP uses the phrase "OCO Source materials" in their copyright # # block, which is classified as 'p1' . We will use the same # # classification here. # # NOTE: to list all files in src EXCEPT the build dir, run: # # make clean # remove autogenerated files # # find src -path 'src/build' -prune -o ! -type d -print | tr '\n' ' ' # # # # addCopyright.pl does not support piping, but you can send these # # to a file, add "addCopyright.pl update" to the beginning of the line, # # and run the file to update all # ############################################################################### # Project-specific settings. # ## my $releaseYear = "2011"; my $releaseYear = `date +%Y`; chomp( $releaseYear ); my $copyrightSymbol = ""; # my $copyrightSymbol = "(C)"; # Uncomment if unable to use  character. my $projectName = "HostBoot"; my $DELIMITER_END = "IBM_PROLOG_END"; my $DELIMITER_BEGIN = "IBM_PROLOG_BEGIN_TAG"; my $DELIMITER_WARNING_TEXT = "This is an automatically generated prolog."; my $PVALUE = "p1"; ## my best guess my $PVALUE_TEXT = "Object Code Only (OCO) source materials Licensed Internal Code Source Materials IBM $projectName Licensed Internal Code The source code for this program is not published or other- wise divested of its trade secrets, irrespective of what has been deposited with the U.S. Copyright Office."; my $ORIGIN = "30"; # End Project-specific settings ####################################################################### # Main ####################################################################### if (scalar(@ARGV) < 2) { usage(); } ## my $operation = shift; if (not ($operation =~ m/update/i) and not ($operation =~ m/validate/i)) { print "Operation update or validate is required\n"; usage(); } ## check for debug mode my $debug = shift( @ARGV ); # print "$debug\n"; if ( $debug =~ m/debug/i ) { print STDERR "debug mode\n"; $debug = 1; } else { print STDERR "normal mode\n"; unshift( @ARGV , $debug ); $debug = 0; } # Read files and process. while (defined($_ = shift)) { my $filetype = filetype($_); print "File $_: Type $filetype\n"; ## ## validate ## Exit 1 for unknown filetype ## Exit 2 if has old copyright block ## Exit 3 if no copyright block ## if ( $operation =~ m/validate/i ) { if ("Unknown" eq $filetype) { print "ERROR: File $_ :Unknown Filetype: $_"; exit 1; } if ( hasoldcopyrightblock( $_, $filetype ) ) { print "ERROR File $_: has old copyright block, please fix\n"; exit 2; } if ( ! hascopyrightblock( $_, $filetype ) ) { print "ERROR File $_: Missing Copyright notice!!!\n"; exit 3; } # good file next; } ## ## update ## Continue with a warning for unknown filetype - ## if ($operation =~ m/update/i) { if ("Unknown" eq $filetype) { print "!!!!! WARNING: File $_ :Unknown Filetype: $_\n"; next; } ## do a check for the old "$IBMCopyright: $" block if ( hasoldcopyrightblock ( $_, $filetype ) ) { print "ERROR File $_: has old copyright block, please fix\n"; exit 2; } if ( ! hascopyrightblock( $_, $filetype ) ) { if ($debug) { print "Add empty copyright block\n"; } addEmptyCopyrightBlock( $_, $filetype ); ## check that the first part worked if ( ! hascopyrightblock( $_, $filetype ) ) { print STDERR "Failed to create Copyright block, please fix\n"; exit 2; } fillInEmptyCopyrightBlock( $_, $filetype ); } } } # endwhile ######################################################################### ## Subroutines ######################################################################### ####################################### ## usage: print usage and quit ####################################### sub usage { print "Usage: addCopyright.pl { update | validate } [ debug ] file1 ...\n\n"; exit 1; } ##################################### ## log unknown file type - unfinished ##################################### sub logUnknownFiletype { my $filename = shift; my $fileinfo = shift; # TODO print "Unknown filetype: $filename $fileinfo\n"; } ##################################### ## Analyze file and return a text string of the file type ##################################### sub filetype { my $filename = shift; my $fileinfo = `file $filename | sed 's/^.*: //'`; chomp $fileinfo; # Sorted by anticipated frequency of occurrence. if ( ( $filename =~ m/\.[cht]$/i ) ||( $filename =~ m/\.[cht]\+\+$/i ) ||( $filename =~ m/\.[cht]pp$/i ) ||( $fileinfo =~ m/c program text/i ) ||( $fileinfo =~ m/c\+\+ program text/i ) ) { return "C"; } if ( ( $filename =~ m/\.pl$/ ) ||( $filename =~ m/\.perl$/ ) ||( $filename =~ m/\.pm$/ ) ||( $fileinfo =~ m/perl.*script text executable/i) ) { return "Perl"; } if ($filename =~ m/\.s$/i) { return "Assembly"; } if (($filename =~ m/Makefile$/i) or ($filename =~ m/\.mk$/i)) { return "Makefile"; } if ( $filename =~ m/\.am$/i ) { return "Automake"; } if ( ($filename =~ m/configure\.ac$/i) ||($filename =~ m/Makefile\.in$/i) ) { return "Autoconf"; } if ( ( $filename =~ m/\.[kc]{0,1}sh$/i ) ||( $filename =~ m/\.bash$/i ) ||( $fileinfo =~ m/shell script/i ) ||( $fileinfo =~ m/^a \/bin\/[af]sh( -x|) *script text( executable|)$/ ) ||( $fileinfo eq "Bourne shell script text") ||( $fileinfo eq "Bourne shell script text executable") ||( $fileinfo eq "Bourne-Again shell script text") ||( $fileinfo eq "Bourne-Again shell script text executable") ) { return "Shellscript"; } if ( $filename =~ m/\.py$/ ) { return "Python"; } if ( $filename =~ m/\.tcl$/ ) { return "Tcl"; } if ( $filename =~ m/\.x$/ ) { return "RPC"; } if ( ($filename =~ m/^commitinfo$/) ||($filename =~ m/^checkoutlist$/) ||($filename =~ m/^loginfo$/) ) { return "CVS"; } if ( $filename =~ m/\.emx$/ ) { # Used by Rational Software Architect. modelling file. return "EmxFile"; } if ( $filename =~ m/\.mof$/ ) { return "MofFile"; } if ( $filename =~ m/\.ld$/ ) { return "LinkerScript"; } if ( $filename =~ m/\.xml$/i ) { return "xml" } if ( ( $filename =~ m/\.emx$/i ) ||( $filename =~ m/\.odt$/i ) ||( $filename =~ m/\.gitignore$/i ) ||( $filename =~ m/\.conf$/i ) ||( $filename =~ m/\.lidhdr$/i ) ||( $filename =~ m/\.vpdinfo$/i ) ||( $filename =~ m/\.pdf$/i ) ) { # Known, but we can't deal with it so call it unknown. return "Unknown"; } if ( -f $filename ) { my $type = `grep "\\\$Filetype:.*\\\$" $filename`; if ( $type =~ m/\$Filetype:([^\$]*)\$/ ) { $type = $1; } $type =~ s/^\s*//; $type =~ s/\s*$//; my %knownTypes = qw/Assembly Assembly Automake Automake Autoconf Autoconf C C CVS CVS EmxFile EmxFile LinkerScript LinkerScript Makefile Makefile MofFile MofFile Perl Perl Python Python RPC RPC Shellscript Shellscript Tcl Tcl/; return $type if defined($knownTypes{$type}); } { # Other random files containing non-printable characters. my $file = `cat $filename`; if ( $file =~ m/([^\x20-\x7E\s])/ ) { return "Unknown"; } } logUnknownFiletype($filename,$fileinfo); return "Unknown"; } ###################################### ## Figure out the first copyright year for the file ## return as a string ###################################### sub copyrightFirstYearForFile { my $file = shift; my $fileContent = shift; my $year = $releaseYear; my @logstrings; # TODO find multiple copyright statements and pick the earliest one # Search for earlier years from prior release. if ($fileContent =~ m/Copyright IBM Corp. (\d{4})/) { $year = $1 if ($1 < $year); } my $cmd = "git log -- $file | grep Date: | tail --line=1"; ## print "run $cmd\n"; @logstrings = split( " ", `$cmd` ); # new files will not have a log, so the "git log" call above will # return nothing. In this case, just return the old calculated # value. if ( (scalar(@logstrings) < 5) or ($year lt $logstrings[5]) ) { return $year; } else { return $logstrings[5]; } } ######################################## ## Figure out the last copyright year for file ## Return as a string ######################################## sub copyrightLastYearForFile { return $releaseYear; } ####################################### ## Check for old $IBMCopyrightBlock signature ## return 1 if it's there, otherwise 0 ####################################### sub hasoldcopyrightblock { my ( $filename, $filetype ) = @_; my $file = `head -180 $filename`; # Must appear in first 180 lines. if ( $file =~ m/\$IBMCopyrightBlock:.*\$/s ) { return 1; } return 0; } ####################################### ## Check for new IBM_PROLOG_BEGIN_TAG signature ## return 1 if it's there, otherwise 0 ####################################### sub hascopyrightblock { my ( $filename, $filetype ) = @_; my $file = `head -180 $filename`; # Must appear in first 180 lines. #print $filename; #print $file; #print $DELIMITER_BEGIN; #print $DELIMITER_END; if ( $file =~ m/$DELIMITER_BEGIN.*$DELIMITER_END/s ) { return 1; } return 0; } ################################### ## Add an empty copyright block to the file, for example (C/C++ files): ## ## // IBM_PROLOG_BEGIN_TAG IBM_PROLOG_END_TAG ## ## - The block will be filled-in in the next step. ## - Makes up a temporary file called ".cvsCPYRT" ################################## sub addEmptyCopyrightBlock { my ( $filename, $filetype) = @_; my $line; open(INPUT, $_) or exit; system "touch $_.cvsCPYRT"; open(OUTPUT, ">$_.cvsCPYRT") or exit; if ("Assembly" eq $filetype) { ## print OUTPUT ";// \$IBMCopyrightBlock: \$\n"; print OUTPUT "# $DELIMITER_BEGIN $DELIMITER_END\n"; } elsif (("Autoconf" eq $filetype) or ("Automake" eq $filetype) or ("CVS" eq $filetype) or ("Makefile" eq $filetype) or ("Perl" eq $filetype) or ("Python" eq $filetype) or ("Shellscript" eq $filetype) or ("Tcl" eq $filetype)) { $line = ; # Keep the '#!' line at the top. if ($line =~ m/^#!/) { print OUTPUT $line; } ## print OUTPUT "# \$IBMCopyrightBlock: \$\n"; print OUTPUT "# $DELIMITER_BEGIN $DELIMITER_END\n"; unless ($line =~ m/^#!/) { print OUTPUT $line; } } elsif ( ("C" eq $filetype) ) { ##print OUTPUT " * \$IBMCopyrightBlock: \$\n"; print OUTPUT "// $DELIMITER_BEGIN $DELIMITER_END\n"; } elsif ( ("RPC" eq $filetype) or ("LinkerScript" eq $filetype) ) { # ld stubbornly refuses to use modern comment lines. print OUTPUT "/* $DELIMITER_BEGIN $DELIMITER_END\n */\n"; } elsif ("MofFile" eq $filetype) { ##print OUTPUT "// \$IBMCopyrightBlock: \$\n"; print OUTPUT "// $DELIMITER_BEGIN $DELIMITER_END\n"; } elsif ("xml" eq $filetype ) { print OUTPUT "\n"; } else { print STDERR "Can\'t handle filetype: $filetype\n"; exit 1; } # Copy rest of file while (defined($line = )) { print OUTPUT $line; } close OUTPUT; close INPUT; system "cat $_.cvsCPYRT > $_"; system "rm -f $_.cvsCPYRT"; system "touch $_"; } ############################################ ## fill in the empty copyright block ## Copyright guidelines from: ## FSP ClearCase Architecture ## Version 1.9 ## 10/12/2010 ## Editor: Alan Hlava ## ## Section 3.14.1 has templates for different files ## ############################################ sub fillInEmptyCopyrightBlock { my ( $filename, $filetype ) = @_; my $file = `cat $_`; my $firstYear = copyrightFirstYearForFile($_, $file); my $lastYear = copyrightLastYearForFile($_); my $copyrightYear = $firstYear; $copyrightYear .= " - $lastYear" unless ( "$firstYear" eq "$lastYear" ); ## define the final copyright block template here. my $IBMCopyrightBlock = " $DELIMITER_BEGIN $DELIMITER_WARNING_TEXT \$Source: $filename \$ IBM CONFIDENTIAL COPYRIGHT International Business Machines Corp. $copyrightYear $PVALUE $PVALUE_TEXT Origin: $ORIGIN $DELIMITER_END"; if (($file =~ m/$DELIMITER_BEGIN*.$DELIMITER_END/s ) and ("Unknown" ne $filetype)) { open(INPUT, $_ ) or exit; system "touch $_.cvsCPYRT"; open(OUTPUT, ">$_.cvsCPYRT") or exit; my $newline; my $lines = ""; while ( defined($newline = ) ) { $lines .= $newline; } if ("Assembly" eq $filetype) { ## assembly $IBMCopyrightBlock =~ s/\n/\n# /sg; } if (("Autoconf" eq $filetype) or ("Automake" eq $filetype) or ("CVS" eq $filetype) or ("Makefile" eq $filetype) or ("Perl" eq $filetype) or ("Python" eq $filetype) or ("Shellscript" eq $filetype) or ("Tcl" eq $filetype)) { $IBMCopyrightBlock =~ s/\n/\n#/sg; } if (("C" eq $filetype) ) { # Use C++ style comments $IBMCopyrightBlock =~ s|\n|\n//|sg; } if (("RPC" eq $filetype) or ("LinkerScript" eq $filetype) ) { $IBMCopyrightBlock =~ s|\n|\n *|sg; } if ("EmxFile" eq $filetype) { # Not yet formatted correctly for EmxFile needs, but should coexist. $IBMCopyrightBlock = "$DELIMITER_BEGIN IBM Confidential OCO Source Materials (C) Copyright IBM Corp. $copyrightYear The source code for this program is not published or otherwise divested of its trade secrets, irrespective of what has been deposited with the U.S. Copyright Office. $DELIMITER_END"; } if ("MofFile" eq $filetype) { $IBMCopyrightBlock =~ s|\n|\n//|sg; } if ( "xml" eq $filetype) { $IBMCopyrightBlock =~ s|\n|\n |sg; } # Replace existing block with the current content. # $lines =~ s/\$IBMCopyrightBlock:[^\$]*\$/$IBMCopyrightBlock/s; $lines =~ s/$DELIMITER_BEGIN[^\$]*$DELIMITER_END/$IBMCopyrightBlock/s; print OUTPUT $lines; close OUTPUT; close INPUT; system "cat $_.cvsCPYRT > $_"; system "rm -f $_.cvsCPYRT"; system "touch $_"; } else { print "Cannot find empty copyright block\n"; exit 1; } }