diff --git a/ppd/PPD.pm b/ppd/PPD.pm index 4f4556197087601538e242e649212f8e66884354..4f983140d61769933e8cebf1624ee44bc7f5d9fd 100644 --- a/ppd/PPD.pm +++ b/ppd/PPD.pm @@ -211,24 +211,104 @@ sub int_option($) { option($o); } +sub is_false($) { + return $_[0] =~ m{^(None|False)$}; +} + sub constrain($$$$) { my ($name, $k1, $k2, $condition) = @_; $name //= "$k1 vs. $k2"; + $k1 ne $k2 or die "Want to create constrait between a keyword $k1 and itself\n"; my $kw1 = $keywords{$k1} or die "Want to create constraint for unknown keyword $k1\n"; my $kw2 = $keywords{$k2} or die "Want to create constraint for unknown keyword $k2\n"; $kw1->{Type} eq 'o' && $kw2->{Type} eq 'o' or die "Want to create constraint between non-option keywords $k1 and $k2\n"; + + # Evaluate which combinations are permitted + my @vals1 = map { $_->{Key} } @{$kw1->{Values}}; + my @vals2 = map { $_->{Key} } @{$kw2->{Values}}; + my %allow = (); + for my $v1 (@vals1) { + for my $v2 (@vals2) { + $allow{$v1}{$v2} = $condition->($v1, $v2) ? 1 : 0; + } + } + my @c = (); - for my $vv1 (@{$kw1->{Values}}) { - for my $vv2 (@{$kw2->{Values}}) { - my $v1 = $vv1->{Key}; - my $v2 = $vv2->{Key}; - if (! &{$condition}($v1, $v2)) { - push @c, { K1 => $k1, V1 => $v1, K2 => $k2, V2 => $v2 }; - push @c, { K1 => $k2, V1 => $v2, K2 => $k1, V2 => $v1 }; + + my $case1 = sub { + # Special case 1: Forbid True & True + for my $v1 (@vals1) { + for my $v2 (@vals2) { + if (is_false($v1) || is_false($v2)) { + $allow{$v1}{$v2} or return; + } else { + !$allow{$v1}{$v2} or return; + } } } - } - push @constraints, { Name => $name, Pairs => [@c] } if @c; + push @c, { K1 => $k1, K2 => $k2 }; + return 1; + }; + + my $case2 = sub { + # Special case 2: Forbid True & subset + my %res = (); + for my $v1 (@vals1) { + for my $v2 (@vals2) { + if (is_false($v1)) { + $allow{$v1}{$v2} or return; + } else { + my $a = $allow{$v1}{$v2}; + $res{$v2} //= $a; + $res{$v2} == $a or return; + } + } + } + for my $v2 (@vals2) { + !$res{$v2} and push @c, { K1 => $k1, K2 => $k2, V2 => $v2 }; + } + return 1; + }; + + my $case3 = sub { + # Special case 3: Forbid subset & True + my %res = (); + for my $v1 (@vals1) { + for my $v2 (@vals2) { + if (is_false($v2)) { + $allow{$v1}{$v2} or return; + } else { + my $a = $allow{$v1}{$v2}; + $res{$v1} //= $a; + $res{$v1} == $a or return; + } + } + } + for my $v1 (@vals1) { + !$res{$v1} and push @c, { K1 => $k1, K2 => $k2, V1 => $v1 }; + } + return 1; + }; + + my $case4 = sub { + # General case + for my $v1 (@vals1) { + for my $v2 (@vals2) { + $allow{$v1}{$v2} or push @c, { K1 => $k1, V1 => $v1, K2 => $k2, V2 => $v2 }; + } + } + }; + + $case1->() || $case2->() || $case3->() || $case4->() || return; + @c or return; + + push @constraints, { + Name => $name, + Pairs => [ + @c, + map(+{ K1 => $_->{K2}, K2 => $_->{K1}, V1 => $_->{V2}, V2 => $_->{V1} }, @c), + ], + }; } ### Auxiliary functions ### @@ -447,12 +527,14 @@ sub emit_constraints() { for my $cc (@constraints) { heading($cc->{Name}); for my $c (@{$cc->{Pairs}}) { - printf "*%sUIConstraints: *%s %s *%s %s\n", + my $c1 = $c->{K1}; + $c1 .= ' ' . $c->{V1} if defined $c->{V1}; + my $c2 = $c->{K2}; + $c2 .= ' ' . $c->{V2} if defined $c->{V2}; + printf "*%sUIConstraints: *%s *%s\n", ((!$keywords{$c->{K1}}->{Choice} || !$keywords{$c->{K2}}->{Choice})) ? "Non" : "", - $c->{K1}, - $c->{V1}, - $c->{K2}, - $c->{V2}; + $c1, + $c2; } } } diff --git a/ppd/gen-nessie-xcpt b/ppd/gen-nessie-xcpt index 21f361d15d45166ed78c333c5f365c148a2f56ce..eed2ab9dd8aa67ac29a9e8d8f7f8704eaeb4ebb2 100755 --- a/ppd/gen-nessie-xcpt +++ b/ppd/gen-nessie-xcpt @@ -1,8 +1,5 @@ #!/usr/bin/perl -# FIXME: cupsIPPFinishings -# FIXME: cupsSingleFile? -# FIXME: Constraints # FIXME: Path to XCPT filter use strict; @@ -274,18 +271,6 @@ option({ ], }); -# FIXME: Update -#constrain(undef, 'InputSlot', 'MediaType', sub { -# my ($is, $mt) = @_; -# return !(($is eq 'Tray2' || $is eq 'Tray3') && -# ($mt eq 'Labels' || $mt eq 'Envelope')); -#}); - -#constrain(undef, 'Duplex', 'MediaType', sub { -# my ($dp, $mt) = @_; -# return !($dp ne 'None' && $mt =~ /^(Labels|Transparency|Bond)$/); -#}); - define_ui_group({ Key => 'Quality', Name => 'Print Quality' }); option({ @@ -584,4 +569,36 @@ ZapfChancery-MediumItalic: Standard "(003.000)" Standard ROM ZapfDingbats: Special "(002.000)" Special ROM AMEN +# Various constraints + +constrain(undef, 'PageSize', 'MediaType', sub { + my ($ps, $mt) = @_; + return !($ps =~ m{^Env} && $mt ne 'Envelopes' && $mt ne 'AutoSelect'); +}); + +constrain(undef, 'Duplex', 'PageSize', sub { + my ($dp, $ps) = @_; + return !($dp ne 'None' && $ps !~ m{^(A[345]|ISOB[345]|Letter|Legal)$}); +}); + +constrain(undef, 'Duplex', 'MediaType', sub { + my ($dp, $mt) = @_; + return !($dp ne 'None' && $mt =~ /^(Labels|Transparency|Bond|Envelopes)$/); +}); + +constrain(undef, 'StapleLocation', 'PageSize', sub { + my ($sl, $ps) = @_; + return !($sl ne 'None' && $ps !~ m{^(A[345]|ISOB[345]|Letter|Legal)$}); +}); + +constrain(undef, 'XRFold', 'StapleLocation', sub { + my ($f, $s) = @_; + return !($f ne 'None' && $s ne 'None'); +}); + +constrain(undef, 'XRFold', 'XRPunch', sub { + my ($f, $s) = @_; + return !($f ne 'None' && $s ne 'None'); +}); + generate();