#!/usr/bin/perl
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
#NAME
#  deMorse - convert from Morse Code to text
#
#SYNOPSIS
#  deMorse [file]..
#
#DESCRIPTION
#  Read one or more input files (default: STDIN), looking for embedded  Morse
#  Code.  When found, the Morse Code is converted to text.
#
#  The '/' char may be used as a spacer, with "/ /" used for a  newline.   Or
#  you  can just use spaces and newlines.  If you use both, you'll get double
#  spaces and newlines.
#
#OPTIONS
#
#EXAMPLES
#
#FILES
#
#BUGS
#
#SEE ALSO
#
#AUTHOR
#  John Chambers <jc@trillian.mit.edu> 2005
#  There were lots of Morse-Code converters online, but all of them were part
#  of some bigger package. I couldn't find one that ran standalone. So I just
#  wrote one.  It took less time than the search that failed.
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #

$| = 1;
$exitstat = 0;
($P = $0) =~ s".*/"";
$V = $ENV{"V_$P"} || $ENV{"D_$P"} || 1;	# Verbose level.

%C2M	= (
	'A'	=> '.-',
	'B'	=> '-...',
	'C'	=> '-.-.',
	'D'	=> '-..',
	'E'	=> '.',
	'F'	=> '..-.',
	'G'	=> '--.',
	'H'	=> '....',
	'I'	=> '..',
	'J'	=> '.---',
	'K'	=> '-.-',
	'L'	=> '.-..',
	'M'	=> '--',
	'N'	=> '-.',
	'O'	=> '---',
	'P'	=> '.--.',
	'Q'	=> '--.-',
	'R'	=> '.-.',
	'S'	=> '...',
	'T'	=> '-',
	'U'	=> '..-',
	'V'	=> '...-',
	'W'	=> '.--',
	'X'	=> '-..-',
	'Y'	=> '-.--',
	'Z'	=> '--..',
	'0'	=> '-----',
	'1'	=> '.----',
	'2'	=> '..---',
	'3'	=> '...--',
	'4'	=> '....-',
	'5'	=> '.....',
	'6'	=> '-....',
	'7'	=> '--...',
	'8'	=> '---..',
	'9'	=> '----.',
	'.'	=> '.-.-.-',
	','	=> '--..--',
	'?'	=> '..--.. ',      # Why does this contain a space?
);

%M2C	= (
	'.-'	=> 'A',
	'-...'	=> 'B',
	'-.-.'	=> 'C',
	'-..'	=> 'D',
	'.'	=> 'E',
	'..-.'	=> 'F',
	'--.'	=> 'G',
	'....'	=> 'H',
	'..'	=> 'I',
	'.---'	=> 'J',
	'-.-'	=> 'K',
	'.-..'	=> 'L',
	'--'	=> 'M',
	'-.'	=> 'N',
	'---'	=> 'O',
	'.--.'	=> 'P',
	'--.-'	=> 'Q',
	'.-.'	=> 'R',
	'...'	=> 'S',
	'-'	=> 'T',
	'..-'	=> 'U',
	'...-'	=> 'V',
	'.--'	=> 'W',
	'-..-'	=> 'X',
	'-.--'	=> 'Y',
	'--..'	=> 'Z',
	'-----'	=> '0',
	'.----'	=> '1',
	'..---'	=> '2',
	'...--'	=> '3',
	'....-'	=> '4',
	'.....'	=> '5',
	'-....'	=> '6',
	'--...'	=> '7',
	'---..'	=> '8',
	'----.'	=> '9',
	'.-.-.-'	=> '.',
	'--..--'	=> ',',
	'..--.. '	=> '?',     # Why does this contain a space?
#
	'/'	=> ' ',
#
	'.----.'	=> "'",
	'-.-.--'	=> '!',
	'-..-.'	=> '/',
	'-.--.-'	=> '()',
	'. ...'	=> '&',
	'---...'	=> ':',
	'-.-.-.'	=> ';',
	'-...-'	=> '=',
	'-..-.'	=> '/',	# Fraction bar
	'-....-'	=> '-',
	'..--.-'	=> '_',
	'.-..-.'	=> '"',
	'.--.-.'	=> '@',
);

for $arg (@ARGV) {
	if (($flag,$opts) = ($arg =~ /^([-+])(.*)$/)) {
		# No command-line options now
	} else {
		++$files;	# Count the file names
		if (open(F,$arg)) {
			&onefile(*F);
		} else {
			print STDERR "$P: Can't read \"$arg\" ($!)\n";
		}
	}
}
unless ($files > 0) {
	&onefile(*STDIN);
}

print "$P: Exit with status $exitstat.\n" if $V>1;
exit $exitstat;

sub onefile { my $F='onefile';
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
	local(*FIL) = @_;
	local($c,$in,$init,$morse,$out,$space);
	while ($in = <FIL>) {
		$in =~ s/[\r\s]+$//;
		$in = " $in ";
		print "$P: $in\n" if $V>2;
		while (($init,$morse,$in) = ($in =~ m"^ (.*?)([-/.]+)( .*)")) {
			if ($c = $M2C{$morse}) {
				print STDERR "$P: \"$morse\" is '$c'\n" if $V>2;
				if ($morse eq '/') {
				#	if ($space) {$out .= $init . "\n"}
				#	      else  {$out .= $init . ' '}
					++$space;	# Just count spaces
				} else {
					if ($space > 0) {
						$out .=  ($space > 1) ? "\n" : ' ';
						$space = 0;
					}
					$out .= $init . $c;
				}
			} else {
				print STDERR "$P: \"$morse\" not known.\n" if $V>1;
				$out .= $init . $morse;
			}
		}
		$out .= $in if $in;
		print "$out\n";
		$out = '';
	}
}
