#!/usr/bin/perl -w
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
#NAME
#  checkabc - Look for errors in tune files
#
#SYNOPSIS
#  checkabc [file]..
#REQUIRES
#
#DESCRIPTION
#  This scans the content of ABC tune files, looking for and  reporting  some
#  of the common errors and other problems.
#
#  The currect checking is only for Kerr's Merrie  Melodies  v.1,  to  verify
#  that  the numeric part of file names agrees with the X: index value inside
#  the files.
#
#OPTIONS
# None yet, but there may be some soon.
#
#EXAMPLES
#
#FILES
#
#BUGS
#  This is somewhat open-ended, and will change randomly.
#
#SEE ALSO
#
#AUTHOR
#  John Chambers <jc@trillian.mit.edu>
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #

$| = 1;
$exitstat = 0;
($P = $0) =~ s".*/"";
&Vopt($ENV{"V_$P"} || $ENV{"D_$P"} || '2'); 	# Verbose/debug level
print "$P: Started.\n" if $V>0;

$files = 0;		# Number of files processed so far
$errors = 0;	# Number of errors detected so far
$warnings = 0;	# Number of minor problems detected so far

for $f (@ARGV) {
	print V "$P: FILE \"$f\" ...\n" if $V>1;
	if (-f $f) {
		++$files;
		if (open(F,$f)) {
			print V "$P: Read \"$f\" ...\n" if $V>1;
			&onefile($f);
		} else {
			print V "$P: Can't read \"$f\" [$?]\n" if $V>0;
		}
	} else {
	}
}

print "$files files checked.\n" if $V>0;
print "$errors errors found.\n" if $V>0;
print "$warnings problems found.\n" if $V>0;

exit $exitstat;
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #

sub onefile {my $F='onefile'; local($file) = @_;
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# Check one file.
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
	local($line,$nerr,$nwarn);
	local($fx,$fv,$fp,$fs,$fn,$fc);	# index, vol, page, section, number, char for file
	local($tx,$tv,$tp,$ts,$tn);		# index, vol, page, section, number, char for tune
#
	$nerr = $nwarn = 0;
	if (($fx,$fv,$fp,$fs,$fn,$fc) = ($file =~ m/^((\d)(\d\d)(\d)(\d\d))([-=_])/)) {	# MM1
		print V "$F: fx=$fx fv=$fv fp=$fp fs=$fs fn=$fn fc='$fc'\n" if $V>1;
	} elsif (($fx,$fv,$fn,$fc) = ($file =~ m/^((\d)(\d\d\d))([-=_])/)) {	# MM2-4
		print V "$F: fx=$fx fv=$fv fn=$fn fc='$fc'\n" if $V>1;
	} else {
		print V "$F: file \"$file\" not parsed.\n" if $V>2;
	}
	for $line (<F>) {
		$line =~ s/[\r\s]+$//;	# Trim away white stuff
		print V "$F: LINE \"$line\"\n" if $V>2;
		if ($line =~ m/X:\s*(\d+)/) {
			$tx = $1;
			print V "$F: tx=$tx.\n" if $V>2;
			if (($tv,$tp,$ts,$tn) = ($tx =~ m/^(\d)(\d\d)(\d)(\d\d)$/)) {	# VPPSNN
				print V "$F: tx=$tx tv=$tv tp=$tp ts=$ts tn=$tn.\n" if $V>1;
				if ($fx != $tx || $fv != $tv || $fp != $tp || $fs != $ts || $fn != $tn) {
					print "$F: Tune index \"$tx\" and file \"$file\" differ.\n" if $V>0;
					print "$F: tx=$tx fx=$fx in $file\n" if $V>0 && $fx != $tx;
					print "$F: tv=$tv fv=$fv in $file\n" if $V>0 && $fv != $tv;
					print "$F: tp=$tp fp=$fp in $file\n" if $V>0 && $fp != $tp;
					print "$F: ts=$ts fs=$fs in $file\n" if $V>0 && $fs != $ts;
					print "$F: tn=$tn fn=$fn in $file\n" if $V>0 && $fn != $tn;
					++$nwarn; ++$warnings;
				} else {
					print "$F: Tune index \"$tx\" and file \"$file\" agree.\n" if $V>1;
				}
			} elsif (($tv,$tn) = ($tx =~ m/^(\d)(\d\d\d)$/)) {	# VNNN
				print V "$F: tx=$tx tv=$tv tn=$tn.\n" if $V>1;
				if ($fx != $tx || $fv != $tv || $fn != $tn) {
					print "$F: Tune index \"$tx\" and file \"$file\" differ.\n" if $V>0;
					print "$F: tx=$tx fx=$fx in $file\n" if $V>0 && $fx != $tx;
					print "$F: tv=$tv fv=$fv in $file\n" if $V>0 && $fv != $tv;
					print "$F: tn=$tn fn=$fn in $file\n" if $V>0 && $fn != $tn;
					++$nwarn; ++$warnings;
				} else {
					print "$F: Tune index \"$tx\" and file \"$file\" agree.\n" if $V>1;
				}
			} else {
				print V "$F: Index \"$tx\" not parsed.\n" if $V>2;
			}
		} else {
			print V "$F: Line \"$line\" not parsed.\n" if $V>2;
		}
	}
	print "$F: $nerr errors $nwarn warnings in $file\n" if $V>0 && ($nerr || $nwarn);
	return $nerr + $nwarn;
}

