chiark / gitweb /
option parsing etc
[xfonts-traditional] / utility
1 #!/usr/bin/perl -w
2 use strict;
3 use POSIX;
4 use IO::File;
5 use Getopt::Long;
6
7 our $package='xfonts-traditional';
8 our $sharedir="/usr/share/$package";
9 our @rulespath;
10 our $mode;
11 our %foundrymap;
12 our $verbose=0;
13 our $reportfh;
14
15 sub reportloaded {
16     return unless $verbose;
17     print $reportfh @_,"\n" or die $!;
18 }
19
20 sub loadrules ($) {
21     my ($key) = @_;
22     our %cache;
23     my $fc=$cache{$key};  
24     return $fc if $fc;
25     foreach my $path (@rulespath) {
26         my $script="$path/$key.rules";
27         $!=0; $@=''; my $f = do $script;
28         if (defined $f) {
29             reportloaded("rules: loaded ",$script);
30             $cache{$key}=$f;
31             return $f;
32         }
33         die "$! $? $script" unless $! == &ENOENT;
34     }
35     return $cache{$key}=undef;
36 }
37
38 sub processbdf ($$$) {
39     my ($inbdf,$outbdf,$what) = @_;
40     my $state='idle';
41     my ($foundry,$font);
42     my ($w,$h,$xo,$yo,$y,$bitmap,$glyph);
43     my $modified=0;
44     while (<$inbdf>) {
45         if ($state eq 'bitmap' && $y==$h) {
46             $glyph = uc $glyph;
47             $glyph =~ s/\;$//;
48             local ($_) = $glyph;
49             my $key= sprintf "%s,%d,%d,%d,%d", $foundry,$w,$h,$xo,$yo;
50             my $rules= loadrules($key);
51             return (0,'no rules') if !$rules;
52             $rules->();
53             $modified += ($_ ne $glyph);
54             print $outbdf $_,"\n" or die $!
55                 foreach split /\;/, $_; # /;
56             $state='idle';
57         }
58         if ($state eq 'bitmap') {
59             m/^([0-9a-fA-F]+)\s+$/ or die $y;
60             length($1) == (($w+7 >> 3) << 1) or die "$1 $w";
61             $glyph .= "$1;";
62             $y++;
63             next;
64         }
65         if ($state eq 'idle' && m/^FOUNDRY\s+/) {
66             die if defined $foundry;
67             return (0,'foundry syntax') unless m/^FOUNDRY\s+\"(\w+)\"\s+/;
68             $foundry = $foundrymap{lc $1};
69             return (0,'no foundry') unless defined $foundry;
70             $_ = "FOUNDRY \"$foundry\"\n";
71         }
72         if ($state eq 'idle' && m/^FONT\s+/) {
73             die if defined $font;
74             return 0 unless m/^(FONT\s+)\-(\w+)\-/;
75             $font = $foundrymap{lc $2};
76             return (0,'no foundry') unless defined $font;
77             $_ = "FONT -$font-$'";
78         }
79         if ($state eq 'idle' && m/^STARTCHAR\s/) {
80             die unless defined $foundry;
81             die unless defined $font;
82             return (0,'foundry != font') unless $foundry eq $font;
83             $state='startchar';
84             $w=undef;
85         }
86         if ($state eq 'startchar') {
87             if (m/^BBX\s+(\+?\d+)\s+(\+?\d+)\s+([-+]?\d+)\s+([-+]?\d+)\s+$/) {
88                 ($w,$h,$xo,$yo) = ($1,$2,$3,$4);
89             }
90             if (m/^BITMAP\s+$/) {
91                 die unless defined $w;
92                 $y=0;
93                 $glyph='';
94                 $state='bitmap';
95             }
96         }
97         print $outbdf $_ or die $!;
98     }
99     die $! if $inbdf->error;
100     die $! if $outbdf->error or !$outbdf->flush;
101     die unless $state eq 'idle';
102     if ($modified) {
103         printf $reportfh "%s: %d glyphs changed\n", $what, $modified
104             or die $!;
105     } else {
106         printf $reportfh "%s: unchanged - no rules matched\n", $what
107             or die $!;
108     }
109     return $modified;
110 }
111
112 our (@options)=(
113     'R|rules-include=s@' => \@rulespath,
114     'share-dir=s' => \$sharedir,
115     'verbose|v+' => \$verbose,
116     );
117
118 sub define_mode ($$) {
119     my ($optname,$f) = @_;
120     push @options, $optname, sub {
121         die "only one mode may be specified\n" if defined $mode;
122         $mode=$f;
123     };
124 }
125
126 sub loadfoundries () {
127     foreach my $path (@rulespath) {
128         my $p = "$path/foundries";
129         my $f = new IO::File $p;
130         if (!$f) {
131             die "$p $!" unless $!==&ENOENT;
132             print $reportfh "foundries: none in $p\n" or die $! if $verbose;
133             next;
134         }
135         while (<$f>) {
136             s/^\s*//; s/\s+$//;
137             next if m/^\#/;
138             m/^(\w+)\s+(\w+)$/ or die;
139             my $k = lc $1;
140             next if exists $foundrymap{$k};
141             $foundrymap{$k}=$2;
142         }
143         $f->error and die $!;
144         reportloaded('foundries: loaded ',$p);
145     }
146     die "no foundry maps\n" unless %foundrymap;
147 }
148
149 our $stdin = new IO::File '<&STDIN' or die $!;
150 our $stdout = new IO::File '>&STDOUT' or die $!;
151 our $stderr = new IO::File '>&STDERR' or die $!;
152 $reportfh = $stdout;
153
154 define_mode('bdf-filter', sub {
155     die "no arguments allowed with --bdf-filter\n" if @ARGV;
156     $reportfh = $stderr;
157     loadfoundries();
158     my $r = processbdf($stdin,$stdout,'stdin');
159     if ($r !~ m/^\d/) {
160         print STDERR "stdin not processed: $r\n";
161         exit 2;
162     }
163 });
164
165 Getopt::Long::Configure(qw(bundling));
166 GetOptions(@options) or exit 127;
167
168 push @rulespath, "$sharedir/rules";
169
170 die "need a mode\n" unless $mode;
171
172 $mode->();
173
174 #   70  zcat /usr/share/fonts/X11/misc/6x13.pcf.gz |pcf2bdf >in.bdf
175 #   71  ./utility <in.bdf >out.bdf
176 #   83  bdftopcf out.bdf >out.pcf
177 #   84  gzip out.pcf 
178 #   85  cp out.pcf.gz /usr/share/fonts/X11/misc/
179 # really mkfontdir /usr/share/fonts/X11/misc/
180 # xset fp rehash
181 # xfontsel