#!/usr/bin/perl =head1 NAME bdf2fbcon - Convert Glyph Bitmap Distribution Format fonts to Linux fbcon fonts =cut use strict; use warnings; use Getopt::Long; use constant { BDF_2_1_SECTION_NONE => 0, BDF_2_1_SECTION_PROPERTIES => 1, BDF_2_1_SECTION_CHAR => 2, }; my $VERSION; $VERSION = '0.1.0'; sub main { my %opts; my %convert_opts; my $input; my $output; $SIG{'__WARN__'} = \&warning; Getopt::Long::Configure("no_ignore_case", "bundling", "gnu_compat", "no_getopt_compat"); if (not GetOptions(\%opts, "o=s", "s=s", "h|help", "V|version", )) { usage(*STDERR); exit(4); } if (exists($opts{'h'})) { help(*STDOUT); exit(0); } if (exists($opts{'V'})) { version(*STDOUT); exit(0); } if (exists($opts{'s'})) { $convert_opts{'w'} = $convert_opts{'h'} = $opts{'s'}; $convert_opts{'w'} =~ s/x.*//; $convert_opts{'h'} =~ s/.*x//; } if ($#ARGV lt 0) { error(4, "No input files\n"); } if (exists($opts{'o'})) { if ($#ARGV gt 0) { error(4, "Cannot specify -o with multiple files\n"); } convert($ARGV[0], $opts{'o'}, %convert_opts); } else { for $input (@ARGV) { $output = $input; $output =~ s/\.bdf$/.c/; convert($input, $output, %convert_opts); } } } sub usage { my ($fh) = @_; printf($fh "Usage: %s [-o ] ...\n", $0); } sub help { my ($fh) = @_; usage($fh); print($fh "Options:\n"); print($fh " -o Place the output into \n"); print($fh " -s x Override the font size\n"); print($fh " -h, --help Display this information\n"); print($fh " -V, --version Display version information\n"); } sub version { my ($fh) = @_; printf($fh "bdf2fbcon %s\n", $VERSION); print($fh "Copyright (C) 2013, 2014 Patrick \"P. J.\" McDermott\n"); print($fh "License GPLv3+: GNU GPL version 3 or later " . ".\n"); print($fh "This is free software: you are free to change and " . "redistribute it.\n"); print($fh "There is NO WARRANTY, to the extent permitted by law.\n"); } sub warning { my ($fmt, @args) = @_; printf(STDERR "bdf2fbcon: Warning: " . $fmt . "\n", @args); } sub error { my ($status, $fmt, @args) = @_; printf(STDERR "bdf2fbcon: Error: " . $fmt . "\n", @args); exit($status); } sub convert { my ($input, $output, %opts) = @_; my $input_fh; my $output_fh; my $line; my $font; if ($input eq $output and $input ne "-") { warning("Input and output files are equal"); } if ($input eq "-") { $input_fh = *STDIN; } else { if (not open($input_fh, "<", $input)) { error(4, "%s: %s", $input, $!); } } if ($output eq "-") { $output_fh = *STDOUT; } else { if (not open($output_fh, ">", $output . "~")) { error(4, "%s: %s", $output . "~", $!); } } $font = init_font(%opts); $line = readline($input_fh); if ($line =~ m/^STARTFONT 2.[12]$/) { parse_bdf_2_1($input_fh, $font); } else { error(4, "Unsupported input format"); } write_fbcon($output_fh, $font); if ($input ne "-") { close($input_fh); } if ($output ne "-") { close($output_fh); if (not rename($output . "~", $output)) { error(4, "%s: %s", $output, $!); } } } sub init_font { my (%opts); my $font; my $i; $font = { 'comments' => [], 'idx' => undef, 'name' => undef, 'width' => undef, 'height' => undef, 'chars' => [], }; $font->{'width'} = $opts{'w'} if (exists($opts{'w'})); $font->{'height'} = $opts{'h'} if (exists($opts{'h'})); for ($i = 0; $i < 256; ++$i) { $font->{'chars'}[$i] = { 'name' => 'hello', 'encoding' => undef, 'bitmap' => [], }; } return $font; } sub parse_bdf_2_1 { my ($input_fh, $font) = @_; my $section; my $found_end; my $line; my $stmt; my $arg; my @argv; my $char; $section = BDF_2_1_SECTION_NONE; $found_end = 0; while ($line = readline($input_fh)) { chomp($line); ($stmt, $arg) = split(/[ \t]+/, $line, 2); $arg =~ s/^"(.*)"$/$1/ if ($arg); ($stmt, @argv) = split(/[ \t]+/, $line); if ($section == BDF_2_1_SECTION_NONE) { if ($stmt eq 'FONTBOUNDINGBOX') { unless ($font->{'width'}) { $font->{'width'} = $argv[0]; } unless ($font->{'height'}) { $font->{'height'} = $argv[1]; } } elsif ($stmt eq 'COMMENT') { push(@{$font->{'comments'}}, $arg); } elsif ($stmt eq 'STARTPROPERTIES') { $section = BDF_2_1_SECTION_PROPERTIES; } elsif ($stmt eq 'STARTCHAR') { $char = $argv[0]; $section = BDF_2_1_SECTION_CHAR; } elsif ($stmt eq 'ENDFONT') { $found_end = 1; last; } } elsif ($section == BDF_2_1_SECTION_PROPERTIES) { if ($stmt eq 'FONT_NAME') { $font->{'idx'} = uc($arg); $font->{'idx'} =~ s/[^A-Z0-9_]//g; $font->{'name'} = lc($arg); $font->{'name'} =~ s/[^a-z0-9_]/_/g; } elsif ($stmt eq 'ENDPROPERTIES') { $section = BDF_2_1_SECTION_NONE; } } elsif ($section == BDF_2_1_SECTION_CHAR) { if ($stmt eq 'ENCODING') { $font->{'chars'}[$argv[0]]->{'name'} = $char; } elsif ($stmt eq 'ENDCHAR') { $section = BDF_2_1_SECTION_NONE; } } } warning("Missing end of font") unless ($found_end); } sub write_fbcon { my ($output_fh, $font) = @_; my $i; my $char; for (@{$font->{'comments'}}) { printf($output_fh "/* %s */\n", $_); } printf($output_fh "/* Generated by bdf2fbcon */\n\n"); printf($output_fh "#include \n\n"); # XXX printf($output_fh "#define FONTDATAMAX %d\n\n", 0); printf($output_fh "static const unsigned char" . " fontdata_%s[FONTDATAMAX] = {\n", $font->{'name'}); for ($i = 0; $i < 256; ++$i) { $char = $font->{'chars'}[$i]; printf($output_fh "\n\t/* %3d 0x%02x '%s' */\n", $i, $i, $char->{'name'}); } printf($output_fh "\n};\n\n"); printf($output_fh "const struct font_desc font_%s = {\n", $font->{'name'}); printf($output_fh "\t.idx\t= %s_IDX,\n", $font->{'idx'}); printf($output_fh "\t.name\t= \"%s\",\n", $font->{'idx'}); printf($output_fh "\t.width\t= %d,\n", $font->{'width'}); printf($output_fh "\t.height\t= %d,\n", $font->{'height'}); printf($output_fh "\t.data\t= fontdata_%s,\n", $font->{'name'}); # XXX printf($output_fh "\t.pref\t= ???,\n"); printf($output_fh "};\n"); } main(); __END__ =head1 SYNOPSIS B [B<-o> I] [B<-s> IxI] I ... =head1 DESCRIPTION B converts Glyph Bitmap Distribution Format fonts to Linux fbcon fonts. =head1 OPTIONS =over 4 =item B<-o> I Place the output into I. =item B<-s> IxI Override the font size. =item B<-h>, B<--help> Display help information. =item B<-V>, B<--version> Display version information. =back =head1 COPYRIGHT Copyright (C) 2013, 2014 Patrick "P. J." McDermott This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 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, see . =cut