- $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, 'Candidate';
+ setcanddesc $cand, $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, 'Ballot';
+ } elsif (m/^\.$/) {
+ } else {
+ badinput "unknown line format \`$_'";
+ }
+}
+
+print "| @options\n" or die $!;
+
+foreach my $cand (sort keys %candref) {
+ badinput "missing candidate $cand (ref. by $candref{$cand}"
+ unless defined $candidates{$cand};
+}
+
+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 $!;