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}[]
19 my $candvoter_re = '\w+';
20 my $opt_re = '\w+(?:=\S*)?';
23 die "bad input: $_[0]";
26 sub normalise_opts_list ($) {
30 foreach my $o (split /\s+/, $os) {
33 } elsif ($o =~ m/^\w+\=\S+$/) {
35 } elsif ($o !~ m/\S/) {
37 badinput "bad option \`$o'";
43 sub normalise_opts ($) {
45 my @o = normalise_opts_list $os;
49 sub setcanddesc ($$) {
50 my ($cand,$desc) = @_;
53 badinput "multiple descriptions for $cand" if
54 defined $candidates{$cand}{Desc};
55 $candidates{$cand}{Desc} = $desc;
63 } elsif (m/^(\w+)=([^|]+)$/) {
65 } elsif (m/^\+($opt_re)$/) {
67 } elsif (m/^\+(\w+)\+($opt_re)$/) {
68 push @{ $candidates{$1}{Opts} }, $2;
70 die "unknown normalise option \`$_'\n";
84 push @options, normalise_opts_list $';
85 } elsif (m/^($candvoter_re?)\s*=\s*([^|]+?)\s*\|(.*)?$/o) {
87 print STDERR Dumper($1,$2,$3);
88 my ($cand,$desc,$opts) = ($1,$2,$3);
89 push @{ $candidates{$cand}{Opts} }, normalise_opts $opts;
90 setcanddesc $cand, $desc;
91 } elsif (m/^($candvoter_re?)?\s*\:([^|]*)(?:\|(.*))?$/) {
92 my ($voter,$opts) = ($1,$3);
94 foreach my $p (split /\s+/, $2) {
95 if ($p =~ m/^\w+(?:\=\w+)*$/) {
97 $candidates{$_} //= { } foreach $p =~ m/\w+/g;
99 # empty entry can only happen if voter casts no prefs at all
101 badinput "bad vote preference \`$p'";
104 push @ballots, "$voter : @p".normalise_opts $opts;
107 badinput "unknown line format \`$_'";
111 print "| @options\n" or die $!;
113 foreach my $cand (sort keys %candidates) {
114 my $c = $candidates{$cand};
115 $c->{Desc} //= $cand;
117 my $opts = $c->{Opts};
118 print "$cand = $c->{Desc} | @$opts\n" or die $!;
121 sub vsortkey { $_[0] =~ m/:/; return "$' : $`"; }
123 print $_,"\n" or die $! foreach
124 sort { vsortkey($a) cmp vsortkey($b) } @ballots;
126 print ".\n" or die $!;