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