\d afm data:.() / Trim whitespace from beginning and end of string. trimf:{((" "=x)?0)_ x} trim:{trimf[|trimf[|x]]} / Remove illegal dictionary chars from name. clean:{[name]`$($name)_dv/" -"} hex:{16 _sv "0123456789ABCDEF"?/:x} / Parse one line. parse:{[line] / afm.parse line:trim line s:line?" " key: :[s~#line;line;s#line] value:(1+s)_ line value:trim value (`$key;value)} / Parse character metrics. Simple version (widths other than WX not implemented). parse_cm:{[line] / afm.parse_cm line:parse'-1_'trim'(-1_0,1+&";"=line)_ line if[#l:&`L=line[;0] line:(line _di l),,(`L;line[l;1])] line:. line if[`C _in !line line[`C]:0$line`C] if[`CH _in !line line[`C]:hex -1_1_ line`CH line:line _di `CH] if[`WX _in !line line[`WX]:0.0$line`WX] if[`N _in !line line[`N]:`$line`N] if[`B _in !line line[`B]:0.0$'(&" "=line`B)_ line[`B]:" ",line`B] if[`L _in !line line[`L]:`$''{trim'(&" "=x)_ x:" ",x}'line`L] line} parse_kpx:{[line] / afm.parse_kpx line:trim'(&" "=line)_ line:" ",line if["KPX"~line 0 kp:(`$line 1;`$line 2;0.0$line 3)] kp} read:{[filename] / afm.read / Read in file and kill blank lines. d:0:filename while[""~*d;d:1_ d] while[""~*|d;d:-1_ d] / Parse "FontMetrics" wrapper. kv:parse[*d] if[~`StartFontMetrics~kv 0 '"Bad font metrics file: no 'StartFontMetrics' line"] if[~`EndFontMetrics~parse[*|d][0] '"Bad font metrics file: no 'EndFontMetrics' line"] font:.,(`AFMVersion;0.0$kv 1) d:-1_1_ d / Parse basic font information. ln:0 while[~"Start"~5#$*kv:parse[d ln] key:kv 0 value:kv 1 if[~`Comment~key;font[key]:value] if[key _in`FontName`FullName`FamilyName`Weight`EncodingScheme`CharacterSet font[key]:`$value] if[key _in`MetricsSets`MappingScheme`EscChar`Characters font[key]:0$value] if[key _in`FontBBox`VVector font[key]:0.0$'(&" "=value)_ value:" ",value] if[key _in`ItalicAngle`UnderlinePosition`UnderlineThickness`CapHeight`XHeight`Ascender`Descender`StdHW`StdVW font[key]:0.0$value] if[key _in`IsFixedPitch`IsBaseFont`IsFixedV font[key]: :["true"~value;1;0]] ln+:1] fd:clean font`FontName data[fd]:font if[ln~#d;:_n] / Skip "Direction" section. while[`StartDirection~*parse[d ln] while[~`EndDirection~*parse[d ln] ln+:1] ln+:1] if[ln~#d;:_n] / Process "CharMetrics" section. if[`StartCharMetrics~*kv:parse[d ln] cmc:0$kv 1 ln+:1 data[fd;`CharMetrics]:() do[cmc data[fd;`CharMetrics],:parse_cm[d ln] ln+:1] if[~`EndCharMetrics~*parse[d ln] '"Bad font metrics file: no 'EndCharMetrics' line"] keys:?,/!:'data[fd;`CharMetrics] data[fd;`CharMetrics]:.+(keys;+data[fd;`CharMetrics;;keys]) ln+:1] if[ln~#d;:_n] / Process "KernData" section. if[`StartKernData~*kv:parse[d ln] ln+:1 / Skip "TrackKern" subsection. if[`StartTrackKern~*parse[d ln] while[~`EndTrackKern~*parse[d ln] ln+:1] ln+:1] / Process "KernPairs" section. Simple version (KPX only). if[`StartKernPairs~*kv:parse[d ln] ln+:1 kpc:0$kv 1 data[fd;`KernPairs]:() do[kpc data[fd;`KernPairs],:,parse_kpx[d ln] ln+:1] if[~`EndKernPairs~*parse[d ln] '"Bad font metrics file: no 'EndKernPairs' line"] kp:data[fd;`KernPairs;;0 1] kps: