#!/usr/bin/perl # Copyright © 2011 Anton Zinoviev # 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 2 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. # If you have not received a copy of the GNU General Public License # along with this program, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA use warnings 'all'; use strict; sub debug { if (1) { print STDERR "@_"; } } my @forbidden = (0) x 32; $forbidden[0x00] = 1; # NUL $forbidden[0x07] = 1; # BEL $forbidden[0x08] = 1; # BS $forbidden[0x09] = 1; # HT $forbidden[0x0a] = 1; # LF (NL) $forbidden[0x0b] = 1; # VT $forbidden[0x0c] = 1; # FF $forbidden[0x0d] = 1; # CR $forbidden[0x1b] = 1; # ESC # Maps the names used in freebsd.set to the terminfo symbol and code. # The symbols are termcap/terminfo standard and may not be changed. # Changes in the codes will lead in incompatibility with the previous # versions the terminal description but not too drastic so perhaps # such changes are acceptable. my %acsc = ( 'UK pound sign' => [ '}', 0 ], 'arrow pointing down' => [ '.', 0x01 ], 'arrow pointing left' => [ ',', 0x02 ], 'arrow pointing right' => [ '+', 0x03 ], 'arrow pointing up' => [ '-', 0x04 ], 'board of squares' => [ 'h', 0x05 ], 'bullet' => [ '~', 0x06 ], 'checker board (stipple)' => [ 'a', 0x0e ], 'degree symbol' => [ 'f', 0x0f ], 'diamond' => [ '`', 0x10 ], 'greater-than-or-equal-to' => [ 'z', 0 ], 'greek pi' => [ '{', 0 ], 'horizontal line' => [ 'q', 0x11 ], 'lantern symbol' => [ 'i', 0 ], 'large plus or crossover' => [ 'n', 0x12 ], 'less-than-or-equal-to' => [ 'y', 0 ], 'lower left corner' => [ 'm', 0x13 ], 'lower right corner' => [ 'j', 0x14 ], 'not-equal' => [ '|', 0 ], 'plus/minus' => [ 'g', 0 ], 'scan line 1' => [ 'o', 0 ], 'scan line 3' => [ 'p', 0 ], 'scan line 7' => [ 'r', 0 ], 'scan line 9' => [ 's', 0 ], 'solid square block' => [ '0', 0x15 ], 'tee pointing down' => [ 'w', 0x16 ], 'tee pointing left' => [ 'u', 0x17 ], 'tee pointing right' => [ 't', 0x18 ], 'tee pointing up' => [ 'v', 0x19 ], 'upper left corner' => [ 'l', 0x1a ], 'upper right corner' => [ 'k', 0x1c ], 'vertical line' => [ 'x', 0x1d ] ); for my $name (keys %acsc) { my $code = $acsc{$name}[1]; die if ($code != 0 && $forbidden[$code]); } my ($file1, $file2, $file3, $task); sub mono { my $a = $_[0]; $a =~ s/[|]/-m|/g; $a =~ s/-line /-line monochrome /; return $a; } sub lines { my $a = $_[1]; $a =~ s/25/$_[0]/g; return $a; } sub print_term { my $ac = ""; for my $name (sort keys %acsc) { if ($acsc{$name}[1]) { $ac = $ac . sprintf("%s\\%03o", $acsc{$name}[0], $acsc{$name}[1]); } } my $name1 = 'cons25cs|cons25cs-bs|FreeBSD 25-line console with console-setup (Backspace is BS)'; my $name2 = 'cons25cs-del|cons25cs-debian|FreeBSD 25-line console with console-setup (Backspace is DEL)'; my $name1m = mono($name1); my $name2m = mono($name2); if ($task eq 'termcap') { print <= 0) { if ($ARGV[0] eq "--help" || $ARGV[0] eq "-h") { print STDERR < list of unicodes ACM 8-bit encoding -> Unicode EOT exit 0; } elsif ($ARGV[0] eq "--binaryscm") { $task='binaryscm'; } elsif ($ARGV[0] eq "--textscm") { $task='textscm'; } elsif ($ARGV[0] eq "--termcap") { $task='termcap'; print_term(); exit 0; } elsif ($ARGV[0] eq "--terminfo") { $task='terminfo'; print_term(); exit 0; } else { if (! defined $file1) { $file1=$ARGV[0]; } elsif (! defined $file2) { $file2=$ARGV[0]; } elsif (! defined $file3) { $file3=$ARGV[0]; } else { die "$0: Unknown argument $ARGV[0]\n"; } } shift @ARGV; } sub output { my $a = $_[0]; my $b = $_[1]; if ($task eq 'binaryscm') { printf "%c", $b; } elsif ($task eq 'textscm') { printf "0x%02x 0x%02x\n", $a, $b; } } sub printable { my $u = $_[0]; return (($u >= 0x20 && $u <= 0x7e) || $u >= 0xa0); } my %acs2uni; my %sfm; my @acm; open (ACS, $file1) or die "$0: $file1: $!\n"; while () { chomp; next unless (/^\s*[^#\s]/); unless (/^\s*U\+([0-9a-fA-F]{4})\s+# (.+?)\s*$/) { die "<$_>"; } if (/^\s*U\+([0-9a-fA-F]{4})\s+# (.+?)\s*$/) { my $uni = $1; my $name = $2; if (! defined $acsc{$name}) { die "$0: unknown symbol $name in $file1\n"; } $acs2uni{$name} = $uni; } else { die "$0: Syntax error in ACS file: $_\n"; } } close ACS; if ($file2 =~ /gz$/) { open (SFM, '-|:utf8', "zcat $file2") or die "$0: $file2: $!\n"; } else { open (SFM, '<:utf8', $file2) or die "$0: $file2: $!\n"; } while () { s/\#.*//; chomp; next unless (/[^\s]/); if (s/^\s*0x([0-9a-fA-F]{1,2})\s+//) { my $c = hex ($1); while (s/^U\+([0-9a-fA-F]{4})\s*//) { $sfm{hex ($1)} = $c; } die "$0: Garbage in SFM file: $_\n" unless (/^\s*$/); } else { die "$0: Syntax error in SFM file: $_\n"; } } close SFM; for my $c (32..126) { if (defined $sfm{$c}) { $acm[$c] = $sfm{$c}; } } if ($file3 =~ /gz$/) { open (ACM, '-|:utf8', "zcat $file3") or die "$0: $file3: $!\n"; } else { open (ACM, '<:utf8', $file3) or die "$0: $file3: $!\n"; } while () { s/\#.*//; chomp; next unless (/[^\s]/); if (/^\s*0x([0-9a-fA-F]{1,2})\s+\'([^\']+)\'\s*$/) { my $uni = ord ($2); my $c = hex ($1); if (printable($uni) && defined $sfm{$uni}) { $acm[$c] = $sfm{$uni}; } } else { die "$0: Syntax error in ACM file: $_\n"; } } close ACM; my @acm2acsname; for my $name (sort keys %acsc) { my $a = $acsc{$name}[1]; next if ($a == 0); my $uni = hex($acs2uni{$name}); next unless (defined $sfm{$uni}); if (defined $acm[$a] && $acm[$a] != $sfm{$uni}) { die "$0: Contradicting definition for $name and $acm2acsname[$a], both competing for position $a in the font.\n" } else { $acm[$a] = $sfm{$uni}; $acm2acsname[$a] = $name; } } my $fallback = 0x10; # diamond output 0, 0; for my $i (1..255) { if ($acm[$i]) { output $i, $acm[$i]; } else { output $i, $fallback; } }