4 # normalise [NORM-OPTIONS...] [--] INPUT-FILES...
7 # +OPTNAME[=OPTVAL] Election option
9 # +CAND+OPTNAME[=OPTVAL] Candidate option
10 # -- End of options to normalise
11 # -... Reserved for future options to normalise
16 our %candidates; # $candidates{CAND}{Desc}, {Opts}[]
17 our %candref; # $candref{CAND} => msg of why needed
20 my $candvoter_re = '\w+';
21 my $cands_re = '\w+(?,\w+)*';
22 my $opt_re = '\w+(?:=\S*)?';
25 die "bad input: $_[0]";
28 sub normalise_opts_list ($$) {
29 # $ctx is one of Election Candidate Ballot
33 foreach my $o (split /\s+/, $os) {
36 } elsif ($o =~ s/^_[Tt]ie\=//) {
37 $o =~ m/^($cands_re)([<>])($cands_re)$/
38 or badinput "bad value \`$_' for tie option";
39 my ($l,$op,$r) = ($1,$2,$3);
40 ($l,$op,$r) = ($r,'>',$l) if $op eq '<';
41 $candref{$_} = "tie break spec" foreach $o =~ m/\w+/g;
42 $l = join ',', sort split /\,/, $l;
43 $r = join ',', sort split /\,/, $r;
44 $l =~ m/\b$_\b/ and badinput "reflexive tie"
45 foreach split /\,/, $r;
47 } elsif ($o =~ m/^\w+\=\S+$/) {
49 } elsif ($o !~ m/\S/) {
51 badinput "bad option \`$o'";
57 sub normalise_opts ($$) {
59 my @o = normalise_opts_list $os, $ctx;
63 sub setcanddesc ($$) {
64 my ($cand,$desc) = @_;
67 badinput "multiple descriptions for $cand" if
68 defined $candidates{$cand}{Desc};
69 $candidates{$cand}{Desc} = $desc;
77 } elsif (m/^(\w+)=([^|]+)$/) {
79 } elsif (m/^\+($opt_re)$/) {
81 } elsif (m/^\+(\w+)\+($opt_re)$/) {
82 push @{ $candidates{$1}{Opts} }, $2;
84 die "unknown normalise option \`$_'\n";
98 push @options, normalise_opts_list $', 'Election';
99 } elsif (m/^($candvoter_re?)\s*=\s*([^|]+?)\s*\|(.*)?$/o) {
101 print STDERR Dumper($1,$2,$3);
102 my ($cand,$desc,$opts) = ($1,$2,$3);
103 push @{ $candidates{$cand}{Opts} }, normalise_opts $opts, 'Candidate';
104 setcanddesc $cand, $desc;
105 } elsif (m/^($candvoter_re?)?\s*\:([^|]*)(?:\|(.*))?$/) {
106 my ($voter,$opts) = ($1,$3);
108 foreach my $p (split /\s+/, $2) {
109 if ($p =~ m/^\w+(?:\=\w+)*$/) {
111 $candidates{$_} //= { } foreach $p =~ m/\w+/g;
113 # empty entry can only happen if voter casts no prefs at all
115 badinput "bad vote preference \`$p'";
118 push @ballots, "$voter : @p".normalise_opts $opts, 'Ballot';
121 badinput "unknown line format \`$_'";
125 print "| @options\n" or die $!;
127 foreach my $cand (sort keys %candref) {
128 badinput "missing candidate $cand (ref. by $candref{$cand}"
129 unless defined $candidates{$cand};
132 foreach my $cand (sort keys %candidates) {
133 my $c = $candidates{$cand};
134 $c->{Desc} //= $cand;
136 my $opts = $c->{Opts};
137 print "$cand = $c->{Desc} | @$opts\n" or die $!;
140 sub vsortkey { $_[0] =~ m/:/; return "$' : $`"; }
142 print $_,"\n" or die $! foreach
143 sort { vsortkey($a) cmp vsortkey($b) } @ballots;
145 print ".\n" or die $!;