sub Vopt {
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
#   &Vopt("5myname.log");                                                     #
# Set  the  verbosity from various environment variables.  The value may be a #
# verbose level (1 digit), plus an optional output file name.  The file V  is #
# opened to the file, if any, or STDERR by default. The default value for the #
# verbosity level is 1, which generally means to produce only  serious  error #
# messages.                                                                   #
#                                                                             #
# Here's how this routine is typically called:                                #
#   ($P = $0) =~ s'.*/''; # Program name without directories                  #
#   &Vopt($ENV{"V_$P"} || $ENV{"D_$P"} || $ENV{"T_$P"} || '1');               #
# That's for when you want to call this a "verbose" and "debug"  and  "trace" #
# facility.  I mostly just use the V_$P environment variable.                 #
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
	$Vopt = shift || '1';			# Make sure we have a verbosity string
	$V = 1 unless defined $V;
	($P = $0) =~ s'.*/'' unless defined($P);
	print "<br>Vopt: Vopt=\"$Vopt\"<br>\n" if $V>2;
	if ($Vopt =~ /^(\d+)(.*)$/) {	# Initial debug level 0-9?
		$V = int($1);				# Verbose level
		if ($Vfil = $2) {			# Verbose output file?
			if (open(V,">>$Vfil")) {	# Try to append to the file
				open(STDERR,">>&V");	# Switch STDERR over to V
			} else {
				print STDERR "$P: Can't append to \"$Vfil\" ($!)\n" if $V>0;
				open(V,">>&STDERR");	# STDERR is the default 
			}
		} else {					# No file name, use STDERR
			open(V,">>&STDERR");    # STDERR is the default
		}
	} elsif ($Vopt) {				# File name only?
		if (open(V,">>$Vopt")) {	# Try to append to the file
			open(STDERR,">>&V");	# Switch STDERR over to V
		} else {
			print V "$P: Can't append to \"$Vopt\" ($!)\n" if $V>0;
			open(V,">>&STDERR");	# STDERR is the default 
		}
	} else {
		$V ++;					# Null arg, just increment the verbose level
		open(V,">>&STDERR");	# And write to STDERR
	}
	select V; $| = 1;			# Make V unbuffered
	select STDOUT; $| = 1;		# Make sure STDERR is unbuffered
	$esep = '=' x 70;
	print V "\n$P $esep\n" if $V>1;	# Tell the world if we're verbose
	print V "$P started with V=$V [pid=$$] ", `date` if $V>1;
}

