xref: /curl/.github/scripts/spacecheck.pl (revision 092c07d1)
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