summaryrefslogtreecommitdiff
path: root/src/foomatic/foomatic-generator.in
diff options
context:
space:
mode:
Diffstat (limited to 'src/foomatic/foomatic-generator.in')
-rw-r--r--src/foomatic/foomatic-generator.in671
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);
+