#!/usr/bin/env perl

# Simple wrapper to the editor for svn.
#
# For commits, remove trailing whitespace and trailing newlines from
# the log message, and abort if there is a non-printable character
# (except \n). The file name needs to match /^svn-commit/, i.e. this
# does not apply to "svn propedit --revprop svn:log".
#
# This script can be run in various ways, e.g. by setting $SVN_EDITOR
# to the path to this wrapper.
#
# Copyright (c) 2008-2020 Vincent Lefevre <vincent@vinc17.net>.

# This program is free software; you may redistribute it
# and/or modify it under the same terms as Perl itself.

use strict;
use warnings;
use Config;

use open ':locale';

my ($proc) = '$Id: svneditor 127623 2020-05-16 09:17:34Z vinc17/zira $'
  =~ /^.Id: (\S+) / or die;

# svn currently calls the editor with one argument: the file name.
@ARGV == 1 or $! = 1, die "Usage: $proc <file>\n";

sub getmtime ($)
  {
    my $mtime = (stat $_[0])[9];
    # If mtime isn't available, something wrong could have occurred.
    defined $mtime or die "$proc: can't stat file $_[0]: $!\n";
    return $mtime;
  }

sub signame ($)
  {
    my $s = $_[0];
    # Get the signal name (see perlipc(1) man page).
    my @signame = split / /, $Config{sig_name};
    return defined $signame[$s] ? " (SIG$signame[$s])" : "";
  }

my $file = $ARGV[0];
my $mtime1 = getmtime $file;

# If $EDITOR isn't set, run emacs because this is what I like.
# Feel free to change it to something else. :)
system $ENV{EDITOR} || 'emacs', @ARGV;
if ($?)
  {
    my $s;
    die "$proc: ".
      ($? == -1 ? "cannot execute editor ($!)" :
       ($s = $? & 127) ? "editor killed by signal $s".signame($s).
       ", with".($? & 128 ? '' : 'out')." coredump" :
       "editor terminated with exit value ".($? >> 8))."\n";
  }

exit if $file !~ /^svn-commit/;

# Exit without touching anything if file hasn't been modified.
my $mtime2 = getmtime $file;
exit if $mtime2 == $mtime1;

my $changed = 0;
my $s = '';
open FILE, '<', $file or die "$proc: can't open file $file (R): $!\n";
while (<FILE>)
  {
    last if $_ eq "--This line, and those below, will be ignored--\n";
    last if /^--Cette ligne, et les suivantes ci-dessous, seront/;
    s/[\t ]+$// and $changed = 1;
    $s .= $_;
    chomp;
    /[^[:print:]]/ and $! = 1,
      die "Log message contains a non-printable character. Aborting.\n";
  }
close FILE or die "$proc: can't close file $file (R): $!\n";
$s =~ s/\n+\z// || $changed or exit;

print "Log message has been cleaned up\n";
open FILE, '>', $file or die "$proc: can't open file $file (W): $!\n";
print FILE $s or die "$proc: can't write to file $file: $!\n";
close FILE or die "$proc: can't close file $file (W): $!\n";