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