#This file belongs to the TOIL package : Ten plik nale/zy do pakietu TOIL #This package is public domain : Pakiet stanowi dobro powszechne #For more info see `0TOILENG.LIC' : Wi/ecej informacji w ,,0TOILPOL.LIC'' #============================================================================ # MAIN TASK FILE: generates the MF program which will generate the TFM file # ========================================================================== BEGIN { B_CHAR_NAME=".boundarychar" # local constant (unimportant, in fact) fix_const(); get_tmp_config(TMP_CFG) # 0: READ AFM FILE: RS="(\012|\015|\012\015)" getline < CV["AFM"] if (!/^StartFontMetrics/) errmess(4, CV["AFM"], "is not an AFM file") mess("Converting", CV["AFM"], "to", CV["MF_MF"]) FS=" *;? *" # convenient FS for parsing AFM files while (getline < CV["AFM"] > 0) { if ($1=="UnderlineThickness") UnderlineThickness=$2 if ($1=="FontName") FontName=$2 if ($1=="XHeight") XHeight=$2 if ($1=="ItalicAngle") ItalicAngle=$2 if ($1 == "C") { AFM_C[++AFM_NUM]=round($2) AFM_W[AFM_NUM]=round($4) AFM_N[AFM_NUM]=$6 AFM_SET[$6]=AFM_NUM XL[AFM_NUM]=round($8) YL[AFM_NUM]=round($9) XH[AFM_NUM]=round($10) YH[AFM_NUM]=round($11) AFM_CN[AFM_C[AFM_NUM]]=AFM_N[AFM_NUM] if (AFM_C[AFM_NUM]>Cmax) Cmax=AFM_C[AFM_NUM] for (i=12; i<=NF; i+=3) if ($i=="L") AFM_L[$6,$(i+1)]=$(i+2) } if ($1 == "KPX") if (($2 in AFM_SET) && ($3 in AFM_SET)) # warning: a bit of trickery is comming: if ((is_digit($2)+is_digit($3))<=CV["USE_DIGIT_KPX"]) K[$2,$3]=round($4) } FS=" " # restore standard FS # 1: ``MATHEMATIZE'' FONT IF REQUIRED (USUALLY REQUIRED): if (CV["MATHEMATIZE"]) { # The innocent word ``mathematize'' means that # 1. All depths (e.g., accents) and heights (e.g., underscore) but # the depth of equal sign are set par force to non-negative values # according to the formula (x<0 ? 0 : x) # 2. Math axis is determined in the following way: # (a) if an equals sign exists, the math axis is calculated # on the basis of its bounding box, # (b) if an equals sign does not exist, the math axis is # assumed to be equal 1/4 of the design size of the font. # 3. If an equals sign exists, its height and depth are calculated from # the AFM bounding box; it is the only character that can have # a negative depth. # 4. The following characters are considered to be math operators: # plus, minus, multiply, divide, plusminus, periodcentered, # less, greater, greaterequal, approxequal, lessequal # All the listed characters are subjected to the following # uniformizing adjustments of their heights and depths: # (a) a plus sign is considered first; if an equal sign is present, # the height and depth of a plus sign are adjusted in such # a way that the resulting bounding box is the smallest one # having the following properties: it contains the AFM bounding # box, depth is non-negative, and, moreover, m+d=h-m, where # m is the height of the math axis, d -- resulting depth, # h -- resulting height; if an equal sign is not present, # plus sign receives merely a non-negative depth (see p. 1); # (b) if a plus sign does not exist, it is considered to have # zero height and depth; # (c) the remaining characters from the list receive height and # depth according to the following formula: h=max(h,h'), # d=min(d,d'), where h' and d' are the height and depth of # a plus sign, and h and d are, obviously, the height # and depth of a given character. # 5. Finally, two parameters are fixed MATH_RULE (as equal to # UnderlineThickness (or 2/5pt#, if UnderlineThickness<=0), # and MATH_AXIS, as equal to the value determined in p. 2. # These parameters are written to the TFM file as # fontdimen registers 8 and 22, respectively. # COMMENT: the process of ``mathematization'' may seem somewhat # arbitrary and, frankly speaking, it is. ``Though this # be madness, yet there is method in 't'': # * negative depths may manifest their presence only in # math mode, as, according to ``The TeXbook'': # The result of `\hbox' never has negative height # or negative depth [...] # * if accent characters have negative depths, they # behave OK in the text mode, but fall too low # when used as `\mathaccent' commands; # * almost all math operators in CM fonts have uniformized # height and depth basing on that of a plus sign; # an equals sign, however, has different settings; # * `\fontdimen22' of `\fam2' denotes the height of math axis, # moreover, at least 22 `\fontdimen' registers are # necessary for to make TeX accepting a font as # a math one; # * `\fontdimen8' of `\fam3' denotes the default (math) rule # thickness; if ("equal" in AFM_SET) { math_axis=(YH[AFM_SET["equal"]]+YL[AFM_SET["equal"]])/2 YL[AFM_SET["equal"]]=-YL[AFM_SET["equal"]] } MATH_AXIS=((math_axis+0)==0 ? "9/2u#" : "V" math_axis) MATH_RULE=(UnderlineThickness>0 ? "V" UnderlineThickness+0 : ".4pt#"); if ("plus" in AFM_SET) { plus_ht=YH[AFM_SET["plus"]] plus_dp=nneg(-YL[AFM_SET["plus"]]) plus_ht=max(plus_ht,math_axis+plus_dp) } math_op["minus"]=1; math_op["multiply"]=1; math_op["divide"]=1 math_op["plusminus"]=1; math_op["periodcentered"]=1 math_op["less"]=1; math_op["greater"]=1; math_op["greaterequal"]=1 math_op["approxequal"]=1; math_op["lessequal"]=1 for (m in math_op) if (m in AFM_SET) { YH[AFM_SET[m]]=max(YH[AFM_SET[m]],plus_ht) YL[AFM_SET[m]]=max(nneg(-YL[AFM_SET[m]]),plus_dp) } for (n in AFM_SET) if (n!="equal") { YH[AFM_SET[n]]=nneg(YH[AFM_SET[n]]) YL[AFM_SET[n]]=nneg(-YL[AFM_SET[n]]) } } else for (n in AFM_SET) YL[AFM_SET[n]]=-YL[AFM_SET[n]] # 2: WRITE PREAMBLE getline < CV["MF1"] # skip first line print "% This is a METAFONT file created by TOIL ver. " CV["VER_NO"] > CV["MF_MF"] while (getline < CV["MF1"] > 0) { gsub("TONEFILE", QQ CV["PSF_XNAME"] QQ) gsub("ENCNNAME", QQ CV["ENC_NAME"] QQ) gsub("ENCXNAME", QQ CV["ENC_XNAME"] QQ) gsub("TFMNAME", QQ CV["TFM"] QQ) gsub("TONENAME", QQ FontName QQ) gsub("DUMMYPPI", CV["PPI"]) if (CV["MATHEMATIZE"]) { gsub("MATHRULE", MATH_RULE) gsub("MATHAXIS", MATH_AXIS) } gsub("MESSAGES", (CV["QUIET"] ? "true" : "false")) print > CV["MF_MF"] } close(CV["MF1"]) # 3: WRITE ENCODING AND ADD (OPTIONALLY) A BOUNDARY CHAR enc_kind="AFM-based encoding" internal_enc=1 if ((CV["ENC_ACT"]=="") && (CV["ENC_GVN"]!="")) {mess("Encoding file", CV["ENC_GVN"], "not found (ignored)")} else if (CV["ENC_ACT"]!="") { getline < CV["ENC_ACT"] if (!/^[ \t]*EXTERNAL ENCODING FOR TOIL/) { mess(CV["ENC_ACT"], "is not an encoding file for TOIL") mess("AFM encoding will be used") } else { mess("Encoding taken from", CV["ENC_ACT"]) getline enc_kind < CV["ENC_ACT"]; gsub(/ *%.*$/,"",enc_kind) for (i in AFM_CN) delete AFM_CN[i]; Cmax=0 while (getline < CV["ENC_ACT"] > 0) if ((/^[^%]/) && ($2 in AFM_SET)) {AFM_CN[$1+0]=$2; if (($1+0)>Cmax) Cmax=$1+0} internal_enc=0 } close(CV["ENC_ACT"]) } if (B_CHAR>=0) if (B_CHAR in AFM_CN) mess("Slot " B_CHAR " occupied; boundary char specification ignored") else { AFM_C[++AFM_NUM]=B_CHAR AFM_W[AFM_NUM]=0 AFM_N[AFM_NUM]=B_CHAR_NAME AFM_SET[B_CHAR_NAME]=AFM_NUM XL[AFM_NUM]=0; YL[AFM_NUM]=0; XH[AFM_NUM]=0; YH[AFM_NUM]=0 AFM_CN[AFM_C[AFM_NUM]]=AFM_N[AFM_NUM] if (AFM_C[AFM_NUM]>Cmax) Cmax=AFM_C[AFM_NUM] for (every_char in AFM_SET) if (every_char!=B_CHAR_NAME) { K[B_CHAR_NAME,every_char]=-XL[AFM_SET[every_char]] K[every_char,B_CHAR_NAME]=-AFM_W[AFM_SET[every_char]]+XH[AFM_SET[every_char]] } } print "string enc_kind; enc_kind=" QQ enc_kind QQ ";" > CV["MF_MF"] print "internal_enc:=" (internal_enc ? "true" : "false") ";" > CV["MF_MF"] print "vardef Enc expr tit =" > CV["MF_MF"] first=1 for (i=0; i<=Cmax; ++i) if (i in AFM_CN) { print (first ? " if tit=" : " elseif tit=") QQ AFM_CN[i] QQ ":" i > CV["MF_MF"] first=0 } print " else:-1\n fi\nenddef;" > CV["MF_MF"] # 4: WRITE INTERAMBLE getline < CV["MF2"] # skip first line while (getline < CV["MF2"] > 0) { gsub("XHEIGHT","V" XHeight+0); if (ItalicAngle==0) {gsub("SLANT","0")} else gsub("SLANT","-sind(" ItalicAngle ")/cosd(" ItalicAngle ")") print > CV["MF_MF"] } close(CV["MF2"]) # 5: WRITE DUMMY CHAR PROGRAMS for (i=1; i<=AFM_NUM; ++i) { print "char_title", QQ AFM_N[i] QQ ";" > CV["MF_MF"] print "beginchar(curr_enc,H" AFM_W[i] ",V" YH[i] ",V" (YL[i]) ");" > CV["MF_MF"] print "IC(H" XH[i] ",V" YH[i] "); endchar;" > CV["MF_MF"] print "% ---" > CV["MF_MF"] } # 6: CLEAN UP LIGATURES ALREADY READ IN AND READ OPTIONAL LIGATURES for (i in AFM_L) { split(i,u,SUBSEP) # by definition, (u[1] in AFM_SET) == true ## if ((!(u[2] in AFM_SET)) || (!(AFM_L[i] in AFM_SET))) delete AFM_L[i] if ((!(u[2] in AFM_SET)) || (!(AFM_L[i] in AFM_SET))) AFM_L[i]="" } if ((CV["LIG_ACT"]=="") && (CV["LIG_GVN"]!="")) { mess("Ligature file", CV["LIG_GVN"], "not found (ignored)") } else if (CV["LIG_ACT"]!="") { getline < CV["LIG_ACT"] if (!/^[ \t]*OPTIONAL LIGATURES FOR TOIL/) { mess(CV["LIG_ACT"], "is not a ligature file for TOIL") mess("Only AFM ligatures will be used") } else { mess("Ligatures taken from", CV["LIG_ACT"]) while (getline < CV["LIG_ACT"] > 0) if ((/^[^%]/) && ($1 in AFM_SET) && ($2 in AFM_SET) && ($3 in AFM_SET)) { if (($1,$2) in AFM_L) if (AFM_L[$1,$2]!=$3) {# inform about collision mess(" afm ligature " $1 " " $2 " " AFM_L[$1,$2]) mess(" new ligature " $1 " " $2 " " $3) } AFM_L[$1,$2]=$3 } } close(CV["LIG_ACT"]) } # 7: WRITE LIGTABLE # 6a: write ligatures and kerns ## for (i in AFM_L) { for (i in AFM_L) if (AFM_L[i]!="") { split(i,u,SUBSEP) print "LK(" QQ u[1] QQ ")" > CV["MF_MF"] print " LP(" QQ u[2] QQ "," QQ AFM_L[i] QQ ")" > CV["MF_MF"] ## delete AFM_L[i] AFM_L[i]="" ## for (j in AFM_L) { for (j in AFM_L) if (AFM_L[j]!="") { split(j,v,SUBSEP) if (v[1]==u[1]) { print " LP(" QQ v[2] QQ "," QQ AFM_L[j] QQ ")" > CV["MF_MF"] ## delete AFM_L[j] AFM_L[j]="" } } ## for (j in K) { for (j in K) if (K[j]!="") { split(j,v,SUBSEP) if (v[1]==u[1]) { print " KP(" QQ v[2] QQ ",H" K[j] ")" > CV["MF_MF"] ## delete K[j] K[j]="" } } print "KL;" > CV["MF_MF"] } # 6b: write remaining kerns ## for (i in K) { for (i in K) if (K[i]!="") { split(i,u,SUBSEP) print "LK(" QQ u[1] QQ ")" > CV["MF_MF"] print " KP(" QQ u[2] QQ ",H" K[i] ")" > CV["MF_MF"] ## delete K[i] K[i]="" for (j in K) if (K[j]!="") { split(j,v,SUBSEP) if (v[1]==u[1]) { print " KP(" QQ v[2] QQ ",H" K[j] ")" > CV["MF_MF"] ## delete K[j] K[j]="" } } print "KL;" > CV["MF_MF"] } # 8: WRITE POSTAMBLE getline < CV["MF3"] # skip first line while (getline < CV["MF3"] > 0) print > CV["MF_MF"] close(CV["MF3"]) # 9: SAY BYE if ((!CV["QUIET"]) && (LOG!="")) print "Transcript written on " LOG > "CON" } # ========================================================================== function max(x,y) {return (x>y ? x : y)} function abs(x) {return (x>0 ? x : -x)} function nneg(x) {return max(x,0)} function round(x) {return (x>0 ? int(x+.5) : -int(-x+.5))} function is_digit(n) {# let's be explicit here; it suffices that it is used # in a tricky way... return (n~/^(zero|one|two|three|four|five|six|seven|eight|nine)$/?1:0) } function errmess(e,s1,s2,s3) {# at most three parts may occur mess("TOIL ERROR:",s1, s2, s3); exit(e) } function mess(s1,s2,s3,s4, s) {# at most four parts may occur s=s1; if (s2!="") s=s " " s2; if (s3!="") s=s " " s3; if (s4!="") s=s " " s4 if (length(s)<=max_line) { if (!CV["QUIET"]) print s > "CON"; if (LOG!="") print s > LOG } else { if ((!CV["QUIET"]) && (s1!="")) print s1 > "CON" if ((LOG!="") && (s1!="")) print s1 > LOG if ((!CV["QUIET"]) && (s2!="")) print s2 > "CON" if ((LOG!="") && (s2!="")) print s2 > LOG if ((!CV["QUIET"]) && (s3!="")) print s3 > "CON" if ((LOG!="") && (s3!="")) print s3 > LOG if ((!CV["QUIET"]) && (s4!="")) print s4 > "CON" if ((LOG!="") && (s4!="")) print s4 > LOG } } function get_tmp_cfg_item(item_name, item) { CV[$1]=$0; gsub("^" $1 " +", "", CV[$1]); } function get_tmp_config (TMP_CFG, v) { while (getline < TMP_CFG > 0) get_tmp_cfg_item() # for (v in CV) printf("%20s %s\n", v, CV[v]) TMP_TMP=CV["TMP_TMP"] TMP_ENC=CV["TMP_ENC"] TMP_MAP=CV["TMP_MAP"] B_CHAR=CV["B_CHAR"]+0 } function fix_const() { # GENERAL CONSTANTS (used also in toila.awk and toilc.awk) QQ="\"" max_line=79 # screen limit max_sys_line=127 # MSDOS limit TMP_CFG="~t~m~p~.cfg" }