program T1tidy; uses Dos, pathunit, strtype, afm, data; function makeint (s: string): integer; var i, c: integer; begin val (s, i, c); makeint := i end; function hex (c: char): integer; begin if c < '0' then hex := 0 else if c <= '9' then hex := ord (c) - ord ('0') else if upcase (c) < 'A' then hex := 0 else if upcase (c) <= 'F' then hex := ord (upcase (c)) - ord ('A') + 10 else hex := 0 end; function intstr (i: longint): string; var s: string; begin str (i, s); intstr := s end; function basename (fn: string): string; begin if pos ('.', fn) > 0 then basename := copy (fn, 1, pos ('.', fn) - 1) else basename := fn end; function isdir (fn: string): Boolean; var f: file; a: word; begin assign (f, fn); GetFAttr (f, a); isdir := (a and $10) <> 0 end; (* main procedure: *) procedure tidy (var infile, out: text); const maxintermediatelines = 40; var line, Subrsline, CharStringsline: strec; intermediatelines: array [1..maxintermediatelines] of string; linesafterOtherSubrs, linesafterSubrs: integer; blanklines: integer; i: integer; (***************************************************************************) function eofile: Boolean; begin eofile := eof (infile) end; procedure readline; var s: string; begin readln (infile, s); line.ini (s) end; function nexttoken: string; var r: string; begin r := line.nexttoken; while r = '' do begin readline; r := line.nexttoken end; nexttoken := r end; procedure readSubr; var s: string; index: integer; begin Subrscount := Subrscount + 1; new (Subrs [Subrscount], ini); with Subrs [Subrscount] ^ do begin index := makeint (nexttoken); (* writeln ('% reading Subr ', index); *) setindex (index); if nexttoken <> '{' then writeln ('% missing { in Subr'); s := nexttoken; while s <> '}' (* and ... Fehlerabfang! *) do begin if s = '' then writeln ('% empty line detected in Subr'); appendtoken (s); s := nexttoken; end; if s <> '}' then writeln ('% missing } in Subr'); s := nexttoken; if s = 'noaccess' then s := s + ' ' + nexttoken; setdef (s); cleanup end end; procedure readCharString; var s: string; begin CharStringscount := CharStringscount + 1; new (CharStrings [CharStringscount], ini); with CharStrings [CharStringscount] ^ do begin s := line.lasttoken; if ttfix then if (s [2] = 'G') and (length (s) = 4) then begin i := hex (s [3]) * 16 + hex (s [4]); if WinANSI [i] <> '/.notdef' then s := WinANSI [i] end; setname (s); if nexttoken <> '{' then writeln ('% missing { in CharString'); s := nexttoken; while s <> '}' (* and ... Fehlerabfang! *) do begin appendtoken (s); s := nexttoken; end; if s <> '}' then writeln ('% missing } in CharString'); s := nexttoken; if s = 'noaccess' then s := s + ' ' + nexttoken; if clearifempty then begin dispose (CharStrings [CharStringscount]); CharStringscount := CharStringscount - 1 end else begin setdef (s); cleanup; if not generate and split then splitpath end end end; procedure fixchars; procedure halfchar (oldname, newname: string); var CSold, CSnew: CharStrpointer; begin CSold := getCharString (oldname); CSnew := getCharString (newname); if (CSnew = nil) and (CSold <> nil) then begin new (CSnew, ini); CSold^.copyhalf (CSnew^, newname); CharStringscount := CharStringscount + 1; CharStrings [CharStringscount] := CSnew; end end; procedure downchar (oldname, newname: string); var CSold, CSnew: CharStrpointer; begin CSold := getCharString (oldname); CSnew := getCharString (newname); if (CSnew = nil) and (CSold <> nil) then begin new (CSnew, ini); CSold^.downpath (CSnew^, newname); CharStringscount := CharStringscount + 1; CharStrings [CharStringscount] := CSnew; end end; procedure copychar (oldname, newname: string); var CSold, CSnew: CharStrpointer; begin CSold := getCharString (oldname); CSnew := getCharString (newname); if (CSnew = nil) and (CSold <> nil) then begin new (CSnew, ini); CSold^.copypath (CSnew^, newname); CharStringscount := CharStringscount + 1; CharStrings [CharStringscount] := CSnew; end end; var CSbullet, CSperiodcentered: CharStrpointer; begin if verbose then writeln ('% generating missing characters'); if corelfix then begin CSbullet := getCharString ('/bullet'); CSperiodcentered := getCharString ('/periodcentered'); if (CSbullet <> nil) and (CSperiodcentered <> nil) then swappaths (CSbullet^, CSperiodcentered^); end; halfchar ('/quotedbl', '/quotesingle'); downchar ('/quotedblright', '/quotedblbase'); halfchar ('/quotedblbase', '/quotesinglbase'); halfchar ('/quotedblleft', '/quoteleft'); halfchar ('/quotedblright', '/quoteright'); downchar ('/quoteright', '/quotesinglbase'); halfchar ('/guillemotleft', '/guilsinglleft'); halfchar ('/guillemotright', '/guilsinglright'); copychar ('/less', '/guilsinglleft'); copychar ('/greater', '/guilsinglright'); if getCharString ('/endash') <> nil then copychar ('/endash', '/minus') else copychar ('/hyphen', '/minus'); copychar ('/slash', '/fraction'); copychar ('/bar', '/brokenbar'); copychar ('/asciitilde', '/tilde'); copychar ('/asciicircum', '/circumflex'); copychar ('/degree', '/ring'); if afmopen or ccopen then begin if verbose then writeln ('% generating composed characters'); composeCCs; end end; var uidfile: text; UniqueID, OtherSubrsfilepos: longint; OtherSubrs: text; savedOtherSubrs: Boolean; s: string; OtherSubrslevel: integer; OtherSubrsup, OtherSubrsdown: string; begin (* tidy *) Subrscount := 0; linesafterOtherSubrs := 0; savedOtherSubrs := false; linesafterSubrs := 0; CharStringscount := 0; UniqueID := 0; readline; (* i := line.posof ('FontType1-1.0'); (* if i > 0 then line.replace (i, i + 12, 'PS-AdobeFont-1.0'); *) blanklines := 0; while not eofile and not line.findtoken ('/Subrs') and not line.findtoken ('/OtherSubrs') and not line.findtoken ('/CharStrings') do begin if line.str <> '' then if line.firsttoken = '' then blanklines := blanklines + 1 else begin if line.hasprefix ('/FontName') then writeln ('% FontName: ', line.nthtoken (2)); if corelfix then begin (* The following modification, if desired at all, would have to be accompanied with metrics adjustment in the .afm file *) (* if line.hasprefix ('/FontMatrix') then begin if line.findtoken ('0.001000') then line.replacelasttoken ('0.000950'); if line.findtoken ('0.001000') then line.replacelasttoken ('0.000950'); end; *) if line.hasprefix ('/UniqueID') then if line.findtoken ('4221071') then begin if UniqueID = 0 then begin assign (uidfile, 'UniqueID.int'); (*$I-*) reset (uidfile) (*$I+*); if IOresult = 0 then read (uidfile, UniqueID) else UniqueID := 4221071; UniqueID := UniqueID + 1; rewrite (uidfile); write (uidfile, UniqueID); close (uidfile); end; line.replacelasttoken (intstr (UniqueID)); end end; if stdenc then begin if line.findtoken ('/Encoding') then begin while not line.findtoken ('def') do begin stdenc := false; readline; end; line.ini ('/Encoding StandardEncoding def'); if verbose and not stdenc then writeln ('% replacing encoding vector with StandardEncoding') end end; writeln (out, line.str); end; readline; end; if blanklines > 0 then begin writeln ('% ', blanklines, ' blank lines removed'); end; if line.findtoken ('/OtherSubrs') then begin (* Borland unwisely prohibited filepos / seek on text files, so we must save the OtherSubrs part in an intermediate file to paste it in again if needed. *) if getenv ('TEMP') <> '' then assign (OtherSubrs, getenv ('TEMP') + '\other.sub') else assign (OtherSubrs, 'other.sub'); rewrite (OtherSubrs); OtherSubrslevel := 1; OtherSubrsup := ''; repeat s := line.nexttoken; if s = '' then begin writeln (OtherSubrs, line.str); readline; end else if OtherSubrsup = '' then begin OtherSubrsup := s; if s = '[' then OtherSubrsdown := ']' else OtherSubrsdown := '}'; end else if s = OtherSubrsup then OtherSubrslevel := OtherSubrslevel + 1 else if s = OtherSubrsdown then OtherSubrslevel := OtherSubrslevel - 1; until OtherSubrslevel = 0; writeln (OtherSubrs, line.str); reset (OtherSubrs); savedOtherSubrs := true; readline; while not eofile and not line.findtoken ('/Subrs') and not line.findtoken ('/CharStrings') do begin if not line.empty then begin linesafterOtherSubrs := linesafterOtherSubrs + 1; intermediatelines [linesafterOtherSubrs] := line.str; end; readline end; end; if line.findtoken ('/Subrs') then begin if verbose then writeln ('% reading Subrs'); Subrsline := line; readline; while nexttoken = 'dup' do readSubr; end else writeln ('% /Subrs not found'); linesafterSubrs := linesafterOtherSubrs; while not eofile and not line.findtoken ('/CharStrings') do begin if not line.empty then begin linesafterSubrs := linesafterSubrs + 1; intermediatelines [linesafterSubrs] := line.str; end; readline end; if line.findtoken ('/CharStrings') then begin if verbose then writeln ('% reading CharStrings'); CharStringsline := line; readline; while pos ('/', nexttoken) = 1 do begin readCharString; (* readline; *) end; end else writeln ('% /CharStrings not found'); i := 1; while noOtherSubrs and (i <= CharStringscount) do begin noOtherSubrs := not CharStrings [i]^.usesothersubrs; i := i + 1 end; (* Borland unwisely prohibited filepos / seek on text files if noOtherSubrs then seek (out, OtherSubrsfilepos); *) if savedOtherSubrs then begin if noOtherSubrs then writeln ('% unused /OtherSubrs removed') else while not eof (OtherSubrs) do begin readln (OtherSubrs, s); writeln (out, s) end; close (OtherSubrs); erase (OtherSubrs); end; for i := 1 to linesafterOtherSubrs do writeln (out, intermediatelines [i]); if Subrscount > 0 then begin (* re-structure Subrs and CharStrings: *) (* if verbose then write ('% cleaning junk operations - '); *) (* for i := 1 to Subrscount do Subrs [i]^.cleanup; *) (* for i := 1 to CharStringscount do CharStrings [i]^.cleanup; *) if generate then begin if verbose then write ('% generating missing chars - '); fixchars; end; if generate and split then begin if verbose then write ('% splitting paths - '); for i := 1 to CharStringscount do CharStrings [i]^.splitpath; (**) end; (* sort and number subroutines, collect statistics *) sortMoreSubrs; if verbose then writeln ('% arranging new subpaths'); arrangeMoreSubrs (Subrscount); (* output Subrs: *) if expand then begin Subrstotal := 4; Subrscount := 4 (* assume they sit on the first positions *) end; Subrsline.gotonexttoken; Subrsline.replacelasttoken (intstr (Subrstotal)); writeln (out, Subrsline.str); begin (* writeln (out, '% Subrs: -------'); *) if verbose then write ('% writing previous Subrs - '); for i := 1 to Subrscount do Subrs [i]^.print (out); if not expand then begin if verbose then writeln ('% writing new Subrs'); printMoreSubrs (out) end end; for i := linesafterOtherSubrs + 1 to linesafterSubrs do writeln (out, intermediatelines [i]); end; if afmcheck and afmopen then begin if verbose then writeln ('% checking afm measure information'); for i := 1 to CharStringscount do CharStrings [i]^.checkafm (false); end; if CharStringscount > 0 then begin (* output CharStrings: *) CharStringsline.gotonexttoken; CharStringsline.replacelasttoken (intstr (CharStringscount)); writeln (out, CharStringsline.str); begin (* writeln (out, '% CharStrings: -------'); *) if verbose then writeln ('% writing CharStrings'); for i := 1 to CharStringscount do CharStrings [i]^.print (out) end; end; while not eofile do begin writeln (out, line.str); readline; end; write (out, line.str); writeln (out); end; var infile, out, afmin, ccin, afmout: text; fontfile, fontname: string; paramindex, i: integer; option: string; optionvalue: Boolean; function isoption: Boolean; begin if paramindex > paramcount then isoption := false else begin option := paramstr (paramindex); if length (option) = 0 then isoption := false else isoption := option [1] in ['-', '+', '/'] end end; begin corelfix := false; generate := true; split := true; ttfix := true; verbose := true; stdenc := true; noOtherSubrs := true; afmcheck := true; expand := false; paramindex := 1; while isoption do begin optionvalue := true; for i := 1 to length (option) do case option [i] of '+': optionvalue := true; '-': optionvalue := false; 'c': corelfix := optionvalue; 'g': generate := optionvalue; 's': split := optionvalue; 't': ttfix := optionvalue; 'v': verbose := optionvalue; 'e': stdenc := optionvalue; 'o': noOtherSubrs := optionvalue; 'a': afmcheck := optionvalue; 'x': expand := optionvalue; end; if corelfix then generate := true; if expand then split := false; paramindex := paramindex + 1 end; if paramindex <= paramcount then begin fontfile := paramstr (paramindex); fontname := basename (fontfile); assign (infile, fontfile); reset (infile); assign (afmin, fontname + '.afm'); assign (ccin, fontname + '.cc'); paramindex := paramindex + 1; if paramindex <= paramcount then begin if isdir (paramstr (paramindex)) then begin fontfile := paramstr (paramindex) + '\' + fontfile; fontname := paramstr (paramindex) + '\' + fontname; end else begin fontfile := paramstr (paramindex); fontname := basename (fontfile); end; assign (out, fontfile); assign (afmout, fontname + '.afm'); end else begin assign (out, '' (* use standard output *)); assign (afmout, fontname + '.af$'); end; (*$I-*) reset (afmin) (*$I+*); afmopen := IOresult = 0; if afmopen then begin if verbose then writeln ('% reading afm information'); openafm (afmin, afmout); end; (*$I-*) reset (ccin) (*$I+*); ccopen := IOresult = 0; if ccopen then begin if verbose then writeln ('% reading compose information'); opencc (ccin); close (ccin); end; rewrite (out); tidy (infile, out); close (out); if afmopen then begin if verbose then writeln ('% finishing afm file'); closeafm (afmin, afmout); end; close (infile) end else tidy (input, output); printusedstat; end.