chiark / gitweb /
spi2loose and normalise fixes
[appendix-a6.git] / normalise
index ca5ecf7975742a29bb521de392b4295f68dabb3d..7db074006a9f6627376b7e88ea5276c0b859318f 100755 (executable)
--- a/normalise
+++ b/normalise
@@ -2,26 +2,37 @@
 
 use strict;
 
-our @options, @candiates, @voters;
+our @options;
+our %candidates; # $candidates{CAND}{Desc}, {Opts}[]
+our @ballots;
 
-our %seen_cand, %need_cand;
+my $candvoter_re = '\w+';
 
-my $candvoter_re = '[^\000-\037!"#$%()*+,/0-\136`-\177]+';
+sub badinput ($) {
+    die "bad input: $_[0]";
+}
 
-sub normalise_opts ($) {
+sub normalise_opts_list ($) {
     my ($os) = @_;
+    $os //= '';
     my @o;
     foreach my $o (split /\s+/, $os) {
        if ($o =~ m/^\w+$/) {
            push @o, $&;
        } elsif ($o =~ m/^\w+\=\S+$/) {
-           push @o, $&;S
-       } elseif ($o !~ m/\S/) {
+           push @o, $&;
+       } elsif ($o !~ m/\S/) {
        } else {
            badinput "bad option \`$o'";
        }
     }
-    return @o ? " | @o" : "";
+    return @o;
+}
+
+sub normalise_opts ($) {
+    my ($os) = @_;
+    my @o = normalise_opts_list $os;
+    return " | @o";
 }
 
 while (<>) {
@@ -29,12 +40,51 @@ while (<>) {
     next if m/^\#/;
     s/^\s+//;
     s/\s+$//;
-    if (m/^\|\s*(\w+(?:\=\S+)?)$/) {
-       push @options, "| $1";
-    } elsif (m/^($candvoter_re?)\s*=\s*([^|]+?)\s*|(.*)?$/) {
+    if (m/^\|/) {
+       push @options, normalise_opts_list $';
+    } elsif (m/^($candvoter_re?)\s*=\s*([^|]+?)\s*\|(.*)?$/o) {
+       use Data::Dumper;
+print STDERR Dumper($1,$2,$3);
        my ($cand,$desc,$opts) = ($1,$2,$3);
-       $desc=$cand unless length $desc;
-       $opts = normalise_opts $opts;
-       push @candidates, "$cand = $desc".$opts;
-    } elsif (m/^($candvoter_re?)?\s*\:/) {
-       
+       push @{ $candidates{$cand}{Opts} }, normalise_opts $opts;
+       if (length $desc) {
+           badinput "multiple descriptions for $cand" if
+               defined $candidates{$cand}{Desc};
+           $candidates{$cand}{Desc} = $desc;
+       }
+    } elsif (m/^($candvoter_re?)?\s*\:([^|]*)(?:\|(.*))?$/) {
+       my ($voter,$opts) = ($1,$3);
+       my @p;
+       foreach my $p (split /\s+/, $2) {
+           if ($p =~ m/^\w+(?:\=\w+)*$/) {
+               push @p, $&;
+               $candidates{$_} //= { } foreach $p =~ m/\w+/g;
+           } elsif ($p eq '') {
+               # empty entry can only happen if voter casts no prefs at all
+           } else {
+               badinput "bad vote preference \`$p'";
+           }
+       }
+       push @ballots, "$voter : @p".normalise_opts $opts;
+    } elsif (m/^\.$/) {
+    } else {
+       badinput "unknown line format \`$_'";
+    }
+}
+
+print "| @options\n" or die $!;
+
+foreach my $cand (sort keys %candidates) {
+    my $c = $candidates{$cand};
+    $c->{Desc} //= $cand;
+    $c->{Opts} //= [ ];
+    my $opts = $c->{Opts};
+    print "$cand = $c->{Desc} | @$opts\n" or die $!;
+}
+
+sub vsortkey { $_[0] =~ m/:/; return "$' : $`"; }
+
+print $_,"\n" or die $! foreach
+    sort { vsortkey($a) cmp vsortkey($b) } @ballots;
+
+print ".\n" or die $!;