# Key Value Pair File Format reader/writer 1.0
# By Tyler Bletsch
use Carp;
 
# Format:
#    ; comment type one
#    # comment type two
#    ; 
#    ; standard key value pair
#    key1=value1
#    ; multiline value
#    key2=\
#    This is literally the data.
#    The only problem is that there is no way to escape the end symbol,
#    which is a dot alone on a line (AKA "\n.\n").
#    .
#    ; if your data has an equal sign, a multiline escape is used
#    ;   (even if the data is one line)
#    key3=\
#    This single-line data contains a '=', which is an equal sign.
#    .
#    ; A non-data, non-comment, non-blank line is an error.
#    ; If one is read, it will generate a carp (warning)
 
 
 
# Read a file and return a hash of it's content.  Returns undef on error.
# Will carp if a file can't be opened for reading.
# Ex:
#  %myData = kvpRead('myfile.kvp');
sub kvpRead {
	my ($filename) = @_;
	open $fp,$filename  or (carp "Couldn't open '$filename' for read ($!).\n",return);
	my %result;
	my $lineNum=0;
	while (<$fp>) {
		my ($k,$v);
		$lineNum++;
		chomp;
		if (/\s*(.*)\s*=\s*\\\s*$/) { #multiline
			$k=$1;
			{
				local $/="\n.\n";
				$v = <$fp>;
				chomp $v;
			}
			$result{$k}=$v;
		} elsif (/\s*(.*)\s*=(.*)/) {
			($k,$v) = ($1,$2);
			$result{$k}=$v;
		} elsif (/^\s*[;#]/ || /^\s*$/) {
			#ignore this comment/blank
		} else {
			carp "Unrecognized format, line $lineNum of in '$filename'.\n";
		}
	}
	return %result;
 
}
 
# Write a hash of printable scalars (i.e. not references) to a KVP file.
# Return true on sucess, false on failure.  Will carp if a file can't be opened
# for writing.
# Ex:
#  %myData = kvpRead('myfile.kvp');
sub kvpWrite {
	my ($filename,%data) = @_;
	open $fp,"> $filename" or (carp "Couldn't open '$filename' for write ($!).\n",return);
	while (my ($k,$v) = each(%data)) {
		$k =~ s/=/\\=/g;
		if ($v=~/[=\n]/ || $v=~/^\\$/) {
			print $fp "$k=\\\n$v\n.\n";
		} else {
			$v =~ s/=/\\=/g;
			print $fp "$k=$v\n";
		}
	}
	close $fp;
	return 1;
}
 
 
1;
 
__END__
 
 
# Tests:
use Data::Dumper;
 
$a{b} = '\\';
$a{c} = 'alpha=beta';
$a{m1} = "this\nis\nmulti=line\n";
$a{m2} = "=\nthis\nis\nmultiline too\n";
 
print Dumper(%a);
 
print "------------------------------\n";
#kvpWrite "test1.kvp",%a;
 
print Dumper(%a);
 
print "------------------------------\n";
 
%b = kvpRead "test1.kvp";
 
print Dumper(%b);