#!/usr/bin/perl # $Id$ # # File: ppd-doc-extractor # Date: 27 Jan 2022 16:28:17 # Author: Alexander Zangerl # # Abstract: # very minimal recreation of the PPD documentation extractor # of foomatic-rip 3.x (which you got with foomatic-rip -o docs), which # is not part of the rewritten 4.x versions despite the documentation's # claims and the broken option code that doesn't reject what it cannot # handle. # # copyright (c) 2022 Alexander Zangerl # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 # as published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. use strict; use File::Slurp; use Data::Dumper; my ($ppdfile,@a2ps) = @ARGV; die "usage: $0 [a2ps args]\n no a2ps args: print to stdout automatically added: --center-title, --footer\n\n" if (!-f $ppdfile); my @stuff = read_file($ppdfile); # parse everything but massage and handle just the relevant parts my (%x, $curopengroup); for (my $i = 0; $i <= $#stuff; ++$i) { my $line = $stuff[$i]; $line =~ s/\r\n$//; # de-dos chomp $line; my ($key, $value, $option, $xlatoption); next if ($line =~ /^(\*%.*)?$/ or $line eq "*End"); if ($line =~ /^\*([^:]+):\s*(.+)\s*$/) { ($key, $value) = ($1,$2); if ($key =~ /^(\S+)\s+(.+)$/) { $key = $1; $option = $2; if ($option =~ m!^([^/]+)/(.+)$!) { ($option,$xlatoption) = ($1,$2); undef $xlatoption if ($xlatoption eq $option); # unnecessary ones } } # invocationvalue and quotedvalue allow continuation if ($value =~ /^"([^"]+)"\s*$/) { $value = $1; } elsif ($value =~ /^"([^"]*)*$/) { $value = $1; while ((my $nextline = $stuff[++$i]) !~ /"/) { $value .= $nextline; } if ($stuff[$i] =~ /^([^"]+)"\s*$/) { $value .= $1; } } # orderdependency is laid out extraspecially stupidly if ($key =~ /^(NonUI)?OrderDependency$/) { $key = "OrderDependency"; # we lump these together my ($num,$dontcare,$appliesto) = split(/\s+/,$value); ($option = $appliesto) =~ s/^\*//; $value = $num; } # want the options under openui w/o fluff elsif ($key eq "OpenUI") { $option =~ s/^\*//; } # another instance of shitty structural layout elsif ($key eq "OpenGroup") { if ($value =~ m!^\s*(\S+)/(.+)$!) { ($option,$xlatoption) = ($1,$2); } else { $xlatoption = $option = $value; } $curopengroup = $value = $option; } elsif ($key eq "CloseGroup") { undef $curopengroup; } if (defined $option) { # for option entries add a sequence number for sorting - simply use the line number $x{$key}->{$option} = { xlat => $xlatoption, value => $value, sequence => $i, ingroup => $curopengroup, }; } else { $x{$key} = $value; } } else { die "unrecognized line nr. $i\n"; } } # print Dumper(\%x); if (@a2ps) { push @a2ps, ("--center-title=Documentation for $x{ModelName}","--footer="); # lazy me: just duping the pipe fd... open(P, "|-", "a2ps", @a2ps) or die "cannot pipe to a2ps: $!\n"; open(STDOUT, ">&", \*P) or die "cannot dup: $!\n"; } print qq| Invocation summary for $x{ModelName}: Command line: lpr [-Z opt=value, opt=value...] [lpr options] List of available options:\n\n|; # meh...orderdependency is not in all ppds or all sections :-( my $odep = $x{OrderDependency}; my @onames = sort { $odep->{$a}->{ingroup} cmp $odep->{$a}->{ingroup} || $odep->{$a}->{sequence} <=> $odep->{$b}->{sequence} || $odep->{$a}->{value} <=> $odep->{$b}->{value} || $x{OpenUI}->{$a}->{sequence} <=> $x{OpenUI}->{$b}->{sequence} } keys %{$x{OpenUI}}; for my $oname (@onames) { my $label = $x{OpenUI}->{$oname}->{xlat} // $oname; my $type = $x{OpenUI}->{$oname}->{value} // "Unknown"; # one choice is no choice next if ($type eq "PickOne" && keys %{$x{$oname}} == 1); my $this = $x{$oname}; my $example = (keys %$this)[0]; my $sectionname = $x{OpenGroup}->{$this->{$example}->{ingroup}}->{xlat}; my $sectionlabel = $sectionname ? " Section: $sectionname\n":""; print "Option '$oname': $label\n$sectionlabel Type: $type\n Choices:\n"; for my $choice (sort { $this->{$a}->{sequence} <=> $this->{$b}->{sequence} } keys %$this) { my $choicelabel = $x{$oname}->{$choice}->{xlat}; print " o '$choice'".($choicelabel? ": $choicelabel":"")."\n"; } print " Default: ".$x{"Default$oname"}."\n Example: -Z $oname=$example\n\n"; } if (@a2ps) { close(STDOUT); close(P); }