#!/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;
}
