diff options
Diffstat (limited to 'src/foomatic/foomatic-generator.in')
-rw-r--r-- | src/foomatic/foomatic-generator.in | 671 |
1 files changed, 671 insertions, 0 deletions
diff --git a/src/foomatic/foomatic-generator.in b/src/foomatic/foomatic-generator.in new file mode 100644 index 0000000..57950aa --- /dev/null +++ b/src/foomatic/foomatic-generator.in @@ -0,0 +1,671 @@ +#!@PERL@ + +# Wherever we put it... +my $mapfile; +# $mapfile = "../main/printers.xml"; +$mapfile = "foomatic-printermap"; + + +# The following substitutions happen to the template XML files: +# @@STPVER@@ - the version number (ie '4.1.5') +# @@DRVNAME@@ - driver name (ie gimp-print) +# @@STPRINTERS@@ - <printers>...</printers> clause for the driver +# @@OPTCONSTRAINTS@@ - <constraints>...</constraints> object for the option +# @@ENUMVALS@@ - <enum_vals>...</enum_vals> section for the enum option +# @@MINVAL@@ - minimum value for numeric setting +# @@MAXVAL@@ - maximum value for numeric setting +# @@DEFVAL@@ - default value for numeric setting + +# For some things, there are option-specific root-around-n-writer +# functions. So we have a dispatch table: +# +# function arguments are: ('StpDriverOptionName') + +my $funcs = { 'InputSlot' => { 'OPTCONSTRAINTS' => \&build_cons, + 'ENUMVALS' => \&build_ev, }, + 'InkType' => { 'OPTCONSTRAINTS' => \&build_cons, + 'ENUMVALS' => \&build_ev }, + 'MediaType' => { 'OPTCONSTRAINTS' => \&build_cons, + 'ENUMVALS' => \&build_ev }, + 'Model' => { 'OPTCONSTRAINTS' => \&build_model_cons, + 'ENUMVALS' => \&build_model_ev }, + 'PageSize' => { 'OPTCONSTRAINTS' => \&build_cons, + 'ENUMVALS' => \&build_ev }, + 'Quality' => { 'OPTCONSTRAINTS' => \&build_cons, + 'ENUMVALS' => \&build_ev }, + 'Dither' => { 'OPTCONSTRAINTS' => \&build_cons, + 'ENUMVALS' => \&build_ev }, + 'Color' => { 'OPTCONSTRAINTS' => \&build_cons, + 'ENUMVALS' => \&build_ev }, + 'Resolution' => { 'OPTCONSTRAINTS' => \&build_resolution_cons, + 'ENUMVALS' => \&build_resolution_ev }, + }; + +my $drivervals = { 'PageSize' => \&optmap_pagesize, + 'Color' => \&optmap_color + }; + +my $debug = 0; + +# Foomatic name => Gimp-print name +%argnamemap = ('Quality' => 'Resolution'); + +%colormap = ('Grayscale' => 0, + 'Color' => 1, + 'BlackAndWhite' => 2); + +use Data::Dumper; + +open PIPE, "./printer_options|" or die "Cannot run printer_options: $!\n"; +print STDERR "Loading options from ./printer_options..."; +while(<PIPE>) { + next if m!^#!; + eval $_; +} +close PIPE or die "Cannot run printer_options: $!\n"; +print STDERR "done.\n"; + +open PIPE, "./stp_limits|" or die "Cannot run stp_limits: $!\n"; +print STDERR "Loading options from ./stp_limits..."; +while(<PIPE>) { + next if m!^#!; + eval $_; +} +close PIPE or die "Cannot run stp_limits: $!\n"; +print STDERR "done.\n"; + +open PIPE, "./printers|" or die "Cannot run printers: $!\n"; +print STDERR "Loading options from ./printers..."; +while(<PIPE>) { + next if m!^#!; + eval $_; +} +close PIPE or die "Cannot run printers: $!\n"; +print STDERR "done.\n"; + +# OK, now %stpdata is a big honking thing, and %defaults is in there, too. + +# Invert, to build %bar{$optionname} = [ choice1, choice2 ]; +my ($a, $otmp, $vtmp); +for $a (keys(%stpdata)) { + for $otmp (keys %{$stpdata{$a}}) { + for $vtmp (keys (%{$stpdata{$a}{$otmp}})) { + if (!$seen_evchoice{$otmp}{$vtmp}++) { + push (@{$ev_choices{$otmp}}, [ $vtmp, + $stpdata{$a}{$otmp}{$vtmp}]); + } + } + } +} + + +# Step 1: construct a map from Model= values to Foomatic model id's +# this map is %mapstp. The inverse from model to Model is %mapdb +# +# Foomatic is supposed to be a superset, so + +open PRINTERS, $mapfile or die "Cannot open mapfile $mapfile: $!\n"; +for (<PRINTERS>) { + if (m!^#\s*gptofoo\s+([^\s]+)\s+([^\s]+)!) { + push (@{$mapstp{$1}}, $2); + $mapfoo{$2} = $1; # do we need? + } +} + +$missing_drivers = 0; + +# Are we missing any stp printers? +for (keys(%stpdata)) { + if (!defined($mapstp{$_})) { + $missing_drivers = 1; + warn "No foomatic printer IDs for gimp-print printer $_.\n"; + } +} + +if ($missing_drivers) { + die "Cannot continue\n"; +} + +# Figure out version etc +open PIPE, "./gimp-print-version|" or die "Cannot run gimp-print-version: $!\n"; +my $stpvers = <PIPE>; +close PIPE or die "Cannot run gimp-print-version: $!\n"; +chomp $stpvers; +print STDERR "Using drivername gimp-print\n"; + +# Build <printers> clause... +my @printerlist = (); +push (@printerlist, " <printers>\n"); +my $p1; +for $p1 (keys(%mapstp)) { + push (@printerlist, " <!-- gimp-print driver: $p1 -->\n"); + for (@{$mapstp{$p1}}) { + push(@printerlist, " <printer><id>$_</id></printer>\n"); + } +} +push (@printerlist, " </printers>\n"); + +my $generalsubs = { 'STPVER' => $stpvers, + 'DRVNAME' => "gimp-print", + 'STPRINTERS' => join('', @printerlist) }; + +my @numericsubs = ('MINVAL', 'MAXVAL', 'DEFVAL'); + +opendir TDIR, "foomatic-templates" or die "Cannot open templates directory: $!\n"; + +# OK, make the db heirarchy alongside the templates one... +mkdir 'foomatic-db', 0755 or die "Cannot create directory foomatic-db: $!\n" + unless -d 'foomatic-db'; +mkdir 'foomatic-db/opt', 0755 or die "Cannot create directory foomatic-db/opt: $!\n" + unless -d 'foomatic-db/opt'; +mkdir 'foomatic-db/driver', 0755 or die "Cannot create directory foomatic-db/driver: $!\n" + unless -d 'foomatic-db/driver'; + +# Now do stuff, already. Do the substitution into each file... +my $tmpl; +while ($tmpl=readdir(TDIR)) { + next if ($tmpl !~ m!.+\.xml$!); + + my $fooopt = $tmpl; + $fooopt =~ s!\.xml$!!; + my $stpopt = $argnamemap{$fooopt}; + $stpopt = $fooopt if ! defined ($stpopt); + +# print STDERR "Argnamemap '$fooopt' => '$stpopt'\n"; + + open TMPL, "foomatic-templates/$tmpl"; + my @datafile = <TMPL>; + close TMPL; + + print STDERR "Processing $tmpl..."; + + my $template = join('',@datafile); + + # First, do the generic substitutions. + + my ($substr); + for $substr (keys(%$generalsubs)) { + my $substitution = $generalsubs->{$substr}; + $template =~ s!\@\@$substr\@\@!$substitution!g; + } + + # Now do the numeric substitutions + + for $substr (@numericsubs) { + my $substitution = $stp_values{$substr}{$stpopt}; + $template =~ s!\@\@$substr\@\@!$substitution!g; + } + + # Now do special-purpose substitutions + + for $substr (keys(%{$funcs->{$fooopt}})) { + my $substitution = &{$funcs->{$fooopt}{$substr}}($stpopt); + if (defined($substitution)) { + $template =~ s!\@\@$substr\@\@!$substitution!g; + } + } + + # Any more? + grep (m!\@\@([^\@]+)\@\@!g + && do { warn " Unknown substitution $1 in $tmpl!\n"; }, + split("\n",$template)); + + # Finally, write out the new file + + # Options are under opt/ + my $dbfilename = lc("foomatic-db/opt/gimp-print-$tmpl"); + + # Special case the actual driver file under driver/ + $dbfilename = "foomatic-db/driver/gimp-print.xml" + if ($tmpl eq 'gimp-print.xml'); + + open NEWF, "> $dbfilename" or die "Cannot create $dbfilename: $!"; + print STDERR "writing $dbfilename..."; + print NEWF $template; + print STDERR "done.\n"; + close NEWF; + +} + + + +sub get_ev_shortname { + my ($val) = @_; + $val =~ s/ //g; + $val =~ s/\///g; + $val =~ s/\://g; + return $val; +} + +sub get_ev_key { + my ($val, $drv) = @_; + return ("ev/$drv-" . get_ev_shortname($val)); +} + +sub build_ev { + my ($stpopt) = @_; + my $drvname = $generalsubs->{'DRVNAME'}; + + my @vals = (); + + # OK, now for each enum_val + my $ev; + for $ev (@{$ev_choices{$stpopt}}) { + # Put in the basic choice info: ev names, etc + my $ev_longname = @$ev[1]; + my $ev_shortname = @$ev[0]; + my $ev_id = get_ev_key($ev_shortname, $drvname); + my $ev_driverval; + + # Either call a per-option function to get the driverval, or + # just use the string choice name. + if (defined($drivervals->{$stpopt})) { + $ev_driverval = &{$drivervals->{$stpopt}}($ev_shortname); + die "Undefined driverval for option $stpopt value $ev_shortname!\n" + if (! defined($ev)); + } else { + $ev_driverval = $ev_shortname; + } + push (@vals, + " <enum_val id='$ev_id'>\n", + " <ev_longname><en>$ev_longname</en></ev_longname>\n", + " <ev_shortname><en>$ev_shortname</en></ev_shortname>\n", + " <ev_driverval>$ev_driverval</ev_driverval>\n", + " <constraints>\n", + " <!-- Assume the option doesn't apply... -->\n", + " <constraint sense='false'>\n", + " <driver>$drvname</driver>\n", + " </constraint>\n"); + + # Build constraints for this particular ev + my $stpprn; + for $stpprn (keys(%stpdata)) { + my $fooprn; + for $fooprn (@{$mapstp{$stpprn}}) { + if ($stpdata{$stpprn}{$stpopt}{$ev_shortname}) { + # OK, this choice applies to this enum + push (@vals, + " <constraint sense='true'>\n", + " <!-- $fooprn == $stpprn -->\n", + " <driver>$drvname</driver>\n", + " <printer>$fooprn</printer>\n", + " </constraint>\n"); + } + } + } + + push (@vals, + " </constraints>\n", + " </enum_val>\n"); + } + + return join('', + "<enum_vals>\n", + @vals, + " </enum_vals>\n"); +} + +sub build_cons { + + my ($stpopt) = @_; + + my $drvname = $generalsubs->{'DRVNAME'}; + + my @PNCONS = (); + + # For each stp printer... + my $stpname; + for $stpname (keys(%stpdata)) { + + if (0) { + print STDERR " Processing gimp-print printer $stpname...\n"; + print STDERR + " There are no foomatic printers mapped to $stpname!?\n" + if !$mapstp{$stpname}; + print STDERR " \%stpdata key is {$stpname}{$stpopt}\n"; + } + + # Add to this printer to argument constraints? + if ($stpdata{$stpname}{$stpopt}) { + + # What's the default value? + my $stpdef = $defaults{$stpname}{$stpopt}; + + # If there's no default, then this option doesn't apply to + # this printer. + if (defined($stpdef)) { + + my $foodefval = get_ev_key($stpdef, $drvname); + + if (0) { + print STDERR + " Default for $stpname/$stpopt is $stpdef aka $foodefval\n"; + } + + my $fooname; + for $fooname (@{$mapstp{$stpname}}) { + + if (0) { + print STDERR + " Printer $fooname takes option $stpopt.\n"; + } + + push (@PNCONS, + " <constraint sense='true'>\n", + " <driver>gimp-print</driver>\n", + " <printer>$fooname</printer><!-- gimp-print name: $stpname -->\n", + " <arg_defval>$foodefval</arg_defval>\n", + " </constraint>\n"); + } + } + } + + } + + return join('', + "<constraints>\n", + @PNCONS, + " </constraints>\n"); +} + +sub optmap_pagesize { + my ($value) = @_; + + if (!defined $pagemap) { + open PUTIL, "./paper_sizes |" or die "Cannot run paper_sizes: $!\n"; + while (<PUTIL>) { + chomp; + $_ =~ m!^\s*(.+\S)\s+([0-9]+)\s+([0-9]+)\s*$!; + my ($name, $width, $height) = ($1, $2, $3); + if ($width >= 0 and $height >= 0) { + $pagemap->{$name} = "$width $height"; +# print STDERR "PageSize '$name' driverval '$width $height'\n"; + } + } + close PUTIL; + } + + return $pagemap->{$value} +} + +sub optmap_color { + my ($value) = @_; + if (defined $colormap{$value}) { + return $colormap{$value}; + } else { + die "Cannot map output type '$value'\n"; + } +} + +sub build_model_cons { + my ($stpopt) = @_; + my $drvname = $generalsubs->{'DRVNAME'}; + + + # OK, this is funky. For each stp model, we have a choice. That + # choice is valid for only the foo printers that correspond. For + # any given foo printer, there is *exactly one* available choice. + # The defval is the one available choice. Backends and + # applications do not show choices with only one option; they just + # select that option. So we don't bother to make pretty option + # names or anything. + # + # See also build_model_ev() + + my @PNCONS = (); + + # For each stp printer... + my $stpname; + for $stpname (keys(%mapstp)) { + + # For each possible foo name + my $fooname; + for $fooname (@{$mapstp{$stpname}}) { + + # What's the default value? + my $foodefval = get_ev_key($stpname, $drvname); + + push (@PNCONS, + " <constraint sense='true'>\n", + " <driver>$drvname</driver>\n", + " <printer>$fooname</printer>\n", + " <arg_defval>$foodefval</arg_defval>\n", + " </constraint>\n"); + } + } + + return join('', + "<constraints>\n", + @PNCONS, + " </constraints>\n"); + + +} + +# See build_model_cons, above. +sub build_model_ev { + my ($stpopt) = @_; + my $drvname = $generalsubs->{'DRVNAME'}; + + my @vals = (); + + # OK, now for each enum_val + my $ev; + for $ev (keys(%mapstp)) { + # Put in the basic choice info: ev names, etc + my $ev_shortname = $ev; + my $ev_longname = $printer_name{$ev}; + my $ev_shortname = get_ev_shortname($ev); + my $ev_id = get_ev_key($ev, $drvname); + my $ev_driverval = $ev; + + push (@vals, + " <enum_val id='$ev_id'>\n", + " <ev_longname><en>$ev_longname</en></ev_longname>\n", + " <ev_shortname><en>$ev_shortname</en></ev_shortname>\n", + " <ev_driverval>$ev_driverval</ev_driverval>\n", + " <constraints>\n", + " <!-- Assume the option doesn't apply... -->\n", + " <constraint sense='false'>\n", + " <driver>$drvname</driver>\n", + " </constraint>\n", + " <!-- ...except to these: -->\n", + ); + + # This stp Model value applies only to mapped foo printers + my $fooprn; + for $fooprn (@{$mapstp{$ev}}) { + + # OK, this choice applies to this enum + push (@vals, + " <constraint sense='true'>\n", + " <!-- Model $ev for $fooprn -->\n", + " <driver>$drvname</driver>\n", + " <printer>$fooprn</printer>\n", + " </constraint>\n"); + } + + push (@vals, + " </constraints>\n", + " </enum_val>\n"); + } + + return join('', + "<enum_vals>\n", + @vals, + " </enum_vals>\n"); +} + + +# Stuff for Resolution. +# +# printer_options gives us Quality information. We examine this to +# determine what to do for the gs resolution argument: +# +# - Is this a 180/360/720 printer or a 150/300/600 printer? +# +# - What are the legal resolutions? Sort of parse and compute these +# from the Resolution values. +# +# The driverval is "x y", and gets passedin a /HWResolution ps clause + +sub compute_resolutions { + my ($stpname) = @_; + + if (!defined($rescache{$stpname})) { + + my @reslist = (); + my %hash; + my $defval; + + my $qual; + for $qual (keys(%{$stpdata{$stpname}{'Resolution'}})) { + $qual =~ m!(\d+)\s*(x\s*(\d+))?!; + my ($x, $y) = ($1, $3); + $y = $x if !defined($y); + + my $r = {'x' => $x, + 'y' => $y, + 'driverval' => "$x $y", + 'ev_key' => get_ev_key("res-$x-$y", "gimp-print") + }; + push (@reslist, $r); + + # Default? + $defval = get_ev_key("res-$x-$y", "gimp-print") + if ($qual eq $defaults{$stpname}{'Resolution'}); + + # Note that this resolution value exists + $resolutions{"$x $y"} = { 'x' => $x, + 'y' => $y }; + + # Note that this printer takes this resolution + $hash{$x}{$y} = 1; + + } + + $rescache{$stpname}{'list'} = \@reslist; + $rescache{$stpname}{'defval'} = $defval; + $rescache{$stpname}{'takesit'} = \%hash; + + die "No default gsResolution found for printer $stpname!?\n" + if ! defined($defval); + } + + return $rescache{$stpname}; +} + +sub do_all_res { + my $n; + for $n (keys(%mapstp)) { + compute_resolutions($n); + } +} + +sub build_resolution_ev { + my ($stpopt) = @_; + my $drvname = $generalsubs->{'DRVNAME'}; + + my @vals = (); + + do_all_res(); + + # OK, now for each possible resolution... + my $ev; + for $ev (keys(%resolutions)) { + + my ($x, $y) = ($resolutions{$ev}{'x'}, $resolutions{$ev}{'y'}); + + # Put in the basic choice info: ev names, etc + my $ev_longname = "$x x $y DPI"; + my $ev_shortname = get_ev_shortname($ev_longname); + my $ev_id = get_ev_key("res-$x-$y", $drvname); + my $ev_driverval = "$x $y"; + + push (@vals, + " <enum_val id='$ev_id'>\n", + " <ev_longname><en>$ev_longname</en></ev_longname>\n", + " <ev_shortname><en>$ev_shortname</en></ev_shortname>\n", + " <ev_driverval>$ev_driverval</ev_driverval>\n", + " <constraints>\n", + " <!-- Assume the option doesn't apply... -->\n", + " <constraint sense='false'>\n", + " <driver>$drvname</driver>\n", + " </constraint>\n", + " <!-- ...except to these: -->\n", + ); + + # Now, for each printer, put in a constraint if this + # resolution makes sense or not... + my $stpprn; + for $stpprn (keys(%mapstp)) { + + my $resobj = compute_resolutions($stpprn); + my $takesit = $resobj->{'takesit'}{$x}{$y}; + + if ($takesit) { + my $fooprn; + for $fooprn (@{$mapstp{$stpprn}}) { + +# print STDERR "Printer $fooprn $stpprn uses ${x}x$y\n"; + + # OK, this choice applies to this enum + push (@vals, + " <constraint sense='true'>\n", + " <driver>$drvname</driver>\n", + " <printer>$fooprn</printer><!-- stpname: $stpprn -->\n", + " </constraint>\n"); + } + } + + } + + push (@vals, + " </constraints>\n", + " </enum_val>\n"); + } + + return join('', + "<enum_vals>\n", + @vals, + " </enum_vals>\n"); +} + +sub build_resolution_cons { + my ($stpopt) = @_; + my $drvname = $generalsubs->{'DRVNAME'}; + + my @PNCONS = (); + + # For each stp printer... + my $stpname; + for $stpname (keys(%mapstp)) { + + # Get some resolution info + my $r = compute_resolutions($stpname); + + # For each possible foo name + my $fooname; + for $fooname (@{$mapstp{$stpname}}) { + + # What's the default value? + my $foodefval = $r->{'defval'}; + + push (@PNCONS, + " <constraint sense='true'>\n", + " <driver>$drvname</driver>\n", + " <printer>$fooname</printer><!-- stpname: $stpname -->\n", + " <arg_defval>$foodefval</arg_defval>\n", + " </constraint>\n"); + } + } + + return join('', + "<constraints>\n", + @PNCONS, + " </constraints>\n"); +} + + +exit(0); + |