+# deal with multiline options
+# %vars should never contain incomplete rows, but just in case it does,
+# we make a list of all the row indices that contain values, and
+# then write a line in each option for each row, even if it's empty.
+# This ensures that all values with the same row index line up.
+my %optionrows;
+foreach my $option (split(',', $cgi->param('multi_options'))) {
+ $optionrows{$option} = {};
+ my %values; # bear with me
+ for (keys %vars) {
+ /^$option(\d+)/ or next;
+ $optionrows{$option}{$1} = $vars{$option.$1};
+ $optionrows{_ALL_}{$1} = 1 if length($vars{$option.$1});
+ }
+}
+foreach my $option (split(',', $cgi->param('multi_options'))) {
+ my $value = '';
+ foreach my $row (sort keys %{$optionrows{_ALL_}}) {
+ $value .= ($optionrows{$option}{$row} // '') . "\n";
+ }
+ chomp($value);
+ $options{$option} = $value;
+}
+