| #!/usr/bin/env perl | |
| #*************************************************************************** | |
| # _ _ ____ _ | |
| # Project ___| | | | _ \| | | |
| # / __| | | | |_) | | | |
| # | (__| |_| | _ <| |___ | |
| # \___|\___/|_| \_\_____| | |
| # | |
| # Copyright (C) Viktor Szakats | |
| # | |
| # This software is licensed as described in the file COPYING, which | |
| # you should have received as part of this distribution. The terms | |
| # are also available at https://curl.se/docs/copyright.html. | |
| # | |
| # You may opt to use, copy, modify, merge, publish, distribute and/or sell | |
| # copies of the Software, and permit persons to whom the Software is | |
| # furnished to do so, under the terms of the COPYING file. | |
| # | |
| # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | |
| # KIND, either express or implied. | |
| # | |
| # SPDX-License-Identifier: curl | |
| # | |
| ########################################################################### | |
| use strict; | |
| use warnings; | |
| my @tabs = ( | |
| "^m4/zz40-xc-ovr.m4", | |
| "Makefile\\.[a-z]+\$", | |
| "/mkfile", | |
| "\\.(bat|sln|vc)\$", | |
| "^tests/certs/.+\\.der\$", | |
| "^tests/data/test", | |
| ); | |
| my @mixed_eol = ( | |
| "^tests/certs/.+\\.(crt|der)\$", | |
| "^tests/certs/Server-localhost0h-sv.pem", | |
| "^tests/data/test", | |
| ); | |
| my @need_crlf = ( | |
| "\\.(bat|sln)\$", | |
| "^winbuild/.+\\.md\$", | |
| ); | |
| my @space_at_eol = ( | |
| "^tests/.+\\.(cacert|crt|pem)\$", | |
| "^tests/data/test", | |
| ); | |
| my @eol_at_eof = ( | |
| "^tests/certs/.+\\.der\$", | |
| ); | |
| sub fn_match { | |
| my ($filename, @masklist) = @_; | |
| foreach my $mask (@masklist) { | |
| if ($filename =~ $mask) { | |
| return 1; | |
| } | |
| } | |
| return 0; | |
| } | |
| sub eol_detect { | |
| my ($content) = @_; | |
| my $cr = () = $content =~ /\r/g; | |
| my $lf = () = $content =~ /\n/g; | |
| if ($cr > 0 && $lf == 0) { | |
| return "cr" | |
| } | |
| elsif ($cr == 0 && $lf > 0) { | |
| return "lf" | |
| } | |
| elsif ($cr == 0 && $lf == 0) { | |
| return "bin" | |
| } | |
| elsif ($cr == $lf) { | |
| return "crlf" | |
| } | |
| return "" | |
| } | |
| my $issues = 0; | |
| open my $git_ls_files, '-|', 'git ls-files' or die "Failed running git ls-files: $!"; | |
| while (my $filename = <$git_ls_files>) { | |
| chomp $filename; | |
| open my $fh, '<', $filename or die "Cannot open '$filename': $!"; | |
| my $content = do { local $/; <$fh> }; | |
| close $fh; | |
| my @err = (); | |
| if (!fn_match($filename, @tabs) && | |
| $content =~ /\t/) { | |
| push @err, "content: has tab"; | |
| } | |
| my $eol = eol_detect($content); | |
| if ($eol eq "" && | |
| !fn_match($filename, @mixed_eol)) { | |
| push @err, "content: has mixed EOL types"; | |
| } | |
| if ($eol ne "crlf" && | |
| fn_match($filename, @need_crlf)) { | |
| push @err, "content: must use CRLF EOL for this file type"; | |
| } | |
| if ($eol ne "lf" && $content ne "" && | |
| !fn_match($filename, @need_crlf) && | |
| !fn_match($filename, @mixed_eol)) { | |
| push @err, "content: must use LF EOL for this file type"; | |
| } | |
| if (!fn_match($filename, @space_at_eol) && | |
| $content =~ /[ \t]\n/) { | |
| push @err, "content: has line-ending whitespace"; | |
| } | |
| if ($content ne "" && | |
| !fn_match($filename, @eol_at_eof) && | |
| $content !~ /\n\z/) { | |
| push @err, "content: has no EOL at EOF"; | |
| } | |
| if ($content =~ /\n\n\z/ || | |
| $content =~ /\r\n\r\n\z/) { | |
| push @err, "content: has multiple EOL at EOF"; | |
| } | |
| if (@err) { | |
| $issues++; | |
| foreach my $err (@err) { | |
| print "$filename: $err\n"; | |
| } | |
| } | |
| } | |
| close $git_ls_files; | |
| if ($issues) { | |
| exit 1; | |
| } |