1#	@(#)afmdit.awk	1.3 (Berkeley) 04/15/88
2# lib/ditroff.font/afmdit.awk
3#
4# Copyright (c) 1984, 1985 Adobe Systems Incorporated. All Rights Reserved.
5#
6# RCSID: $Header: afmdit.awk,v 2.1 85/11/24 12:25:05 shore Rel $
7#
8# This awk(1) program helps build ditroff font description
9# files (for input to makedev/devconfig).  It parses
10# Adobe's AFM PostScript font metrics files.
11#
12#
13# The awk program presented here is rather hairy, but documented
14# throughout.  It started out as a simple idea but got a little
15# out of hand, a redesign is in order, but this version works
16# just fine so far.
17#
18# It works on canonical AFM files, home brew ones are not guarenteed,
19# as there is little hope for error detection and recovery.
20#
21# Lots of the extra character definitions (2 letter codes) come from
22#	"Adventures with Typesetter-Independent Troff"
23#	by Mark Kahrs and Lee Moore, Department of Computer Science
24#	Technical Report TR 159, June 1985
25#	University of Rochester, Rochester NY  14627
26# I thank them for their efforts.
27#
28# PostScript is a trademark of Adobe Systems Incorporated.
29#
30# last edit: Fri Nov 15 10:44:34 1985
31#
32# RCSLOG:
33# $Log:	afmdit.awk,v $
34# Revision 2.1  85/11/24  12:25:05  shore
35# Product Release 2.0
36#
37#
38
39BEGIN {
40	MetricsVersion = 2.0	# afm format version to match
41	SCALE = 5.0		# font width scale factor to
42				# achieve proper dynamic range
43				# (ditroff widths are <= 256)
44	fudge = 10		# ascender/descender fudge factor
45				# a character is judged to be an
46				# ascender (descender) if its bounding
47				# box is within fudge of the published
48				# ascender (descender) numbers for this
49				# font
50
51	# file names for pieces. These are cat'ed together in a shell script.
52	header = "temp.header"	# comments and ligature list
53	spaces = "temp.spaces"	# space widths and "charset" header
54	trailer = "temp.trailer"# actual character data
55	aux = "temp.aux" 	# PS width aux file for psdit
56
57	isspecial = 0		# font is the FIRST special font (S)
58	isfixedpitch = 0	# font is a typewriter font
59	istext = 1		# font is a text font (not special)
60
61# ditmap is a mapping from non-ascii PostScript character names
62#	(plus a few special ones) to DITROFF \( special codes.
63#	Note that some chars have more than one code (separated by spaces).
64#	If we ever determine some extra mappings, or actually digitize
65#	some full ditroff fonts, this will have to change.
66#	Play with it if you like, but the results may be gruesome.
67
68	ditmap[".ditspace"] = "\\^ \\| \\&"
69	ditmap["AE"] = "AE"
70	ditmap["Alpha"] = "*A"
71	ditmap["Beta"] = "*B"
72	ditmap["Chi"] = "*X"
73	ditmap["Delta"] = "*D"
74	ditmap["Epsilon"] = "*E"
75	ditmap["Eta"] = "*Y"
76	ditmap["Gamma"] = "*G"
77	ditmap["Iota"] = "*I"
78	ditmap["Kappa"] = "*K"
79	ditmap["Lambda"] = "*L"
80	ditmap["Lslash"] = "PL"
81	ditmap["Mu"] = "*M"
82	ditmap["Nu"] = "*N"
83	ditmap["OE"] = "OE"
84	ditmap["Omega"] = "*W"
85	ditmap["Omicron"] = "*O"
86	ditmap["Oslash"] = "O/"
87	ditmap["Phi"] = "*F"
88	ditmap["Pi"] = "*P"
89	ditmap["Psi"] = "*Q"
90	ditmap["Rho"] = "*R"
91	ditmap["Sigma"] = "*S"
92	ditmap["Tau"] = "*T"
93	ditmap["Theta"] = "*H"
94	ditmap["Upsilon"] = "*U"
95	ditmap["Xi"] = "*C"
96	ditmap["Zeta"] = "*Z"
97	ditmap["acute"] = "aa \\'"
98	ditmap["ae"] = "ae"
99	ditmap["aleph"] = "al"
100	ditmap["alpha"] = "*a"
101	ditmap["angleleft"] = "l<"
102	ditmap["angleright"] = "r>"
103	ditmap["approxequal"] = "~="
104	ditmap["arrowboth"] = "<>"
105	ditmap["arrowdblboth"] = "io"
106	ditmap["arrowdblleft"] = "<: lh"	# left double arrow (& hand)
107	ditmap["arrowdblright"] = ":> im rh"	# right double arrow (& hand)
108	ditmap["arrowdown"] = "da"
109#	ditmap["arrowleft"] = "<-"	# see procs
110#	ditmap["arrowright"] = "->"	# see procs
111	ditmap["arrowup"] = "ua"
112	ditmap["asteriskmath"] = "**"
113	ditmap["bar"] = "or"
114	ditmap["beta"] = "*b"
115	ditmap["breve"] = "be"
116	ditmap["caron"] = "hc"
117	ditmap["carriagereturn"] = "cr"
118	ditmap["cedilla"] = "cd"
119	ditmap["cent"] = "ct"
120	ditmap["chi"] = "*x"
121	ditmap["circlemultiply"] = "ax"
122	ditmap["circleplus"] = "a+"
123	ditmap["circumflex"] = "^"	# see ascii
124	ditmap["copyrightserif"] = "co"
125	ditmap["dagger"] = "dg"
126	ditmap["daggerdbl"] = "dd"
127	ditmap["degree"] = "de"
128	ditmap["delta"] = "*d"
129	ditmap["diamond"] = "dm"
130	ditmap["dieresis"] = "um .."	# umlaut
131	ditmap["divide"] = "di"
132	ditmap["dotaccent"] = "dt"
133	ditmap["dotlessi"] = "ui"
134	ditmap["dotmath"] = "m."
135	ditmap["element"] = "mo cm"
136	ditmap["emdash"] = "em"
137	ditmap["emptyset"] = "es"
138	ditmap["endash"] = "en"
139	ditmap["epsilon"] = "*e"
140	ditmap["equal"] = "eq"	;	mathonly["eq"] = "equal"
141#	ditmap["equivalence"] = "=="	# see procs
142	ditmap["eta"] = "*y"
143	ditmap["exclamdown"] = "!! I!"
144	ditmap["existential"] = "te"
145	ditmap["ff"] = "ff"
146	ditmap["ffi"] = "Fi"
147	ditmap["ffl"] = "Fl"
148	ditmap["fi"] = "fi"
149	ditmap["fl"] = "fl"
150	ditmap["florin"] = "$D"
151	ditmap["gamma"] = "*g"
152	ditmap["germandbls"] = "ss"
153	ditmap["gradient"] = "gr"
154	ditmap["grave"] = "ga \\`"
155	ditmap["greaterequal"] = ">="
156	ditmap["guillemotleft"] = "d<"
157	ditmap["guillemotright"] = "d>"
158	ditmap["heart"] = "bs"		# bell system logo
159	ditmap["hyphen"] = "hy"
160	ditmap["infinity"] = "if"
161#	ditmap["integral"] = "is"	# see procs
162	ditmap["intersection"] = "ca"
163	ditmap["iota"] = "*i"
164	ditmap["kappa"] = "*k"
165	ditmap["lambda"] = "*l"
166	ditmap["lessequal"] = "<="
167	ditmap["logicaland"] = "an la"
168	ditmap["logicalnot"] = "no"
169	ditmap["logicalor"] = "lo"
170	ditmap["lslash"] = "Pl"
171	ditmap["macron"] = "mc ma"
172	ditmap["minus"] = "\\- mi"
173	ditmap["minute"] = "fm mt"
174	ditmap["mu"] = "*m"
175	ditmap["multiply"] = "mu"
176	ditmap["notelement"] = "!m"
177	ditmap["notequal"] = "!="
178	ditmap["notsubset"] = "!s"
179	ditmap["nu"] = "*n"
180	ditmap["oe"] = "oe"
181	ditmap["ogonek"] = "og"
182	ditmap["omega"] = "*w"
183	ditmap["omicron"] = "*o"
184	ditmap["oslash"] = "o/"
185	ditmap["paragraph"] = "pp"
186	ditmap["partialdiff"] = "pd"
187	ditmap["perpendicular"] = "bt"
188	ditmap["perthousand"] = "pm"
189	ditmap["phi"] = "*f"
190	ditmap["pi"] = "*p"
191	ditmap["plus"] = "pl"	;	mathonly["pl"] = "plus"
192	ditmap["plusminus"] = "+-"
193	ditmap["propersubset"] = "sb"
194	ditmap["propersuperset"] = "sp"
195	ditmap["proportional"] = "pt"
196	ditmap["psi"] = "*q"
197	ditmap["questiondown"] = "?? I?"
198	ditmap["quotedblleft"] = "lq"
199	ditmap["quotedblright"] = "rq"
200	ditmap["quotesingle"] = "n'"
201#	ditmap["radical"] = "sr"	# see procs
202	ditmap["reflexsubset"] = "ib"
203	ditmap["reflexsuperset"] = "ip"
204	ditmap["registerserif"] = "rg"
205	ditmap["rho"] = "*r"
206	ditmap["ring"] = "ri"
207	ditmap["second"] = "sd"
208	ditmap["section"] = "sc"
209	ditmap["sigma"] = "*s"
210	ditmap["sigma1"] = "ts"
211	ditmap["similar"] = "ap"
212	ditmap["slash"] = "sl"
213	ditmap["sterling"] = "ps po"
214	ditmap["tau"] = "*t"
215	ditmap["therefore"] = "tf"
216	ditmap["theta"] = "*h"
217	ditmap["tilde"] = "~"		# see ascii
218	ditmap["trademarkserif"] = "tm"
219	ditmap["underscore"] = "\\_"
220	ditmap["union"] = "cu"
221	ditmap["universal"] = "fa"
222	ditmap["upsilon"] = "*u"
223	ditmap["xi"] = "*c"
224	ditmap["yen"] = "yi yn $J"
225	ditmap["zeta"] = "*z"
226
227# hack font, chars have their troff names
228
229	ditmap["br"] = "br"	# box rule
230	ditmap["bu"] = "bu"	# bullet
231	ditmap["bv"] = "bv"	# bold vertical
232	ditmap["bx"] = "bx"	# box
233	ditmap["ci"] = "ci"	# circle
234	ditmap["lb"] = "lb"	# left bot curly
235	ditmap["lc"] = "lc"	# left ceil
236	ditmap["lf"] = "lf"	# left floor
237	ditmap["lk"] = "lk"	# left center curly
238	ditmap["lt"] = "lt"	# left top curly
239	ditmap["ob"] = "ob"	# outline bullet
240	ditmap["rb"] = "rb"	# right bot curly
241	ditmap["rc"] = "rc"	# right ceil
242	ditmap["rf"] = "rf"	# right floor
243	ditmap["rk"] = "rk"	# right center curly
244	ditmap["rn"] = "rn"	# root extender
245	ditmap["rt"] = "rt"	# rith top curly
246	ditmap["ru"] = "ru"	# rule
247	ditmap["sq"] = "sq"	# square
248	ditmap["ul"] = "ul"	# under rule
249	ditmap["vr"] = "vr"	# vertical rule
250
251
252
253# >>>>> IMPORTANT NOTE! <<<<<
254# if you edit these, make sure you supply char codes and widths
255# below (in proc[]) and make sure you define the proc in the
256# PostScript prolog
257
258	ditmap[".proctext"] = "14 12 34 18 38 58 78 13 23"
259	ditmap[".procspecial"] = "is sr -> <- == uc"
260
261	# character-code and width info for synthetic characters
262
263	cc = 129	# manufacture unique character codes
264	proc["14"] = cc++ " 0 833"	# 1/4
265	proc["12"] = cc++ " 0 833"	# 1/2
266	proc["34"] = cc++ " 0 833"	# 3/4
267	proc["18"] = cc++ " 0 833"	# 1/8
268	proc["38"] = cc++ " 0 833"	# 3/8
269	proc["58"] = cc++ " 0 833"	# 5/8
270	proc["78"] = cc++ " 0 833"	# 7/8
271	proc["13"] = cc++ " 0 833"	# 1/3
272	proc["23"] = cc++ " 0 833"	# 2/3
273	proc["uc"] = cc++ " 0 0"	# uc seal
274
275#	proc["mi"] = cc++ " 0 549"	# minus
276
277	proc["sr"] = "214 0 549"	# square root
278	proc["is"] = "242 3 274"	# integral
279	proc["->"] = "174 0 987"        # arrow right
280	proc["<-"] = "172 0 987"        # arrow left
281	proc["=="] = "186 0 549"        # equivalence
282
283# L. and l. are used for line drawing on systems without graphics
284
285# ascii is a mapping which contains the PostScript character names
286#	for the (printable) ascii characters.  The values are the ascii
287#	character codes (not used in this program).  We just test to
288#	see if a name is in the table.
289#	ditroff (unlike Adobe) thinks that the ascii ^ and ~ are the accents
290#	hence we must leave out asciicircum and asciitilde
291
292	ascii["space"] = 32
293	ascii["exclam"] = 33
294	ascii["quotedbl"] = 34
295	ascii["numbersign"] = 35
296	ascii["dollar"] = 36
297	ascii["percent"] = 37
298	ascii["ampersand"] = 38
299	ascii["quoteright"] = 39
300	ascii["parenleft"] = 40
301	ascii["parenright"] = 41
302	ascii["asterisk"] = 42
303	ascii["plus"] = 43
304	ascii["comma"] = 44
305	ascii["hyphen"] = 45
306	ascii["period"] = 46
307	ascii["slash"] = 47
308	ascii["zero"] = 48
309	ascii["one"] = 49
310	ascii["two"] = 50
311	ascii["three"] = 51
312	ascii["four"] = 52
313	ascii["five"] = 53
314	ascii["six"] = 54
315	ascii["seven"] = 55
316	ascii["eight"] = 56
317	ascii["nine"] = 57
318	ascii["colon"] = 58
319	ascii["semicolon"] = 59
320	ascii["less"] = 60
321	ascii["equal"] = 61
322	ascii["greater"] = 62
323	ascii["question"] = 63
324	ascii["at"] = 64
325	ascii["A"] = 65
326	ascii["B"] = 66
327	ascii["C"] = 67
328	ascii["D"] = 68
329	ascii["E"] = 69
330	ascii["F"] = 70
331	ascii["G"] = 71
332	ascii["H"] = 72
333	ascii["I"] = 73
334	ascii["J"] = 74
335	ascii["K"] = 75
336	ascii["L"] = 76
337	ascii["M"] = 77
338	ascii["N"] = 78
339	ascii["O"] = 79
340	ascii["P"] = 80
341	ascii["Q"] = 81
342	ascii["R"] = 82
343	ascii["S"] = 83
344	ascii["T"] = 84
345	ascii["U"] = 85
346	ascii["V"] = 86
347	ascii["W"] = 87
348	ascii["X"] = 88
349	ascii["Y"] = 89
350	ascii["Z"] = 90
351	ascii["bracketleft"] = 91
352	ascii["backslash"] = 92
353	ascii["bracketright"] = 93
354#	ascii["asciicircum"] = 94	# 195 see ditmap, should be ascii!
355	ascii["underscore"] = 95
356	ascii["quoteleft"] = 96
357	ascii["a"] = 97
358	ascii["b"] = 98
359	ascii["c"] = 99
360	ascii["d"] = 100
361	ascii["e"] = 101
362	ascii["f"] = 102
363	ascii["g"] = 103
364	ascii["h"] = 104
365	ascii["i"] = 105
366	ascii["j"] = 106
367	ascii["k"] = 107
368	ascii["l"] = 108
369	ascii["m"] = 109
370	ascii["n"] = 110
371	ascii["o"] = 111
372	ascii["p"] = 112
373	ascii["q"] = 113
374	ascii["r"] = 114
375	ascii["s"] = 115
376	ascii["t"] = 116
377	ascii["u"] = 117
378	ascii["v"] = 118
379	ascii["w"] = 119
380	ascii["x"] = 120
381	ascii["y"] = 121
382	ascii["z"] = 122
383	ascii["braceleft"] = 123
384	ascii["bar"] = 124
385	ascii["braceright"] = 125
386#	ascii["asciitilde"] = 126	# 196 see ditmap, should be ascii !
387	} # BEGIN
388
389# look at .map files to learn about "special" (sigh)
390
391FILENAME ~ /^S\.map$/ {
392	isspecial = 1
393	istext = 0
394	next
395	}
396
397FILENAME ~ /^SS\.map$/ {
398	isspecial = 0
399	istext = 0
400	next
401	}
402
403FILENAME ~ /.*\.map$/ {next}
404
405
406# Now define the actions on the fields in real AFM format
407#	Note that we generate 3 files which are cat'ed together
408#	outside this program.  This is to avoid scanning the
409#	afm file more than once.  Most of the header stuff is ignored.
410
411/^StartFontMetrics /	{if ($2 != MetricsVersion) {
412				print "ERROR! Metrics Version mismatch"
413				exit 2 # does this get passed out ?
414				}
415			next
416			}
417
418/^Comment Copyright/	{print "# " $0 > header
419			next
420			}
421
422/^Comment /	{next}
423
424/^FontName /	{fontname = $2
425		print "# PostScript " fontname " from " FILENAME > header
426		print "# PostScript is a trademark of Adobe Systems Incorporated" > header
427		next
428		}
429
430/^FullName /	{next}
431
432/^FamilyName /	{next}
433
434/^Weight /	{next}
435
436/^ItalicAngle /	{next}
437
438/^IsFixedPitch /{if ($2 == "true") {isfixedpitch = 1}
439		else {isfixedpitch = 0}
440		next
441		}
442
443/^UnderlinePosition /{next}
444
445/^UnderlineThickness /{next}
446
447/^Version /	{next}
448
449/^Notice /	{print "# " $0 >header
450		next
451		}
452
453/^FontBBox /	{next}
454
455/^CapHeight /	{capheight = $2
456		next
457		}
458
459/^XHeight /	{xheight = $2
460		next
461		}
462
463/^Descender /	{descender = $2
464		next
465		}
466
467/^Ascender /	{ascender = $2
468		next
469		}
470
471/^EncodingScheme /{next}
472
473/^StartCharMetrics/	{printf "ligatures " > header
474			if (capheight < ascender) {
475				ascender = capheight
476				}
477			next}
478
479/^C -1 ;/	{next}			# ignore unencoded chars
480
481# now the hard part: the pattern for encoded characters.
482# note the dependence on canonical form
483# a more detailed parse of split($0,,";") might be better
484
485# 1 2	   3 4  5      6 7 8  9 0 11     12     13     14     15   ???
486/^C [0-9]* ; WX [0-9]* ; N .* ; B [-0-9]* [-0-9]* [-0-9]* [-0-9]* ;/ {
487	charcode = $2
488	width = $5
489	charname = $8
490	bblly = $12
491	bbury = $14
492
493#	parse ligatures
494	n = split($0,line,";")
495	for (i = 5; i < n ; i++) {
496		if (line[i] ~ / L .* .* /) {
497			d = split(line[i],ligs," ")
498			printf "%s ", ligs[d] > header
499			}
500		}
501
502#	compute width
503	scaledwidth = int(0.5 + (width / SCALE))
504	if ((scaledwidth < 0) || (scaledwidth > 256)) {
505		printf "ERROR! Width out of range! (character %s)\n", charname
506#		exit 2
507		next
508		}
509
510#	handle space
511	if (charname == "space") {		# special char widths
512		spacewidth = scaledwidth
513		if (isfixedpitch == 0) {
514			em6 =  int (0.5 + (1000.0/6.0) / SCALE)
515			em12 = int (0.5 + (1000.0/12.0) / SCALE)
516		}
517		else {
518			em6 = spacewidth
519			em12 = spacewidth
520		}
521		printf "spacewidth %d\n", spacewidth > spaces
522		print "charset" > spaces
523		printf "\\|\t%d 0 000\t1/6 em space\n", em6 >trailer
524		printf "\\^\t%d 0 000\t1/12 em space\n", em12 > trailer
525		printf "\\&\t00 0 000\tno space\n" > trailer
526		next
527		}
528
529#	figure out ascender/descender flags (hack!?)
530	ad = 0
531	if (bblly - fudge <= descender) ad += 1
532	if (bbury + fudge >= ascender) ad += 2
533
534#	dump the description line
535	if (length(ascii[charname]) > 0) {
536		printf "%c\t%d %d 0%o\t%s\n", charcode, scaledwidth, ad, charcode, charname  > trailer
537		# look for ditmap synonyms
538		if (length(ditmap[charname]) > 0) {
539			n = split(ditmap[charname],others," ")
540			for (i = 1; i <= n; i++) {
541				oth = others[i];
542				if ((length(mathonly[oth]) > 0) && (isspecial != 1)) continue;
543				printf "%s\t\"\n", others[i]  > trailer
544				}
545			}
546		}
547	else if (length(ditmap[charname]) > 0) {
548		# not a printable ascii character
549		n = split(ditmap[charname],others," ")
550		printf "%s\t%d %d 0%o\t%s\n", others[1], scaledwidth, ad, charcode, charname  > trailer
551		for (i = 2; i <= n; i++) {
552			printf "%s\t\"\n", others[i]  > trailer
553			}
554		}
555
556# dump a line for PS specific actual width/hack table
557
558	printf "%d %d %d\n", charcode, width, specialflag > aux
559
560	}
561
562/^EndCharMetrics/{
563	printf "0\n" > header
564
565	# dump the "fudged" characters.
566	for (i in proc) {
567		p = proc[i]
568		split(p,vals," ")
569		scaledwidth = int(0.5 + (vals[3] / SCALE))
570		if (((istext == 1) && (index(ditmap[".proctext"],i) != 0)) || ((isspecial == 1) && (index(ditmap[".procspecial"],i) != 0))) {
571			printf "%s\t%d %d 0%o\tfudgedproc!\n", i, scaledwidth, vals[2], vals[1] > trailer
572
573			printf "%d %d %d\n", vals[1], vals[3], 1 > aux
574			}
575		}
576	next
577	}
578
579/^EndFontMetrics/{next}
580
581END	{}
582