Remove linking against gmp and cln in tests and parser (#6376)
[cvc5.git] / contrib / update-copyright.pl
1 #!/usr/bin/perl -w
2 #
3 # update-copyright.pl
4 # Copyright (c) 2009-2021 The cvc5 Project
5 #
6 # usage: update-copyright [-m] [files/directories...]
7 # update-copyright [-h | --help]
8 #
9 # This script goes through a source directory rewriting the top bits of
10 # source files to match a template (inline, below). For files with no
11 # top comment, it adds a fresh one.
12 #
13 # if no files/directories are unspecified, the script scans its own
14 # parent directory's "src" directory. Since it lives in contrib/ in
15 # the cvc5 source tree, that means src/ in the cvc5 source tree.
16 #
17 # If -m is specified as the first argument, all files and directories
18 # are scanned, but only ones modified in the index or working tree
19 # are modified (i.e., those that have at least one status M in
20 # "git status -s").
21 #
22 # It ignores any file/directory not starting with [a-zA-Z]
23 # (so, this includes . and .., vi swaps, .git meta-info,
24 # .deps, etc.)
25 #
26 # It ignores any file not ending with one of:
27 # .c .cc .cpp .h .hh .hpp .g .py .cmake .cmake.in CMakeLists.txt
28 # [ or those with ".in" also suffixed, e.g., .cpp.in ]
29 # (so, this includes emacs ~-backups, CVS detritus, etc.)
30 #
31 # It ignores any directory matching $excluded_directories
32 # (so, you should add here any sources imported but not covered under
33 # the license.)
34 #
35
36 my $excluded_directories = '^(CVS|generated)$';
37 my $excluded_paths = '^(';
38 # note: first excluded path regexp must not start with a '|'
39 # different license
40 $excluded_paths .= 'cmake/CodeCoverage.cmake';
41 $excluded_paths .= '|cmake/FindCython.cmake';
42 $excluded_paths .= '|cmake/FindPythonExtensions.cmake';
43 $excluded_paths .= '|cmake/UseCython.cmake';
44 $excluded_paths .= '|cmake/targetLinkLibrariesWithDynamicLookup.cmake';
45 # minisat license
46 $excluded_paths .= '|src/prop/(bv)?minisat/core/.*';
47 $excluded_paths .= '|src/prop/(bv)?minisat/mtl/.*';
48 $excluded_paths .= '|src/prop/(bv)?minisat/simp/.*';
49 $excluded_paths .= '|src/prop/(bv)?minisat/utils/.*';
50 $excluded_paths .= ')$';
51
52 # Years of copyright for the template. E.g., the string
53 # "1985, 1987, 1992, 1997, 2008" or "2006-2009" or whatever.
54 my $years = '2009-2021';
55
56 my $standard_template = <<EOF;
57 *
58 * This file is part of the cvc5 project.
59 *
60 * Copyright (c) $years by the authors listed in the file AUTHORS
61 * in the top-level source directory and their institutional affiliations.
62 * All rights reserved. See the file COPYING in the top-level source
63 * directory for licensing information.
64 * ****************************************************************************
65 EOF
66
67 my $doc_template = <<EOF;
68 *
69 * [[ Add one-line brief description here ]]
70 *
71 * [[ Add lengthier description here ]]
72 * \\todo document this file
73 */
74 EOF
75
76 my $standard_template_hash = $standard_template;
77 $standard_template_hash =~ s/ \* \*/\# \#\#/g;
78 $standard_template_hash =~ s/ \*/\#/g;
79 $standard_template_hash =~ s/\*/\#/g;
80 my $doc_template_hash = $doc_template;
81 $doc_template_hash =~ s/ \*/\#/g;
82 $doc_template_hash =~ s/\#\//\#\#/g;
83
84
85 ## end config ##
86
87 use strict;
88 use Fcntl ':mode';
89
90 my $dir = $0;
91 $dir =~ s,/[^/]+/*$,,;
92
93 if($#ARGV >= 0 && ($ARGV[0] eq '-h' || $ARGV[0] eq '--help')) {
94 open(my $SELF, $0) || die "error opening $0 for reading";
95 while($_ = <$SELF>) {
96 last if !/^#/;
97 print;
98 }
99 close $SELF;
100 exit;
101 }
102
103 # whether we ONLY process files with git status "M"
104 my $modonly = 0;
105
106 if($#ARGV >= 0 && $ARGV[0] eq '-m') {
107 $modonly = 1;
108 shift;
109 }
110
111 my @searchdirs = ();
112 if($#ARGV == -1) {
113 (chdir($dir."/..") && -f "src/include/cvc4_public.h") || die "can't find top-level source directory for cvc5";
114 my $pwd = `pwd`; chomp $pwd;
115
116 print <<EOF;
117 Warning: this script is dangerous. It will overwrite the header comments in your
118 source files to match the template in the script, attempting to retain file-specific
119 comments, but this isn't guaranteed. You should run this in a git working tree
120 and run "git diff" after to ensure everything was correctly rewritten.
121
122 The directories in which to search for and change sources is:
123 $pwd/CMakeLists.txt
124 $pwd/cmake
125 $pwd/src
126 $pwd/examples
127 $pwd/test
128 $pwd/doc
129 $pwd/docs
130
131 Continue? y or n:
132 EOF
133
134 $_ = <STDIN>; chomp;
135 die 'aborting operation' if !( $_ eq 'y' || $_ eq 'yes' || $_ eq 'Y' || $_ eq 'YES' );
136
137 $searchdirs[0] = 'CMakeLists.txt';
138 $searchdirs[1] = 'cmake';
139 $searchdirs[2] = 'src';
140 $searchdirs[3] = 'examples';
141 $searchdirs[4] = 'test';
142 } else {
143 @searchdirs = @ARGV;
144 }
145
146 print "Updating sources...\n";
147
148 while($#searchdirs >= 0) {
149 my $dir = shift @searchdirs;
150 $dir =~ s,\/$,,; # remove trailing slash from directory
151 my $mode = (stat($dir))[2] || warn "file or directory \`$dir' does not exist!";
152 my $is_directory = S_ISDIR($mode);
153 if ($is_directory) {
154 recurse($dir);
155 } else {
156 if ($dir =~ m,^(.*)\/([^/]*)$,) {
157 my ($dir, $file) = ($1, $2);
158 if ($dir eq "") {
159 $dir = "/";
160 }
161 handleFile($dir, $file);
162 } else {
163 handleFile(".", $dir);
164 }
165 }
166 }
167
168 sub reqHashPrefix {
169 my ($file) = @_;
170 return ($file =~ /\.(cmake|py)(\.in)?$/ or $file =~ /CMakeLists\.txt/);
171 }
172
173 sub printHeader {
174 my ($OUT, $file) = @_;
175 if (reqHashPrefix($file)) {
176 print $OUT "###############################################################################\n";
177 } elsif ($file =~ /\.g$/) {
178 # avoid javadoc-style comment here; antlr complains
179 print $OUT "/* ****************************************************************************\n"
180 } else {
181 print $OUT "/******************************************************************************\n"
182 }
183 }
184
185 sub printTopContrib {
186 my ($OUT, $file, $authors) = @_;
187 my $comment_style = " *";
188 if (reqHashPrefix($file)) {
189 $comment_style = "#";
190 }
191 print $OUT "$comment_style Top contributors (to current version):\n";
192 print $OUT "$comment_style $authors\n";
193 }
194
195 sub handleFile {
196 my ($srcdir, $file) = @_;
197 return if !($file =~ /\.(c|cc|cpp|h|hh|hpp|g|java)(\.in)?$/ or reqHashPrefix($file));
198 return if ($srcdir.'/'.$file) =~ /$excluded_paths/;
199 return if $modonly && `git status -s "$srcdir/$file" 2>/dev/null` !~ /^(M|.M)/;
200 print "$srcdir/$file... ";
201 my $infile = $srcdir.'/'.$file;
202 my $outfile = $srcdir.'/#'.$file.'.tmp';
203 open(my $IN, $infile) || die "error opening $infile for reading";
204 open(my $OUT, '>', $outfile) || die "error opening $outfile for writing";
205 open(my $AUTHOR, "$dir/get-authors " . $infile . '|');
206 my $authors = <$AUTHOR>; chomp $authors;
207 close $AUTHOR;
208
209 # Read file into array
210 my @lines = <$IN>;
211 close $IN;
212
213 # Check if file contains a shebang and print it as first line.
214 if ($lines[0] =~ /^\#!/) {
215 print $OUT $lines[0];
216 shift @lines;
217 }
218
219 printHeader($OUT, $file);
220 printTopContrib($OUT, $file, $authors);
221
222 my $adding = 0;
223 # Copyright header already exists
224 if ($lines[0] =~ /^(%\{)?\/\*{78}/
225 or $lines[0] =~ /^(%\{)?\/\* \*{76}/
226 or $lines[0] =~ /^\#{79}$/) {
227 print "updating\n";
228
229 # Skip lines until copyright header end and preserve copyright of non cvc5
230 # authors.
231 my $found_header_end = 0;
232 while (my $line = shift @lines) {
233 # Check if someone else holds this copyright and keep it.
234 if($line =~ /\b[Cc]opyright\b/ && $line !~ /\bby the authors listed in the file AUTHORS\b/) {
235 print $OUT $line;
236 }
237 # Reached end of copyright header section
238 if ($line =~ /^ \* \*{76}\s*$/ or $line =~ /^\# \#{77}$/) {
239 $found_header_end = 1;
240 last;
241 }
242 }
243 if (!$found_header_end) {
244 die "error: did not find end of copyright header secion for file '$file'";
245 }
246 # No header found
247 } else {
248 print "adding\n";
249 $adding = 1;
250 }
251 if (reqHashPrefix($file)) {
252 print $OUT $standard_template_hash;
253 if ($adding) {
254 print $OUT $doc_template_hash;
255 }
256 } else {
257 print $OUT $standard_template;
258 if ($adding) {
259 print $OUT $doc_template;
260 }
261 }
262 # Print remaining file
263 foreach (@lines) {
264 print $OUT $_;
265 }
266 close $OUT;
267
268 # Preserve file permissions of $infile
269 my $perm = (stat($infile))[2] & 0777;
270 chmod $perm, $outfile;
271
272 rename($outfile, $infile) || die "can't rename working file \`$outfile' to \`$infile'";
273 }
274
275 sub recurse {
276 my ($srcdir) = @_;
277 opendir(my $DIR, $srcdir);
278 while(my $file = readdir $DIR) {
279 next if !($file =~ /^[a-zA-Z]/);
280
281 my $mode = (stat($srcdir.'/'.$file))[2];
282 my $is_directory = S_ISDIR($mode);
283 if($is_directory) {
284 next if $file =~ /$excluded_directories/;
285 recurse($srcdir.'/'.$file);
286 } else {
287 handleFile($srcdir, $file);
288 }
289 }
290 closedir $DIR;
291 }
292
293 ### Local Variables:
294 ### perl-indent-level: 2
295 ### End: