1#!/usr/bin/env perl 2#*************************************************************************** 3# _ _ ____ _ 4# Project ___| | | | _ \| | 5# / __| | | | |_) | | 6# | (__| |_| | _ <| |___ 7# \___|\___/|_| \_\_____| 8# 9# Copyright (C) Viktor Szakats 10# 11# This software is licensed as described in the file COPYING, which 12# you should have received as part of this distribution. The terms 13# are also available at https://curl.se/docs/copyright.html. 14# 15# You may opt to use, copy, modify, merge, publish, distribute and/or sell 16# copies of the Software, and permit persons to whom the Software is 17# furnished to do so, under the terms of the COPYING file. 18# 19# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 20# KIND, either express or implied. 21# 22# SPDX-License-Identifier: curl 23# 24########################################################################### 25 26use strict; 27use warnings; 28 29my @tabs = ( 30 "^m4/zz40-xc-ovr.m4", 31 "Makefile\\.[a-z]+\$", 32 "/mkfile", 33 "\\.(bat|sln|vc)\$", 34 "^tests/certs/.+\\.der\$", 35 "^tests/data/test", 36); 37 38my @mixed_eol = ( 39 "^tests/certs/.+\\.(crt|der)\$", 40 "^tests/certs/Server-localhost0h-sv.pem", 41 "^tests/data/test", 42); 43 44my @need_crlf = ( 45 "\\.(bat|sln)\$", 46 "^winbuild/.+\\.md\$", 47); 48 49my @space_at_eol = ( 50 "^tests/.+\\.(cacert|crt|pem)\$", 51 "^tests/data/test", 52); 53 54my @eol_at_eof = ( 55 "^tests/certs/.+\\.der\$", 56); 57 58sub fn_match { 59 my ($filename, @masklist) = @_; 60 61 foreach my $mask (@masklist) { 62 if ($filename =~ $mask) { 63 return 1; 64 } 65 } 66 return 0; 67} 68 69sub eol_detect { 70 my ($content) = @_; 71 72 my $cr = () = $content =~ /\r/g; 73 my $lf = () = $content =~ /\n/g; 74 75 if ($cr > 0 && $lf == 0) { 76 return "cr" 77 } 78 elsif ($cr == 0 && $lf > 0) { 79 return "lf" 80 } 81 elsif ($cr == 0 && $lf == 0) { 82 return "bin" 83 } 84 elsif ($cr == $lf) { 85 return "crlf" 86 } 87 88 return "" 89} 90 91my $issues = 0; 92 93open my $git_ls_files, '-|', 'git ls-files' or die "Failed running git ls-files: $!"; 94while (my $filename = <$git_ls_files>) { 95 chomp $filename; 96 97 open my $fh, '<', $filename or die "Cannot open '$filename': $!"; 98 my $content = do { local $/; <$fh> }; 99 close $fh; 100 101 my @err = (); 102 103 if (!fn_match($filename, @tabs) && 104 $content =~ /\t/) { 105 push @err, "content: has tab"; 106 } 107 108 my $eol = eol_detect($content); 109 110 if ($eol eq "" && 111 !fn_match($filename, @mixed_eol)) { 112 push @err, "content: has mixed EOL types"; 113 } 114 115 if ($eol ne "crlf" && 116 fn_match($filename, @need_crlf)) { 117 push @err, "content: must use CRLF EOL for this file type"; 118 } 119 120 if ($eol ne "lf" && $content ne "" && 121 !fn_match($filename, @need_crlf) && 122 !fn_match($filename, @mixed_eol)) { 123 push @err, "content: must use LF EOL for this file type"; 124 } 125 126 if (!fn_match($filename, @space_at_eol) && 127 $content =~ /[ \t]\n/) { 128 push @err, "content: has line-ending whitespace"; 129 } 130 131 if ($content ne "" && 132 !fn_match($filename, @eol_at_eof) && 133 $content !~ /\n\z/) { 134 push @err, "content: has no EOL at EOF"; 135 } 136 137 if ($content =~ /\n\n\z/ || 138 $content =~ /\r\n\r\n\z/) { 139 push @err, "content: has multiple EOL at EOF"; 140 } 141 142 if (@err) { 143 $issues++; 144 foreach my $err (@err) { 145 print "$filename: $err\n"; 146 } 147 } 148} 149close $git_ls_files; 150 151if ($issues) { 152 exit 1; 153} 154