summaryrefslogtreecommitdiff
path: root/info/symbols/comprehensive/source/makerawtables
blob: 34cfc6f709389164c98d8c9ae39ace6ffdec9b23 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
#! /usr/bin/env perl

#############################################
# Create a massive table of every character #
# in every font used in the Comprehensive   #
# LaTeX Symbol List			    #
#					    #
# By Scott Pakin <scott+clsl@pakin.org>	    #
#############################################

use Getopt::Long;
use File::Basename;
use warnings;
use strict;

# Parse the command line.
my $paper = "letter";
my $usagestr = "Usage: $0 [--paper=<letter|a4>]\n";
GetOptions("p|paper=s" => \$paper) || die $usagestr;
my ($paperwidth, $paperheight);
if ($paper eq "letter") {
    $paperwidth = "8.5in";
    $paperheight = "11in";
}
elsif ($paper eq "a4") {
    $paperwidth = "210mm";
    $paperheight = "297mm";    
}
else {
    die $usagestr;
}

# Define a comparison function to use for sorting font names.
sub compare_names ($$)
{
    return lc($_[0]) cmp lc($_[1]) || $_[0] cmp $_[1];
}

# Define a subroutine that returns a list of valid font names to process.
sub find_valid_fonts ()
{
    # Build the CLSL under strace to acquire a list of .tfm files.
    my %unique_tfms;
    open(STRACE, "strace -e trace=open -s 32768 -f pdflatex -jobname symbols-letter-pdf '\\RequirePackage{snapshot}\\PassOptionsToClass{letterpaper}{article}\\input symbols' 2>&1|") || die "open: $!\n";
    while (my $oneline = <STRACE>) {
	print $oneline;
	next if $oneline !~ /open\(\"(.*?)\.tfm\",.*\)\s+=\s+(\S+)/;
	my ($tfm, $retcode) = (basename($1), $2);
	next if $retcode eq "-1";
	$unique_tfms{$tfm} = 1;
    }
    close STRACE || die;
    my @tfmlist = sort compare_names keys %unique_tfms;

    # Produce one table per font (overwriting as we go) to determine which
    # fonts are missing, then remove those from the TFM list.
    foreach my $tfm (@tfmlist) {
	print "\n*** TESTING $tfm ***\n";
	open(PDFTEX, "|pdftex testfont") || die "open: $!\n";
	print PDFTEX $tfm, "\n";
	print PDFTEX "\\table\n";
	print PDFTEX "\\bye\n";
	close PDFTEX || do {
	    print "*** DISCARDING $tfm ***\n";
	    delete $unique_tfms{$tfm};
	};
    }
    @tfmlist = sort compare_names keys %unique_tfms;

    # For fonts that come in multiple sizes, discard all but the closest to 10 pt.
    my %base2tfms;
    foreach my $tfm (@tfmlist) {
	if ($tfm =~ /^(\D+)\d+$/) {
	    push @{$base2tfms{$1}}, $tfm;
	}
	else {
	    push @{$base2tfms{$tfm}}, $tfm;
	}
    }
    while (my ($base, $tfmref) = each %base2tfms) {
	my @tfms = @$tfmref;
	if ($#tfms == 0) {
	    $base2tfms{$base} = $tfms[0];
	    next;
	}
	my @sizes = map {/(\d+)/; $1 >= 100 ? $1/1000 : $1} @tfms;
	my ($best_tfm, $least_badness) = (0, 2**30);
	foreach my $i (0 .. $#sizes) {
	    my $bad = ($sizes[$i] - 10)**2;
	    if ($bad < $least_badness) {
		$best_tfm = $tfms[$i];
		$least_badness = $bad;
	    }
	}
	print "*** RETAINING ONLY $best_tfm OUT OF [@tfms] ***\n";
	$base2tfms{$base} = $best_tfm;
    }
    @tfmlist = sort compare_names values %base2tfms;
    return @tfmlist;
}

# Use the font list from a prior run if available.  Otherwise, process
# symbols.tex to acquire a list of valid fonts.
my @tfmlist;
if (-e "rawtables.list") {
    open(LIST, "<", "rawtables.list") || die "open: $!\n";
    chomp(@tfmlist = <LIST>);
    close LIST;
}
else {
    # Slow path -- process symbols.tex using strace.
    @tfmlist = find_valid_fonts();

    # Dump the list of font names to disk to use for speeding up
    # subsequent runs.
    open(LIST, ">", "rawtables.list") || die "open: $!\n";
    print LIST join("\n", @tfmlist), "\n";
    close LIST;
}

# Determine the number of tables starting with each letter of the
# alphabet to use for creating a PDF bookmarks list.
my %lettertally;
foreach my $tfm (@tfmlist) {
    $lettertally{uc(substr $tfm, 0, 1)}++;
}

# Produce a series of font tables in a single PDF file.
open(PDFTEX, ">", "rawtables-$paper.tex") || die "open: $!\n";
printf PDFTEX "\% Specify %s paper.\n", $paper eq "a4" ? "A4" : "U.S. letter-sized";
print PDFTEX "\\pdfpagewidth=$paperwidth\n";
print PDFTEX "\\pdfpageheight=$paperheight\n";
print PDFTEX <<'TESTFONT';

% Define this document's metadata.
\pdfinfo {
  /Title (Raw Font Tables)
  /Author (Scott Pakin <scott+clsl@pakin.org>)
  /Subject (Tables of fonts used in the Comprehensive LaTeX Symbol List)
  /Keywords (font tables, symbols, glyphs, characters, TeX, LaTeX)
}

% \reserve@table@space, which was derived from needspace.sty, ensures
% that there is enough space remaining on the page for a complete font
% table.
\catcode`\@=11
\newdimen\dimen@
\newdimen\dimen@ii
\def\reserve@table@space{%
  \par \penalty-100\begingroup
  \dimen@=\ht\tablebox
  \dimen@ii\pagegoal \advance\dimen@ii-\pagetotal
  \ifdim \dimen@>\dimen@ii
    \ifdim \dimen@ii>\z@
      \vfil
    \fi
    \break
  \fi\endgroup
}

% \findfirstletter sets \firstletter to the first letter of its argument.
\let\prevfirstletter=?
\def\findfirstletter#1{\findfirstletter@i#1\null}
\def\findfirstletter@i#1#2\null{\uppercase{\gdef\firstletter{#1}}}

% \fonttable typesets a single font table given a count of fonts starting
% with the same letter and a font name.
\newbox\tablebox
\def\fonttable#1#2{%
  % Start a new page if we don't have enough space on the current one.
  \def\fontname{#2}%
  \setbox\tablebox=\vbox{\startfont\table}%
  \reserve@table@space
  % Start a new top-level bookmark for each letter of the alphabet.
  \findfirstletter{#2}%
  \ifx\firstletter\prevfirstletter
  \else
    \vfill\eject
    \pdfdest name {\firstletter-fonts} xyz
    \pdfoutline goto name {\firstletter-fonts} count -#1 {\firstletter}
    \centerline{\sectionfont\firstletter}\par
    \vskip1cm
    \let\prevfirstletter=\firstletter
  \fi
  % Output a font table.
  \pdfdest name {#2} xyz
  \pdfoutline goto name {#2} {#2}
  \startfont
  \table
  \vskip1cm plus 24pt minus 24pt
}

% Prepare fonts we'll need for the text.
\input plnfss
\input ot1cm.pfd
\font\titlefont=cmbcsc10 at 24pt
\font\symbolfont=cmsy10 at 12pt
\def\symchar#1{{\symbolfont\char#1}}
\font\manfnt=logo10 at 12pt
\font\sectionfont=cminch

% \LaTeX typesets the LaTeX logogram in either roman or italic.  The
% code was derived from the definition of \LaTeX in texnames.sty.
\def\LaTeX{%
  \ifdim\fontdimen1\font>0pt 
    \bgroup
      \itshape
      L\kern-.36em\raise.3ex\hbox{\setfontsize{10pt}\itshape A}\kern-.23em\TeX
    \egroup
  \else
    L\kern-.36em\raise.3ex\hbox{\setfontsize{10pt}\selectfont A}\kern-.16em\TeX
  \fi
}

% \MF typesets the Metafont logogram.
\def\MF{{\manfnt METAFONT}}

% \CLSL is a shortcut for "Comprehensive LaTeX Symbol List".
\def\CLSL{\textit{Comprehensive \LaTeX\ Symbol List}}

% Typeset some title text.
\pdfdest name {title} xyz
\pdfoutline goto name {title} {Title page}
\setfontsize{12pt}\usefont{OT1}{cmr}{m}{n}
{\titlefont\centerline{Raw Font Tables}\par}
\vskip10pt
{\setfontsize{14pt}\usefont{OT1}{cmr}{m}{n}%
 \centerline{Scott Pakin, \textit{scott+clsl@pakin.org}}\par}
\vskip10pt
\centerline{%
  \number\day \ 
  \ifcase\month
     \or January\or February\or March%
     \or April\or May\or June%
     \or July\or August\or September%
     \or October\or November\or December%
  \fi
  \ \number\year
}
\vskip1cm
%
This document presents, in alphabetical order, font tables for all of
the fonts that appear in the \CLSL.  It was mechanically produced
using a script that extracts the list of fonts used by the \CLSL\ and
feeds this list into Knuth's \texttt{testfont.tex}, which is included
in all \TeX\ distributions and can typeset font tables.  The purpose
of this document is to provide a companion mechanism for locating
symbols by organizing the myriad symbols available to \TeX\ and
\LaTeX\ by font family rather than by \LaTeX\ symbol name.  It may
also reveal some unnamed symbols---or symbols overlooked by the \CLSL.

On the other hand, not every symbol shown in the \CLSL\ appears in
this document.  Some symbols are defined by juxtaposing multiple other
symbols; some symbols are defined in terms of graphics primitives
instead of fonts.  The tables shown in this document are only those
that correspond to ``true'' fonts---glyphs drawn in \MF, PostScript,
or other such font formats and that have an associated \TeX\ font
metric (\texttt{.tfm}) file.

In each table, characters are numbered in both base~8 (octal) and
base~16 (hexadecimal).  A character's octal position is formed by
taking the first two octal digits from a table's left column and the
third octal digit from the top row.  A character's hexadecimal
position is formed by taking the first hexadecimal digit from a
table's right column and the second hexadecimal digit from either the
top or the bottom row, based on whether the character lies in the
upper or lower row associated with the first hexadecimal digit.  To
clarify this description with an example, the ``\symchar{"34}'' symbol
in the \texttt{cmsy10} table can be produced by either
\texttt{\string\char'064} (octal) or \texttt{\string\char"34}
(hexadecimal).  The ``\symchar{"3C}'' symbol that lies directly
beneath that in the table can be produced by either
\texttt{\string\char'074} (octal) or \texttt{\string\char"3C}
(hexadecimal).  The decimal equivalents of these are
\texttt{\string\char52} and \texttt{\string\char60}, and their
character equivalents are ``\texttt{4}'' and ``\texttt{<}'',
respectively.
%
\vfill\eject

% Use Knuth's testfont.tex to typeset a bunch of tables.
\let\noinit=!
\input testfont
TESTFONT
;#`
foreach my $tfm (@tfmlist) {
    print "*** PRODUCING A TABLE FOR $tfm ***\n";
    printf PDFTEX "\\fonttable{%d}{%s}\n", $lettertally{uc(substr $tfm, 0, 1)}, $tfm;
}
print PDFTEX "\\bye\n";
close PDFTEX || die;
print "*** SUCCESSFULLY CREATED rawtables-$paper.tex ***\n";