1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
|
% This program by D. E. Knuth is not copyrighted and can be used freely.
% Version 0 was completed on April 23, 1984.
% Version 0.1 added char_code output (May 4).
% Version 0.2 included rules and dots in the boundary calculations (May 25).
% Version 0.3 added label type "/" (May 27).
% Version 0.4 (by Arthur Samuel) improved the dot labeling routine (July 23).
% Version 0.5 added the slant font for rules (September 2).
% Version 0.6 changed label types and allowed invisible dots (September 28).
% Version 1.0 switched to new GF format (December 8).
% Version 1.1 switched to newer GF format (February 2, 1985).
% Version 1.2 added the offset operations of MF version 0.8 (April 1, 1985).
% Version 1.3 allowed online entry of gray font, etc. (April 22, 1985).
% Version 1.4 allowed "almost" horizontal or vertical rules (May 20, 1985).
% Version 1.5 corrected a bug in the diagonal slant routine (June 18, 1985).
% Version 1.6 corrected a bug if labels exist but no dots (September 13, 1985).
% Version 1.7 changed from am to cm fonts; fam became ext (October 5, 1985).
% Version 2.0 was tuned up for the METAFONTware report (April, 1989).
% Version 3.0 uses 8-bit codes and extended ligatures (October, 1989).
% Here is TeX material that gets inserted after \input webmac
\def\hang{\hangindent 3em\indent\ignorespaces}
\font\ninerm=cmr9
\let\mc=\ninerm % medium caps for names like SAIL
\def\PASCAL{Pascal}
\font\logo=manfnt % font used for the METAFONT logo
\def\MF{{\logo META}\-{\logo FONT}}
\let\swap=\leftrightarrow
\def\(#1){} % this is used to make section names sort themselves better
\def\9#1{} % this is used for sort keys in the index
\def\title{GF$\,$\lowercase{to}$\,$DVI}
\def\contentspagenumber{301}
\def\topofcontents{\null
\def\titlepage{F} % include headline on the contents page
\def\rheader{\mainfont\hfil \contentspagenumber}
\vfill
\centerline{\titlefont The {\ttitlefont GFtoDVI} processor}
\vskip 15pt
\centerline{(Version 3.0, October 1989)}
\vfill}
\def\botofcontents{\vfill
\centerline{\hsize 5in\baselineskip9pt
\vbox{\ninerm\noindent
The preparation of this report
was supported in part by the National Science
Foundation under grants IST-8201926, MCS-8300984, and
CCR-8610181,
and by the System Development Foundation. `\TeX' is a
trademark of the American Mathematical Society.
`{\logo hijklmnj}\kern1pt' is a trademark of Addison-Wesley
Publishing Company.}}}
\pageno=\contentspagenumber \advance\pageno by 1
@* Introduction.
The \.{GFtoDVI} utility program reads binary generic font (``\.{GF}'')
files that are produced by font compilers such as \MF, and converts them
into device-independent (``\.{DVI}'') files that can be printed to give
annotated hardcopy proofs of the character shapes. The annotations are
specified by the comparatively simple conventions of plain \MF; i.e.,
there are mechanisms for labeling chosen points and for superimposing
horizontal or vertical rules on the enlarged character shapes.
The purpose of \.{GFtoDVI} is simply to make proof copies; it does not
exhaustively test the validity of a \.{GF} file, nor do its algorithms
much resemble the algorithms that are typically used to prepare font
descriptions for commercial typesetting equipment. Another program,
\.{GFtype}, is available for validity checking; \.{GFtype} also serves
as a model of programs that convert fonts from \.{GF} format to some
other coding scheme.
The |banner| string defined here should be changed whenever \.{GFtoDVI}
gets modified.
@d banner=='This is GFtoDVI, Version 3.0' {printed when the program starts}
@ This program is written in standard \PASCAL, except where it is necessary
to use extensions; for example, \.{GFtoDVI} must read files whose names
are dynamically specified, and such a task would be impossible in pure \PASCAL.
All places where nonstandard constructions are used have been listed in
the index under ``system dependencies.''
@!@^system dependencies@>
Another exception to standard \PASCAL\ occurs in the
use of default branches in |case| statements; the conventions
of \.{TANGLE}, \.{WEAVE}, etc., have been followed.
@d othercases == others: {default for cases not listed explicitly}
@d endcases == @+end {follows the default case in an extended |case| statement}
@f othercases == else
@f endcases == end
@ The main input and output files are not mentioned in the program header,
because their external names
will be determined at run time (e.g., by interpreting the
command line that invokes this program). Error messages and other remarks
are written on the |output| file, which the user may
choose to assign to the terminal if the system permits it.
@^system dependencies@>
The term |print| is used instead of |write| when this program writes on
the |output| file, so that all such output can be easily deflected.
@d print(#)==write(#)
@d print_ln(#)==write_ln(#)
@d print_nl(#)==@+begin write_ln; write(#);@+end
@p program GF_to_DVI(@!output);
label @<Labels in the outer block@>@/
const @<Constants in the outer block@>@/
type @<Types in the outer block@>@/
var @<Globals in the outer block@>@/
procedure initialize; {this procedure gets things started properly}
var @!i,@!j,@!m,@!n:integer; {loop indices for initializations}
begin print_ln(banner);@/
@<Set initial values@>@/
end;
@ If the program has to stop prematurely, it goes to the
`|final_end|'.
@d final_end=9999 {label for the end of it all}
@<Labels...@>=final_end;
@ The following parameters can be changed at compile time to extend or
reduce \.{GFtoDVI}'s capacity.
@<Constants...@>=
@!max_labels=2000; {maximum number of labels and dots and rules per character}
@!pool_size=10000; {maximum total length of labels and other strings}
@!max_strings=1100; {maximum number of labels and other strings}
@!terminal_line_length=150; {maximum number of characters input in a single
line of input from the terminal}
@!file_name_size=50; {a file name shouldn't be longer than this}
@!font_mem_size=2000; {space for font metric data}
@!dvi_buf_size=800; {size of the output buffer; must be a multiple of 8}
@!widest_row=8192; {maximum number of pixels per row}
@!lig_lookahead=20; {size of stack used when inserting ligature characters}
@ Labels are given symbolic names by the following definitions, so that
occasional |goto| statements will be meaningful. We insert the label
`|exit|:' just before the `\ignorespaces|end|\unskip' of a procedure in
which we have used the `|return|' statement defined below; the label
`|reswitch|' is occasionally used just prior to a |case|
statement in which some cases change the conditions and we wish to branch
to the newly applicable case. Loops that are set up with the |loop|
construction defined below are commonly exited by going to `|done|' or to
`|found|' or to `|not_found|', and they are sometimes repeated by going to
`|continue|'.
Incidentally, this program never declares a label that isn't actually used,
because some fussy \PASCAL\ compilers will complain about redundant labels.
@d exit=10 {go here to leave a procedure}
@d reswitch=21 {go here to start a case statement again}
@d continue=22 {go here to resume a loop}
@d done=30 {go here to exit a loop}
@d done1=31 {like |done|, when there is more than one loop}
@d found=40 {go here when you've found it}
@d not_found=45 {go here when you've found nothing}
@ Here are some macros for common programming idioms.
@d incr(#) == #:=#+1 {increase a variable by unity}
@d decr(#) == #:=#-1 {decrease a variable by unity}
@d loop == @+ while true do@+ {repeat over and over until a |goto| happens}
@f loop == xclause
{\.{WEB}'s |xclause| acts like `\ignorespaces|while true do|\unskip'}
@d do_nothing == {empty statement}
@d return == goto exit {terminate a procedure call}
@f return == nil {\.{WEB} will henceforth say |return| instead of \\{return}}
@ If the \.{GF} file is badly malformed, the whole process must be aborted;
\.{GFtoDVI} will give up, after issuing an error message about the symptoms
that were noticed.
Such errors might be discovered inside of subroutines inside of subroutines,
so a procedure called |jump_out| has been introduced. This procedure, which
simply transfers control to the label |final_end| at the end of the program,
contains the only non-local |goto| statement in \.{GFtoDVI}.
@^system dependencies@>
@d abort(#)==@+begin print(' ',#); jump_out;@+end
@d bad_gf(#)==abort('Bad GF file: ',#,'! (at byte ',cur_loc-1:1,')')
@.Bad GF file@>
@p procedure jump_out;
begin goto final_end;
end;
@ As in \TeX\ and \MF, this program deals with numeric quantities that
are integer multiples of~$2^{16}$, and calls them |scaled|.
@d unity==@'200000 {|scaled| representation of 1.0}
@<Types ...@>=
@!scaled=integer; {fixed-point numbers}
@* The character set.
Like all programs written with the \.{WEB} system, \.{GFtoDVI} can be
used with any character set. But it uses ASCII code internally, because
the programming for portable input-output is easier when a fixed internal
code is used. Furthermore, both \.{GF} and \.{DVI} files use ASCII code
for file names and certain other strings.
The next few sections of \.{GFtoDVI} have therefore been copied from the
analogous ones in the \.{WEB} system routines.
@<Types ...@>=
@!ASCII_code=0..255; {eight-bit numbers, a subrange of the integers}
@ The original \PASCAL\ compiler was designed in the late 60s, when
six-bit character sets were common, so it did not make provision for lowercase
letters. Nowadays, of course, we need to deal with both capital and
small letters in a convenient way. So we shall assume that the
\PASCAL\ system being used for \.{GFtoDVI} has a character set containing
at least the standard visible ASCII characters (|"!"| through |"~"|). If
additional characters are present, \.{GFtoDVI} can be configured to
work with them too.
Some \PASCAL\ compilers use the original name |char| for the data type
associated with the characters in text files, while other \PASCAL s
consider |char| to be a 64-element subrange of a larger data type that has
some other name. In order to accommodate this difference, we shall use
the name |text_char| to stand for the data type of the characters in the
output file. We shall also assume that |text_char| consists of
the elements |chr(first_text_char)| through |chr(last_text_char)|,
inclusive. The following definitions should be adjusted if necessary.
@^system dependencies@>
@d text_char == char {the data type of characters in text files}
@d first_text_char=0 {ordinal number of the smallest element of |text_char|}
@d last_text_char=255 {ordinal number of the largest element of |text_char|}
@<Types ...@>=
@!text_file=packed file of text_char;
@ The \.{GFtoDVI} processor converts between ASCII code and
the user's external character set by means of arrays |xord| and |xchr|
that are analogous to \PASCAL's |ord| and |chr| functions.
@<Globals...@>=
@!xord: array [text_char] of ASCII_code;
{specifies conversion of input characters}
@!xchr: array [ASCII_code] of text_char;
{specifies conversion of output characters}
@ Under our assumption that the visible characters of standard ASCII are
all present, the following assignment statements initialize the
|xchr| array properly, without needing any system-dependent changes.
@<Set init...@>=
xchr[@'40]:=' ';
xchr[@'41]:='!';
xchr[@'42]:='"';
xchr[@'43]:='#';
xchr[@'44]:='$';
xchr[@'45]:='%';
xchr[@'46]:='&';
xchr[@'47]:='''';@/
xchr[@'50]:='(';
xchr[@'51]:=')';
xchr[@'52]:='*';
xchr[@'53]:='+';
xchr[@'54]:=',';
xchr[@'55]:='-';
xchr[@'56]:='.';
xchr[@'57]:='/';@/
xchr[@'60]:='0';
xchr[@'61]:='1';
xchr[@'62]:='2';
xchr[@'63]:='3';
xchr[@'64]:='4';
xchr[@'65]:='5';
xchr[@'66]:='6';
xchr[@'67]:='7';@/
xchr[@'70]:='8';
xchr[@'71]:='9';
xchr[@'72]:=':';
xchr[@'73]:=';';
xchr[@'74]:='<';
xchr[@'75]:='=';
xchr[@'76]:='>';
xchr[@'77]:='?';@/
xchr[@'100]:='@@';
xchr[@'101]:='A';
xchr[@'102]:='B';
xchr[@'103]:='C';
xchr[@'104]:='D';
xchr[@'105]:='E';
xchr[@'106]:='F';
xchr[@'107]:='G';@/
xchr[@'110]:='H';
xchr[@'111]:='I';
xchr[@'112]:='J';
xchr[@'113]:='K';
xchr[@'114]:='L';
xchr[@'115]:='M';
xchr[@'116]:='N';
xchr[@'117]:='O';@/
xchr[@'120]:='P';
xchr[@'121]:='Q';
xchr[@'122]:='R';
xchr[@'123]:='S';
xchr[@'124]:='T';
xchr[@'125]:='U';
xchr[@'126]:='V';
xchr[@'127]:='W';@/
xchr[@'130]:='X';
xchr[@'131]:='Y';
xchr[@'132]:='Z';
xchr[@'133]:='[';
xchr[@'134]:='\';
xchr[@'135]:=']';
xchr[@'136]:='^';
xchr[@'137]:='_';@/
xchr[@'140]:='`';
xchr[@'141]:='a';
xchr[@'142]:='b';
xchr[@'143]:='c';
xchr[@'144]:='d';
xchr[@'145]:='e';
xchr[@'146]:='f';
xchr[@'147]:='g';@/
xchr[@'150]:='h';
xchr[@'151]:='i';
xchr[@'152]:='j';
xchr[@'153]:='k';
xchr[@'154]:='l';
xchr[@'155]:='m';
xchr[@'156]:='n';
xchr[@'157]:='o';@/
xchr[@'160]:='p';
xchr[@'161]:='q';
xchr[@'162]:='r';
xchr[@'163]:='s';
xchr[@'164]:='t';
xchr[@'165]:='u';
xchr[@'166]:='v';
xchr[@'167]:='w';@/
xchr[@'170]:='x';
xchr[@'171]:='y';
xchr[@'172]:='z';
xchr[@'173]:='{';
xchr[@'174]:='|';
xchr[@'175]:='}';
xchr[@'176]:='~';
@ Here now is the system-dependent part of the character set.
If \.{GFtoDVI} is being implemented on a garden-variety \PASCAL\ for which
only standard ASCII codes will appear in the input and output files, you
don't need to make any changes here. But if you have, for example, an extended
character set like the one in Appendix~C of {\sl The \TeX book}, the first
line of code in this module should be changed to
$$\hbox{|for i:=0 to @'37 do xchr[i]:=chr(i);|}$$
\.{WEB}'s character set is essentially identical to \TeX's.
@^system dependencies@>
@<Set init...@>=
for i:=0 to @'37 do xchr[i]:='?';
for i:=@'177 to @'377 do xchr[i]:='?';
@ The following system-independent code makes the |xord| array contain a
suitable inverse to the information in |xchr|.
@<Set init...@>=
for i:=first_text_char to last_text_char do xord[chr(i)]:=" ";
for i:=1 to @'377 do xord[xchr[i]]:=i;
xord['?']:="?";
@ The |input_ln| routine waits for the user to type a line at his or her
terminal; then it puts ASCII-code equivalents for the characters on that line
into the |buffer| array. The |term_in| file is used for terminal input.
@^system dependencies@>
Since the terminal is being used for both input and output, some systems
need a special routine to make sure that the user can see a prompt message
before waiting for input based on that message. (Otherwise the message
may just be sitting in a hidden buffer somewhere, and the user will have
no idea what the program is waiting for.) We shall call a system-dependent
subroutine |update_terminal| in order to avoid this problem.
@d update_terminal == break(output) {empty the terminal output buffer}
@<Glob...@>=
@!buffer:array[0..terminal_line_length] of 0..255;
@!term_in:text_file; {the terminal, considered as an input file}
@ A global variable |line_length| records the first buffer position after
the line just read.
@^system dependencies@>
@p procedure input_ln; {inputs a line from the terminal}
begin update_terminal; reset(term_in);
if eoln(term_in) then read_ln(term_in);
line_length:=0;
while (line_length<terminal_line_length)and not eoln(term_in) do
begin buffer[line_length]:=xord[term_in^]; incr(line_length); get(term_in);
end;
end;
@ The global variable |buf_ptr| is used while scanning each line of input;
it points to the first unread character in |buffer|.
@<Glob...@>=
@!buf_ptr:0..terminal_line_length; {the number of characters read}
@!line_length:0..terminal_line_length; {end of line read by |input_ln|}
@* Device-independent file format.
Before we get into the details of \.{GFtoDVI}, we need to know exactly
what \.{DVI} files are. The form of such files was designed by David R.
@^Fuchs, David Raymond@>
Fuchs in 1979. Almost any reasonable typesetting device can be driven by
a program that takes \.{DVI} files as input, and dozens of such
\.{DVI}-to-whatever programs have been written. Thus, it is possible to
print the output of document compilers like \TeX\ on many different kinds
of equipment. (The following material has been copied almost verbatim from the
program for \TeX.)
A \.{DVI} file is a stream of 8-bit bytes, which may be regarded as a
series of commands in a machine-like language. The first byte of each command
is the operation code, and this code is followed by zero or more bytes
that provide parameters to the command. The parameters themselves may consist
of several consecutive bytes; for example, the `|set_rule|' command has two
parameters, each of which is four bytes long. Parameters are usually
regarded as nonnegative integers; but four-byte-long parameters,
and shorter parameters that denote distances, can be
either positive or negative. Such parameters are given in two's complement
notation. For example, a two-byte-long distance parameter has a value between
$-2^{15}$ and $2^{15}-1$.
@.DVI {\rm files}@>
Incidentally, when two or more 8-bit bytes are combined to form an integer of
16 or more bits, the most significant bytes appear first in the file.
This is called BigEndian order.
@^BigEndian order@>
A \.{DVI} file consists of a ``preamble,'' followed by a sequence of one
or more ``pages,'' followed by a ``postamble.'' The preamble is simply a
|pre| command, with its parameters that define the dimensions used in the
file; this must come first. Each ``page'' consists of a |bop| command,
followed by any number of other commands that tell where characters are to
be placed on a physical page, followed by an |eop| command. The pages
appear in the order that they were generated, not in any particular
numerical order. If we ignore |nop| commands and \\{fnt\_def} commands
(which are allowed between any two commands in the file), each |eop|
command is immediately followed by a |bop| command, or by a |post|
command; in the latter case, there are no more pages in the file, and the
remaining bytes form the postamble. Further details about the postamble
will be explained later.
Some parameters in \.{DVI} commands are ``pointers.'' These are four-byte
quantities that give the location number of some other byte in the file;
the first byte is number~0, then comes number~1, and so on. For example,
one of the parameters of a |bop| command points to the previous |bop|;
this makes it feasible to read the pages in backwards order, in case the
results are being directed to a device that stacks its output face up.
Suppose the preamble of a \.{DVI} file occupies bytes 0 to 99. Now if the
first page occupies bytes 100 to 999, say, and if the second
page occupies bytes 1000 to 1999, then the |bop| that starts in byte 1000
points to 100 and the |bop| that starts in byte 2000 points to 1000. (The
very first |bop|, i.e., the one that starts in byte 100, has a pointer of $-1$.)
@ The \.{DVI} format is intended to be both compact and easily interpreted
by a machine. Compactness is achieved by making most of the information
implicit instead of explicit. When a \.{DVI}-reading program reads the
commands for a page, it keeps track of several quantities: (a)~The current
font |f| is an integer; this value is changed only
by \\{fnt} and \\{fnt\_num} commands. (b)~The current position on the page
is given by two numbers called the horizontal and vertical coordinates,
|h| and |v|. Both coordinates are zero at the upper left corner of the page;
moving to the right corresponds to increasing the horizontal coordinate, and
moving down corresponds to increasing the vertical coordinate. Thus, the
coordinates are essentially Cartesian, except that vertical directions are
flipped; the Cartesian version of |(h,v)| would be |(h,-v)|. (c)~The
current spacing amounts are given by four numbers |w|, |x|, |y|, and |z|,
where |w| and~|x| are used for horizontal spacing and where |y| and~|z|
are used for vertical spacing. (d)~There is a stack containing
|(h,v,w,x,y,z)| values; the \.{DVI} commands |push| and |pop| are used to
change the current level of operation. Note that the current font~|f| is
not pushed and popped; the stack contains only information about
positioning.
The values of |h|, |v|, |w|, |x|, |y|, and |z| are signed integers having up
to 32 bits, including the sign. Since they represent physical distances,
there is a small unit of measurement such that increasing |h| by~1 means
moving a certain tiny distance to the right. The actual unit of
measurement is variable, as explained below.
@ Here is a list of all the commands that may appear in a \.{DVI} file. Each
command is specified by its symbolic name (e.g., |bop|), its opcode byte
(e.g., 139), and its parameters (if any). The parameters are followed
by a bracketed number telling how many bytes they occupy; for example,
`|p[4]|' means that parameter |p| is four bytes long.
\yskip\hang|set_char_0| 0. Typeset character number~0 from font~|f|
such that the reference point of the character is at |(h,v)|. Then
increase |h| by the width of that character. Note that a character may
have zero or negative width, so one cannot be sure that |h| will advance
after this command; but |h| usually does increase.
\yskip\hang|set_char_1| through |set_char_127| (opcodes 1 to 127).
Do the operations of |set_char_0|; but use the character whose number
matches the opcode, instead of character~0.
\yskip\hang|set1| 128 |c[1]|. Same as |set_char_0|, except that character
number~|c| is typeset. \TeX82 uses this command for characters in the
range |128<=c<256|.
\yskip\hang|set2| 129 |c[2]|. Same as |set1|, except that |c|~is two
bytes long, so it is in the range |0<=c<65536|.
\yskip\hang|set3| 130 |c[3]|. Same as |set1|, except that |c|~is three
bytes long, so it can be as large as $2^{24}-1$. Not even the Chinese
language has this many characters, but this command might prove useful
in some yet unforeseen way.
\yskip\hang|set4| 131 |c[4]|. Same as |set1|, except that |c|~is four
bytes long, possibly even negative. Imagine that.
\yskip\hang|set_rule| 132 |a[4]| |b[4]|. Typeset a solid black rectangle
of height |a| and width |b|, with its bottom left corner at |(h,v)|. Then
set |h:=h+b|. If either |a<=0| or |b<=0|, nothing should be typeset. Note
that if |b<0|, the value of |h| will decrease even though nothing else happens.
\yskip\hang|put1| 133 |c[1]|. Typeset character number~|c| from font~|f|
such that the reference point of the character is at |(h,v)|. (The `put'
commands are exactly like the `set' commands, except that they simply put out a
character or a rule without moving the reference point afterwards.)
\yskip\hang|put2| 134 |c[2]|. Same as |set2|, except that |h| is not changed.
\yskip\hang|put3| 135 |c[3]|. Same as |set3|, except that |h| is not changed.
\yskip\hang|put4| 136 |c[4]|. Same as |set4|, except that |h| is not changed.
\yskip\hang|put_rule| 137 |a[4]| |b[4]|. Same as |set_rule|, except that
|h| is not changed.
\yskip\hang|nop| 138. No operation, do nothing. Any number of |nop|'s
may occur between \.{DVI} commands, but a |nop| cannot be inserted between
a command and its parameters or between two parameters.
\yskip\hang|bop| 139 $c_0[4]$ $c_1[4]$ $\ldots$ $c_9[4]$ $p[4]$. Beginning
of a page: Set |(h,v,w,x,y,z):=(0,0,0,0,0,0)| and set the stack empty. Set
the current font |f| to an undefined value. The ten $c_i$ parameters can
be used to identify pages, if a user wants to print only part of a \.{DVI}
file; \TeX82 gives them the values of \.{\\count0} $\ldots$ \.{\\count9}
at the time \.{\\shipout} was invoked for this page. The parameter |p|
points to the previous |bop| command in the file, where the first |bop|
has $p=-1$.
\yskip\hang|eop| 140. End of page: Print what you have read since the
previous |bop|. At this point the stack should be empty. (The \.{DVI}-reading
programs that drive most output devices will have kept a buffer of the
material that appears on the page that has just ended. This material is
largely, but not entirely, in order by |v| coordinate and (for fixed |v|) by
|h|~coordinate; so it usually needs to be sorted into some order that is
appropriate for the device in question. \.{GFtoDVI} does not do such sorting.)
\yskip\hang|push| 141. Push the current values of |(h,v,w,x,y,z)| onto the
top of the stack; do not change any of these values. Note that |f| is
not pushed.
\yskip\hang|pop| 142. Pop the top six values off of the stack and assign
them to |(h,v,w,x,y,z)|. The number of pops should never exceed the number
of pushes, since it would be highly embarrassing if the stack were empty
at the time of a |pop| command.
\yskip\hang|right1| 143 |b[1]|. Set |h:=h+b|, i.e., move right |b| units.
The parameter is a signed number in two's complement notation, |-128<=b<128|;
if |b<0|, the reference point actually moves left.
\yskip\hang|right2| 144 |b[2]|. Same as |right1|, except that |b| is a
two-byte quantity in the range |-32768<=b<32768|.
\yskip\hang|right3| 145 |b[3]|. Same as |right1|, except that |b| is a
three-byte quantity in the range |@t$-2^{23}$@><=b<@t$2^{23}$@>|.
\yskip\hang|right4| 146 |b[4]|. Same as |right1|, except that |b| is a
four-byte quantity in the range |@t$-2^{31}$@><=b<@t$2^{31}$@>|.
\yskip\hang|w0| 147. Set |h:=h+w|; i.e., move right |w| units. With luck,
this parameterless command will usually suffice, because the same kind of motion
will occur several times in succession; the following commands explain how
|w| gets particular values.
\yskip\hang|w1| 148 |b[1]|. Set |w:=b| and |h:=h+b|. The value of |b| is a
signed quantity in two's complement notation, |-128<=b<128|. This command
changes the current |w|~spacing and moves right by |b|.
\yskip\hang|w2| 149 |b[2]|. Same as |w1|, but |b| is a two-byte-long
parameter, |-32768<=b<32768|.
\yskip\hang|w3| 150 |b[3]|. Same as |w1|, but |b| is a three-byte-long
parameter, |@t$-2^{23}$@><=b<@t$2^{23}$@>|.
\yskip\hang|w4| 151 |b[4]|. Same as |w1|, but |b| is a four-byte-long
parameter, |@t$-2^{31}$@><=b<@t$2^{31}$@>|.
\yskip\hang|x0| 152. Set |h:=h+x|; i.e., move right |x| units. The `|x|'
commands are like the `|w|' commands except that they involve |x| instead
of |w|.
\yskip\hang|x1| 153 |b[1]|. Set |x:=b| and |h:=h+b|. The value of |b| is a
signed quantity in two's complement notation, |-128<=b<128|. This command
changes the current |x|~spacing and moves right by |b|.
\yskip\hang|x2| 154 |b[2]|. Same as |x1|, but |b| is a two-byte-long
parameter, |-32768<=b<32768|.
\yskip\hang|x3| 155 |b[3]|. Same as |x1|, but |b| is a three-byte-long
parameter, |@t$-2^{23}$@><=b<@t$2^{23}$@>|.
\yskip\hang|x4| 156 |b[4]|. Same as |x1|, but |b| is a four-byte-long
parameter, |@t$-2^{31}$@><=b<@t$2^{31}$@>|.
\yskip\hang|down1| 157 |a[1]|. Set |v:=v+a|, i.e., move down |a| units.
The parameter is a signed number in two's complement notation, |-128<=a<128|;
if |a<0|, the reference point actually moves up.
\yskip\hang|down2| 158 |a[2]|. Same as |down1|, except that |a| is a
two-byte quantity in the range |-32768<=a<32768|.
\yskip\hang|down3| 159 |a[3]|. Same as |down1|, except that |a| is a
three-byte quantity in the range |@t$-2^{23}$@><=a<@t$2^{23}$@>|.
\yskip\hang|down4| 160 |a[4]|. Same as |down1|, except that |a| is a
four-byte quantity in the range |@t$-2^{31}$@><=a<@t$2^{31}$@>|.
\yskip\hang|y0| 161. Set |v:=v+y|; i.e., move down |y| units. With luck,
this parameterless command will usually suffice, because the same kind of motion
will occur several times in succession; the following commands explain how
|y| gets particular values.
\yskip\hang|y1| 162 |a[1]|. Set |y:=a| and |v:=v+a|. The value of |a| is a
signed quantity in two's complement notation, |-128<=a<128|. This command
changes the current |y|~spacing and moves down by |a|.
\yskip\hang|y2| 163 |a[2]|. Same as |y1|, but |a| is a two-byte-long
parameter, |-32768<=a<32768|.
\yskip\hang|y3| 164 |a[3]|. Same as |y1|, but |a| is a three-byte-long
parameter, |@t$-2^{23}$@><=a<@t$2^{23}$@>|.
\yskip\hang|y4| 165 |a[4]|. Same as |y1|, but |a| is a four-byte-long
parameter, |@t$-2^{31}$@><=a<@t$2^{31}$@>|.
\yskip\hang|z0| 166. Set |v:=v+z|; i.e., move down |z| units. The `|z|' commands
are like the `|y|' commands except that they involve |z| instead of |y|.
\yskip\hang|z1| 167 |a[1]|. Set |z:=a| and |v:=v+a|. The value of |a| is a
signed quantity in two's complement notation, |-128<=a<128|. This command
changes the current |z|~spacing and moves down by |a|.
\yskip\hang|z2| 168 |a[2]|. Same as |z1|, but |a| is a two-byte-long
parameter, |-32768<=a<32768|.
\yskip\hang|z3| 169 |a[3]|. Same as |z1|, but |a| is a three-byte-long
parameter, |@t$-2^{23}$@><=a<@t$2^{23}$@>|.
\yskip\hang|z4| 170 |a[4]|. Same as |z1|, but |a| is a four-byte-long
parameter, |@t$-2^{31}$@><=a<@t$2^{31}$@>|.
\yskip\hang|fnt_num_0| 171. Set |f:=0|. Font 0 must previously have been
defined by a \\{fnt\_def} instruction, as explained below.
\yskip\hang|fnt_num_1| through |fnt_num_63| (opcodes 172 to 234). Set
|f:=1|, \dots, |f:=63|, respectively.
\yskip\hang|fnt1| 235 |k[1]|. Set |f:=k|. \TeX82 uses this command for font
numbers in the range |64<=k<256|.
\yskip\hang|fnt2| 236 |k[2]|. Same as |fnt1|, except that |k|~is two
bytes long, so it is in the range |0<=k<65536|. \TeX82 never generates this
command, but large font numbers may prove useful for specifications of
color or texture, or they may be used for special fonts that have fixed
numbers in some external coding scheme.
\yskip\hang|fnt3| 237 |k[3]|. Same as |fnt1|, except that |k|~is three
bytes long, so it can be as large as $2^{24}-1$.
\yskip\hang|fnt4| 238 |k[4]|. Same as |fnt1|, except that |k|~is four
bytes long; this is for the really big font numbers (and for the negative ones).
\yskip\hang|xxx1| 239 |k[1]| |x[k]|. This command is undefined in
general; it functions as a $(k+2)$-byte |nop| unless special \.{DVI}-reading
programs are being used. \TeX82 generates |xxx1| when a short enough
\.{\\special} appears, setting |k| to the number of bytes being sent. It
is recommended that |x| be a string having the form of a keyword followed
by possible parameters relevant to that keyword.
\yskip\hang|xxx2| 240 |k[2]| |x[k]|. Like |xxx1|, but |0<=k<65536|.
\yskip\hang|xxx3| 241 |k[3]| |x[k]|. Like |xxx1|, but |0<=k<@t$2^{24}$@>|.
\yskip\hang|xxx4| 242 |k[4]| |x[k]|. Like |xxx1|, but |k| can be ridiculously
large. \TeX82 uses |xxx4| when |xxx1| would be incorrect.
\yskip\hang|fnt_def1| 243 |k[1]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
Define font |k|, where |0<=k<256|; font definitions will be explained shortly.
\yskip\hang|fnt_def2| 244 |k[2]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
Define font |k|, where |0<=k<65536|.
\yskip\hang|fnt_def3| 245 |k[3]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
Define font |k|, where |0<=k<@t$2^{24}$@>|.
\yskip\hang|fnt_def4| 246 |k[4]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
Define font |k|, where |@t$-2^{31}$@><=k<@t$2^{31}$@>|.
\yskip\hang|pre| 247 |i[1]| |num[4]| |den[4]| |mag[4]| |k[1]| |x[k]|.
Beginning of the preamble; this must come at the very beginning of the
file. Parameters |i|, |num|, |den|, |mag|, |k|, and |x| are explained below.
\yskip\hang|post| 248. Beginning of the postamble, see below.
\yskip\hang|post_post| 249. Ending of the postamble, see below.
\yskip\noindent Commands 250--255 are undefined at the present time.
@ Only a few of the operation codes above are actually needed by \.{GFtoDVI}.
@d set1=128 {typeset a character and move right}
@d put_rule=137 {typeset a rule}
@d bop=139 {beginning of page}
@d eop=140 {ending of page}
@d push=141 {save the current positions}
@d pop=142 {restore previous positions}
@d right4=146 {move right}
@d down4=160 {move down}
@d z0=166 {move down |z|}
@d z4=170 {move down and set |z|}
@d fnt_num_0=171 {set current font to 0}
@d fnt_def1=243 {define the meaning of a font number}
@d pre=247 {preamble}
@d post=248 {postamble beginning}
@d post_post=249 {postamble ending}
@ The preamble contains basic information about the file as a whole. As
stated above, there are six parameters:
$$\hbox{|@!i[1]| |@!num[4]| |@!den[4]| |@!mag[4]| |@!k[1]| |@!x[k]|.}$$
The |i| byte identifies \.{DVI} format; currently this byte is always set
to~2. (The value |i=3| is currently used for an extended format that
allows a mixture of right-to-left and left-to-right typesetting.
Some day we will set |i=4|, when \.{DVI} format makes another
incompatible change---perhaps in the year 2048.)
The next two parameters, |num| and |den|, are positive integers that define
the units of measurement; they are the numerator and denominator of a
fraction by which all dimensions in the \.{DVI} file could be multiplied
in order to get lengths in units of $10^{-7}$ meters. (For example, there are
exactly 7227 \TeX\ points in 254 centimeters, and \TeX82 works with scaled
points where there are $2^{16}$ sp in a point, so \TeX82 sets |num=25400000|
and $|den|=7227\cdot2^{16}=473628672$.)
@^sp@>
The |mag| parameter is what \TeX82 calls \.{\\mag}, i.e., 1000 times the
desired magnification. The actual fraction by which dimensions are
multiplied is therefore $|mag|\cdot|num|/1000|den|$. Note that if a \TeX\
source document does not call for any `\.{true}' dimensions, and if you
change it only by specifying a different \.{\\mag} setting, the \.{DVI}
file that \TeX\ creates will be completely unchanged except for the value
of |mag| in the preamble and postamble. (Fancy \.{DVI}-reading programs allow
users to override the |mag|~setting when a \.{DVI} file is being printed.)
Finally, |k| and |x| allow the \.{DVI} writer to include a comment, which is not
interpreted further. The length of comment |x| is |k|, where |0<=k<256|.
@d dvi_id_byte=2 {identifies the kind of \.{DVI} files described here}
@ Font definitions for a given font number |k| contain further parameters
$$\hbox{|c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.}$$
The four-byte value |c| is the check sum that \TeX\ (or whatever program
generated the \.{DVI} file) found in the \.{TFM} file for this font;
|c| should match the check sum of the font found by programs that read
this \.{DVI} file.
@^check sum@>
Parameter |s| contains a fixed-point scale factor that is applied to the
character widths in font |k|; font dimensions in \.{TFM} files and other
font files are relative to this quantity, which is always positive and
less than $2^{27}$. It is given in the same units as the other dimensions
of the \.{DVI} file. Parameter |d| is similar to |s|; it is the ``design
size,'' and (like~|s|) it is given in \.{DVI} units. Thus, font |k| is to be
used at $|mag|\cdot s/1000d$ times its normal size.
The remaining part of a font definition gives the external name of the font,
which is an ASCII string of length |a+l|. The number |a| is the length
of the ``area'' or directory, and |l| is the length of the font name itself;
the standard local system font area is supposed to be used when |a=0|.
The |n| field contains the area in its first |a| bytes.
Font definitions must appear before the first use of a particular font number.
Once font |k| is defined, it must not be defined again; however, we
shall see below that font definitions appear in the postamble as well as
in the pages, so in this sense each font number is defined exactly twice,
if at all. Like |nop| commands, font definitions can
appear before the first |bop|, or between an |eop| and a |bop|.
@ The last page in a \.{DVI} file is followed by `|post|'; this command
introduces the postamble, which summarizes important facts that \TeX\ has
accumulated about the file, making it possible to print subsets of the data
with reasonable efficiency. The postamble has the form
$$\vbox{\halign{\hbox{#\hfil}\cr
|post| |p[4]| |num[4]| |den[4]| |mag[4]| |l[4]| |u[4]| |s[2]| |t[2]|\cr
$\langle\,$font definitions$\,\rangle$\cr
|post_post| |q[4]| |i[1]| 223's$[{\G}4]$\cr}}$$
Here |p| is a pointer to the final |bop| in the file. The next three
parameters, |num|, |den|, and |mag|, are duplicates of the quantities that
appeared in the preamble.
Parameters |l| and |u| give respectively the height-plus-depth of the tallest
page and the width of the widest page, in the same units as other dimensions
of the file. These numbers might be used by a \.{DVI}-reading program to
position individual ``pages'' on large sheets of film or paper; however,
the standard convention for output on normal size paper is to position each
page so that the upper left-hand corner is exactly one inch from the left
and the top. Experience has shown that it is unwise to design \.{DVI}-to-printer
software that attempts cleverly to center the output; a fixed position of
the upper left corner is easiest for users to understand and to work with.
Therefore |l| and~|u| are often ignored.
Parameter |s| is the maximum stack depth (i.e., the largest excess of
|push| commands over |pop| commands) needed to process this file. Then
comes |t|, the total number of pages (|bop| commands) present.
The postamble continues with font definitions, which are any number of
\\{fnt\_def} commands as described above, possibly interspersed with |nop|
commands. Each font number that is used in the \.{DVI} file must be defined
exactly twice: Once before it is first selected by a \\{fnt} command, and once
in the postamble.
@ The last part of the postamble, following the |post_post| byte that
signifies the end of the font definitions, contains |q|, a pointer to the
|post| command that started the postamble. An identification byte, |i|,
comes next; this currently equals~2, as in the preamble.
The |i| byte is followed by four or more bytes that are all equal to
the decimal number 223 (i.e., @'337 in octal). \TeX\ puts out four to seven of
these trailing bytes, until the total length of the file is a multiple of
four bytes, since this works out best on machines that pack four bytes per
word; but any number of 223's is allowed, as long as there are at least four
of them. In effect, 223 is a sort of signature that is added at the very end.
@^Fuchs, David Raymond@>
This curious way to finish off a \.{DVI} file makes it feasible for
\.{DVI}-reading programs to find the postamble first, on most computers,
even though \TeX\ wants to write the postamble last. Most operating
systems permit random access to individual words or bytes of a file, so
the \.{DVI} reader can start at the end and skip backwards over the 223's
until finding the identification byte. Then it can back up four bytes, read
|q|, and move to byte |q| of the file. This byte should, of course,
contain the value 248 (|post|); now the postamble can be read, so the
\.{DVI} reader can discover all the information needed for typesetting the
pages. Note that it is also possible to skip through the \.{DVI} file at
reasonably high speed to locate a particular page, if that proves
desirable. This saves a lot of time, since \.{DVI} files used in production
jobs tend to be large.
Unfortunately, however, standard \PASCAL\ does not include the ability to
@^system dependencies@>
access a random position in a file, or even to determine the length of a file.
Almost all systems nowadays provide the necessary capabilities, so \.{DVI}
format has been designed to work most efficiently with modern operating systems.
@* Generic font file format.
The ``generic font'' (\.{GF}) input files that \.{GFtoDVI} must deal with
have a structure that was inspired by \.{DVI} format, although the
operation codes are quite different in most cases. The term {\sl
generic\/} indicates that this file format doesn't match the conventions
of any name-brand manufacturer; but it is easy to convert \.{GF} files to
the special format required by almost all digital phototypesetting
equipment. There's a strong analogy between the \.{DVI} files written by
\TeX\ and the \.{GF} files written by \MF; and, in fact, the reader will
notice that many of the paragraphs below are identical to their
counterparts in the description of \.{DVI} already given. The following
description has been lifted almost verbatim from the program for \MF.
A \.{GF} file is a stream of 8-bit bytes that may be
regarded as a series of commands in a machine-like language. The first
byte of each command is the operation code, and this code is followed by
zero or more bytes that provide parameters to the command. The parameters
themselves may consist of several consecutive bytes; for example, the
`|boc|' (beginning of character) command has six parameters, each of
which is four bytes long. Parameters are usually regarded as nonnegative
integers; but four-byte-long parameters can be either positive or
negative, hence they range in value from $-2^{31}$ to $2^{31}-1$.
As in \.{DVI} files, numbers that occupy
more than one byte position appear in BigEndian order,
and negative numbers appear in two's complement notation.
A \.{GF} file consists of a ``preamble,'' followed by a sequence of one or
more ``characters,'' followed by a ``postamble.'' The preamble is simply a
|pre| command, with its parameters that introduce the file; this must come
first. Each ``character'' consists of a |boc| command, followed by any
number of other commands that specify ``black'' pixels,
followed by an |eoc| command. The characters appear in the order that \MF\
generated them. If we ignore no-op commands (which are allowed between any
two commands in the file), each |eoc| command is immediately followed by a
|boc| command, or by a |post| command; in the latter case, there are no
more characters in the file, and the remaining bytes form the postamble.
Further details about the postamble will be explained later.
Some parameters in \.{GF} commands are ``pointers.'' These are four-byte
quantities that give the location number of some other byte in the file;
the first file byte is number~0, then comes number~1, and so on.
@ The \.{GF} format is intended to be both compact and easily interpreted
by a machine. Compactness is achieved by making most of the information
relative instead of absolute. When a \.{GF}-reading program reads the
commands for a character, it keeps track of two quantities: (a)~the current
column number,~|m|; and (b)~the current row number,~|n|. These are 32-bit
signed integers, although most actual font formats produced from \.{GF}
files will need to curtail this vast range because of practical
limitations. (\MF\ output will never allow $\vert m\vert$ or $\vert
n\vert$ to get extremely large, but the \.{GF} format tries to be more general.)
How do \.{GF}'s row and column numbers correspond to the conventions
of \TeX\ and \MF? Well, the ``reference point'' of a character, in \TeX's
view, is considered to be at the lower left corner of the pixel in row~0
and column~0. This point is the intersection of the baseline with the left
edge of the type; it corresponds to location $(0,0)$ in \MF\ programs.
Thus the pixel in \.{GF} row~0 and column~0 is \MF's unit square, comprising the
region of the plane whose coordinates both lie between 0 and~1. The
pixel in \.{GF} row~|n| and column~|m| consists of the points whose \MF\
coordinates |(x,y)| satisfy |m<=x<=m+1| and |n<=y<=n+1|. Negative values of
|m| and~|x| correspond to columns of pixels {\sl left\/} of the reference
point; negative values of |n| and~|y| correspond to rows of pixels {\sl
below\/} the baseline.
Besides |m| and |n|, there's also a third aspect of the current
state, namely the @!|paint_switch|, which is always either \\{black} or
\\{white}. Each \\{paint} command advances |m| by a specified amount~|d|,
and blackens the intervening pixels if |paint_switch=black|; then
the |paint_switch| changes to the opposite state. \.{GF}'s commands are
designed so that |m| will never decrease within a row, and |n| will never
increase within a character; hence there is no way to whiten a pixel that
has been blackened.
@ Here is a list of all the commands that may appear in a \.{GF} file. Each
command is specified by its symbolic name (e.g., |boc|), its opcode byte
(e.g., 67), and its parameters (if any). The parameters are followed
by a bracketed number telling how many bytes they occupy; for example,
`|d[2]|' means that parameter |d| is two bytes long.
\yskip\hang|paint_0| 0. This is a \\{paint} command with |d=0|; it does
nothing but change the |paint_switch| from \\{black} to \\{white} or vice~versa.
\yskip\hang\\{paint\_1} through \\{paint\_63} (opcodes 1 to 63).
These are \\{paint} commands with |d=1| to~63, defined as follows: If
|paint_switch=black|, blacken |d|~pixels of the current row~|n|,
in columns |m| through |m+d-1| inclusive. Then, in any case,
complement the |paint_switch| and advance |m| by~|d|.
\yskip\hang|paint1| 64 |d[1]|. This is a \\{paint} command with a specified
value of~|d|; \MF\ uses it to paint when |64<=d<256|.
\yskip\hang|paint2| 65 |d[2]|. Same as |paint1|, but |d|~can be as high
as~65535.
\yskip\hang|paint3| 66 |d[3]|. Same as |paint1|, but |d|~can be as high
as $2^{24}-1$. \MF\ never needs this command, and it is hard to imagine
anybody making practical use of it; surely a more compact encoding will be
desirable when characters can be this large. But the command is there,
anyway, just in case.
\yskip\hang|boc| 67 |c[4]| |p[4]| |min_m[4]| |max_m[4]| |min_n[4]|
|max_n[4]|. Beginning of a character: Here |c| is the character code, and
|p| points to the previous character beginning (if any) for characters having
this code number modulo 256. (The pointer |p| is |-1| if there was no
prior character with an equivalent code.) The values of registers |m| and |n|
defined by the instructions that follow for this character must
satisfy |min_m<=m<=max_m| and |min_n<=n<=max_n|. (The values of |max_m| and
|min_n| need not be the tightest bounds possible.) When a \.{GF}-reading
program sees a |boc|, it can use |min_m|, |max_m|, |min_n|, and |max_n| to
initialize the bounds of an array. Then it sets |m:=min_m|, |n:=max_n|, and
|paint_switch:=white|.
\yskip\hang|boc1| 68 |c[1]| |@!del_m[1]| |max_m[1]| |@!del_n[1]| |max_n[1]|.
Same as |boc|, but |p| is assumed to be~$-1$; also |del_m=max_m-min_m|
and |del_n=max_n-min_n| are given instead of |min_m| and |min_n|.
The one-byte parameters must be between 0 and 255, inclusive.
\ (This abbreviated |boc| saves 19~bytes per character, in common cases.)
\yskip\hang|eoc| 69. End of character: All pixels blackened so far
constitute the pattern for this character. In particular, a completely
blank character might have |eoc| immediately following |boc|.
\yskip\hang|skip0| 70. Decrease |n| by 1 and set |m:=min_m|,
|paint_switch:=white|. \ (This finishes one row and begins another,
ready to whiten the leftmost pixel in the new row.)
\yskip\hang|skip1| 71 |d[1]|. Decrease |n| by |d+1|, set |m:=min_m|, and set
|paint_switch:=white|. This is a way to produce |d| all-white rows.
\yskip\hang|skip2| 72 |d[2]|. Same as |skip1|, but |d| can be as large
as 65535.
\yskip\hang|skip3| 73 |d[3]|. Same as |skip1|, but |d| can be as large
as $2^{24}-1$. \MF\ obviously never needs this command.
\yskip\hang|new_row_0| 74. Decrease |n| by 1 and set |m:=min_m|,
|paint_switch:=black|. \ (This finishes one row and begins another,
ready to {\sl blacken\/} the leftmost pixel in the new row.)
\yskip\hang|@!new_row_1| through |@!new_row_164| (opcodes 75 to 238). Same as
|new_row_0|, but with |m:=min_m+1| through |min_m+164|, respectively.
\yskip\hang|xxx1| 239 |k[1]| |x[k]|. This command is undefined in
general; it functions as a $(k+2)$-byte |no_op| unless special \.{GF}-reading
programs are being used. \MF\ generates \\{xxx} commands when encountering
a \&{special} string; this occurs in the \.{GF} file only between
characters, after the preamble, and before the postamble. However,
\\{xxx} commands might appear within characters,
in \.{GF} files generated by other
processors. It is recommended that |x| be a string having the form of a
keyword followed by possible parameters relevant to that keyword.
\yskip\hang|xxx2| 240 |k[2]| |x[k]|. Like |xxx1|, but |0<=k<65536|.
\yskip\hang|xxx3| 241 |k[3]| |x[k]|. Like |xxx1|, but |0<=k<@t$2^{24}$@>|.
\MF\ uses this when sending a \&{special} string whose length exceeds~255.
\yskip\hang|xxx4| 242 |k[4]| |x[k]|. Like |xxx1|, but |k| can be
ridiculously large; |k| mustn't be negative.
\yskip\hang|yyy| 243 |y[4]|. This command is undefined in general;
it functions as a 5-byte |no_op| unless special \.{GF}-reading programs
are being used. \MF\ puts |scaled| numbers into |yyy|'s, as a
result of \&{numspecial} commands; the intent is to provide numeric
parameters to \\{xxx} commands that immediately precede.
\yskip\hang|no_op| 244. No operation, do nothing. Any number of |no_op|'s
may occur between \.{GF} commands, but a |no_op| cannot be inserted between
a command and its parameters or between two parameters.
\yskip\hang|char_loc| 245 |c[1]| |dx[4]| |dy[4]| |w[4]| |p[4]|.
This command will appear only in the postamble, which will be explained shortly.
\yskip\hang|@!char_loc0| 246 |c[1]| |@!dm[1]| |w[4]| |p[4]|.
Same as |char_loc|, except that |dy| is assumed to be zero, and the value
of~|dx| is taken to be |65536*dm|, where |0<=dm<256|.
\yskip\hang|pre| 247 |i[1]| |k[1]| |x[k]|.
Beginning of the preamble; this must come at the very beginning of the
file. Parameter |i| is an identifying number for \.{GF} format, currently
131. The other information is merely commentary; it is not given
special interpretation like \\{xxx} commands are. (Note that \\{xxx}
commands may immediately follow the preamble, before the first |boc|.)
\yskip\hang|post| 248. Beginning of the postamble, see below.
\yskip\hang|post_post| 249. Ending of the postamble, see below.
\yskip\noindent Commands 250--255 are undefined at the present time.
@d gf_id_byte=131 {identifies the kind of \.{GF} files described here}
@ Here are the opcodes that \.{GFtoDVI} actually refers to.
@d paint_0=0 {beginning of the \\{paint} commands}
@d paint1=64 {move right a given number of columns, then
black${}\swap{}$white}
@d paint2=65 {ditto, with potentially larger number of columns}
@d paint3=66 {ditto, with potentially excessive number of columns}
@d boc=67 {beginning of a character}
@d boc1=68 {abbreviated |boc|}
@d eoc=69 {end of a character}
@d skip0=70 {skip no blank rows}
@d skip1=71 {skip over blank rows}
@d skip2=72 {skip over lots of blank rows}
@d skip3=73 {skip over a huge number of blank rows}
@d new_row_0=74 {move down one row and then right}
@d xxx1=239 {for \&{special} strings}
@d xxx2=240 {for somewhat long \&{special} strings}
@d xxx3=241 {for extremely long \&{special} strings}
@d xxx4=242 {for incredibly long \&{special} strings}
@d yyy=243 {for \&{numspecial} numbers}
@d no_op=244 {no operation}
@ The last character in a \.{GF} file is followed by `|post|'; this command
introduces the postamble, which summarizes important facts that \MF\ has
accumulated. The postamble has the form
$$\vbox{\halign{\hbox{#\hfil}\cr
|post| |p[4]| |@!ds[4]| |@!cs[4]| |@!hppp[4]| |@!vppp[4]|
|@!min_m[4]| |@!max_m[4]| |@!min_n[4]| |@!max_n[4]|\cr
$\langle\,$character locators$\,\rangle$\cr
|post_post| |q[4]| |i[1]| 223's$[{\G}4]$\cr}}$$
Here |p| is a pointer to the byte following the final |eoc| in the file
(or to the byte following the preamble, if there are no characters);
it can be used to locate the beginning of \\{xxx} commands
that might have preceded the postamble. The |ds| and |cs| parameters
@^design size@> @^check sum@>
give the design size and check sum, respectively, of the font (see the
description of \.{TFM} format below).
Parameters |hppp| and |vppp| are the ratios of
pixels per point, horizontally and vertically, expressed as |scaled| integers
(i.e., multiplied by $2^{16}$); they can be used to correlate the font
with specific device resolutions, magnifications, and ``at sizes.'' Then
come |min_m|, |max_m|, |min_n|, and |max_n|, which bound the values that
registers |m| and~|n| assume in all characters in this \.{GF} file.
(These bounds need not be the best possible; |max_m| and |min_n| may, on the
other hand, be tighter than the similar bounds in |boc| commands. For
example, some character may have |min_n=-100| in its |boc|, but it might
turn out that |n| never gets lower than |-50| in any character; then
|min_n| can have any value |<=-50|. If there are no characters in the file,
it's possible to have |min_m>max_m| and/or |min_n>max_n|.)
@ Character locators are introduced by |char_loc| commands,
which specify a character residue~|c|, character escapements (|dx,dy|),
a character width~|w|, and a pointer~|p|
to the beginning of that character. (If two or more characters have the
same code~|c| modulo 256, only the last will be indicated; the others can be
located by following backpointers. Characters whose codes differ by a
multiple of 256 are assumed to share the same font metric information,
hence the \.{TFM} file contains only residues of character codes modulo~256.
This convention is intended for oriental languages, when there are many
character shapes but few distinct widths.)
@^oriental characters@>@^Chinese characters@>@^Japanese characters@>
The character escapements (|dx,dy|) are the values of \MF's \&{chardx}
and \&{chardy} parameters; they are in units of |scaled| pixels;
i.e., |dx| is in horizontal pixel units times $2^{16}$, and |dy| is in
vertical pixel units times $2^{16}$. This is the intended amount of
displacement after typesetting the character; for \.{DVI} files, |dy|
should be zero, but other document file formats allow nonzero vertical
escapement.
The character width~|w| duplicates the information in the \.{TFM} file; it
is $2^{24}$ times the ratio of the true width to the font's design size.
The backpointer |p| points to the character's |boc|, or to the first of
a sequence of consecutive \\{xxx} or |yyy| or |no_op| commands that
immediately precede the |boc|, if such commands exist; such ``special''
commands essentially belong to the characters, while the special commands
after the final character belong to the postamble (i.e., to the font
as a whole). This convention about |p| applies also to the backpointers
in |boc| commands, even though it wasn't explained in the description
of~|boc|. @^backpointers@>
Pointer |p| might be |-1| if the character exists in the \.{TFM} file
but not in the \.{GF} file. This unusual situation can arise in \MF\ output
if the user had |proofing<0| when the character was being shipped out,
but then made |proofing>=0| in order to get a \.{GF} file.
@ The last part of the postamble, following the |post_post| byte that
signifies the end of the character locators, contains |q|, a pointer to the
|post| command that started the postamble. An identification byte, |i|,
comes next; this currently equals~131, as in the preamble.
The |i| byte is followed by four or more bytes that are all equal to
the decimal number 223 (i.e., @'337 in octal). \MF\ puts out four to seven of
these trailing bytes, until the total length of the file is a multiple of
four bytes, since this works out best on machines that pack four bytes per
word; but any number of 223's is allowed, as long as there are at least four
of them. In effect, 223 is a sort of signature that is added at the very end.
@^Fuchs, David Raymond@>
This curious way to finish off a \.{GF} file makes it feasible for
\.{GF}-reading programs to find the postamble first, on most computers,
even though \MF\ wants to write the postamble last. Most operating
systems permit random access to individual words or bytes of a file, so
the \.{GF} reader can start at the end and skip backwards over the 223's
until finding the identification byte. Then it can back up four bytes, read
|q|, and move to byte |q| of the file. This byte should, of course,
contain the value 248 (|post|); now the postamble can be read, so the
\.{GF} reader can discover all the information needed for individual characters.
Unfortunately, however, standard \PASCAL\ does not include the ability to
@^system dependencies@>
access a random position in a file, or even to determine the length of a file.
Almost all systems nowadays provide the necessary capabilities, so \.{GF}
format has been designed to work most efficiently with modern operating systems.
But if \.{GF} files have to be processed under the restrictions of standard
\PASCAL, one can simply read them from front to back. This will
be adequate for most applications. However, the postamble-first approach
would facilitate a program that merges two \.{GF} files, replacing data
from one that is overridden by corresponding data in the other.
@* Extensions to the generic format.
The \\{xxx} and \\{yyy} instructions understood by \.{GFtoDVI} will be
listed now, so that we have a convenient reference to all of the special
assumptions made later.
Each special instruction begins with an \\{xxx} command, which consists of
either a keyword by itself, or a keyword followed by a space followed
by arguments. This \\{xxx} command may then be followed by \\{yyy}
commands that are understood to be arguments.
The keywords of special instructions that are intended to be used at
many different sites should be published as widely as possible in order
to minimize conflicts. The first person to establish a keyword presumably
has a right to define it; \.{GFtoDVI}, as the first program
to use extended \.{GF} commands, has the opportunity of choosing any
keywords it likes, and the responsibility of choosing reasonable ones.
Since labels are expected to account for the bulk of extended commands
in typical uses of \MF, the ``null'' keyword has been set aside to
denote a labeling command.
@ Here then are the special commands of \.{GFtoDVI}.
\def\string{$\langle\,$string$\,\rangle$}
\def\okpagebreak{\vfil\penalty-100\vfilneg}
\smallskip\hang\noindent
\.{\SP n}\string\ $x$ $y$. Here \.n denotes the type of label; the
characters \.1, \.2, \.3,~\.4 respectively denote labels forced to be
at the top, left, right, or bottom of their dot, and the characters
\.5, \.6, \.7,~\.8 stand for the same possibilities but with no dot printed.
The character \.0 instructs \.{GFtoDVI} to choose one of the first four
possibilities, if there's no overlap with other labels or dots, otherwise
an ``overflow'' entry is placed at the right of the figure. The character
\./ is the same as \.0 except that overflow entries are not produced. The
label itself is the \string\ that follows. \MF\ coordinates of the
point that is to receive this label are given by arguments $x$ and~$y$,
in units of scaled pixels. (These arguments appear in \\{yyy} commands.)
(Precise definitions of the size and positioning of labels, and of the
notion of ``conflicting'' labels, will be given later.)
\smallskip\hang\noindent
\.{rule} $x_1$ $y_1$ $x_2$ $y_2$. This command draws a line from
$(x_1,y_1)$ to $(x_2,y_2)$ in \MF\ coordinates. The present implementation
does this only if the line is either horizontal or vertical, or if its
slope matches the slope of the slant font.
\smallskip\hang\noindent
\.{title\SP}\string. This command (which is output by \MF\
when it sees a ``title statement'') specifies a string that will appear
at the top of the next proofsheet to be output by \.{GFtoDVI}.
If more than one title is given, they will appear in sequence; titles
should be short enough to fit on a single line.
\smallskip\hang\noindent
\.{titlefont\SP}\string. This command, and the other font-naming
commands below, must precede the first |boc| in the \.{GF} file.
It overrides the current font used to
typeset the titles at the top of proofsheets. \.{GFtoDVI} has default
fonts that will be used if none other are specified; the ``current'' title
font is initially the default title font.
\smallskip\hang\noindent
\.{titlefontarea\SP}\string. This command overrides the current
file area (or directory name) from which \.{GFtoDVI} will try to
find metric information for the title font.
\smallskip\hang\noindent
\.{titlefontat} $s$. This command overrides the current ``at size'' that
will be used for the title font. (See the discussion of font metric files
below, for the meaning of ``at size'' versus ``design size.'') The
value of~$s$ is given in units of scaled points.
\okpagebreak
\smallskip\hang\noindent
\.{labelfont\SP}\string. This command overrides the current font
used to typeset the labels that are superimposed on proof figures.
(The label font is fairly arbitrary, but it should be dark enough to
stand out when superimposed on gray pixels, and it should contain at
least the decimal digits and the characters `\.(', `\.)', `\.=', `\.+',
`\.-', `\.,', and `\..'.)
\smallskip\hang\noindent
\.{labelfontarea\SP}\string. This command overrides the current
file area (or directory name) from which \.{GFtoDVI} will try to
find metric information for the label font.
\smallskip\hang\noindent
\.{labelfontat} $s$. This command overrides the current ``at size'' that
will be used for the label font.
\okpagebreak
\smallskip\hang\noindent
\.{grayfont\SP}\string. This command overrides the current font
used to typeset the black pixels and the dots for labels. (Gray fonts
will be explained in detail later.)
@^gray fonts@>
\smallskip\hang\noindent
\.{grayfontarea\SP}\string. This command overrides the current
file area (or directory name) from which \.{GFtoDVI} will try to
find metric information for the gray font.
\smallskip\hang\noindent
\.{grayfontat} $s$. This command overrides the current ``at size'' that
will be used for the gray font.
\okpagebreak
\smallskip\hang\noindent
\.{slantfont\SP}\string. This command overrides the current font
used to typeset rules that are neither horizontal nor vertical. (Slant
fonts will be explained in detail later.)
@^slant fonts@>
\smallskip\hang\noindent
\.{slantfontarea\SP}\string. This command overrides the current
file area (or directory name) from which \.{GFtoDVI} will try to
find metric information for the slant font.
\smallskip\hang\noindent
\.{slantfontat} $s$. This command overrides the current ``at size'' that
will be used for the slant font.
\okpagebreak
\smallskip\hang\noindent
\.{rulethickness} $t$. This command overrides the current value used
for the thickness of rules. If the current value is negative, no rule
will be drawn; if the current value is zero, the rule thickness will
be specified by a parameter of the gray font. Each \.{rule} command
uses the rule thickness that is current at the time the command appears;
hence it is possible to get different thicknesses of rules on the same
figure. The value of $t$ is given in units of scaled points (\TeX's `\.{sp}').
At the beginning of each character the current rule thickness is zero.
\smallskip\hang\noindent
\.{offset} $x$ $y$. This command overrides the current offset values
that are added to all coordinates of a character being output; $x$ and
$y$ are given as scaled \MF\ coordinates. This simply has the effect
of repositioning the figures on the pages; the title line always appears
in the same place, but the figure can be moved up, down, left, or right.
At the beginning of each character the current offsets are zero.
\smallskip\hang\noindent
\.{xoffset} $x$. This command is output by \MF\ just before shipping out
a character whose $x$~offset is nonzero. \.{GFtoDVI} adds the specified
amount to the $x$ coordinates of all dots, labels, and rules
in the following character.
\smallskip\hang\noindent
\.{yoffset} $y$. This command is output by \MF\ just before shipping out
a character whose $y$~offset is nonzero. \.{GFtoDVI} adds the specified
amount to the $y$ coordinates of all dots, labels, and rules
in the following character.
@* Font metric data.
Before we can get into the meaty details of \.{GFtoDVI}, we need to
deal with yet another esoteric binary file format, since \.{GFtoDVI}
also does elementary typesetting operations. Therefore it has to
read important information about the fonts it will be using.
The following material (again copied almost verbatim from \TeX)
describes the contents of so-called \TeX\ font metric (\.{TFM}) files.
The idea behind \.{TFM} files is that typesetting routines
need a compact way to store the relevant information about
fonts, and computer centers need a compact way to store the
relevant information about several hundred fonts. \.{TFM} files are
compact, and most of the information they contain is highly relevant,
so they provide a solution to the problem. \.{GFtoDVI} uses only
four fonts, but interesting changes in its output will occur when
those fonts are varied.
The information in a \.{TFM} file appears in a sequence of 8-bit bytes.
Since the number of bytes is always a multiple of 4, we could
also regard the file as a sequence of 32-bit words; but \TeX\ uses the
byte interpretation, and so does \.{GFtoDVI}. The individual bytes
are considered to be unsigned numbers.
@ The first 24 bytes (6 words) of a \.{TFM} file contain twelve 16-bit
integers that give the lengths of the various subsequent portions
of the file. These twelve integers are, in order:
$$\vbox{\halign{\hfil#&$\null=\null$#\hfil\cr
|@!lf|&length of the entire file, in words;\cr
|@!lh|&length of the header data, in words;\cr
|@!bc|&smallest character code in the font;\cr
|@!ec|&largest character code in the font;\cr
|@!nw|&number of words in the width table;\cr
|@!nh|&number of words in the height table;\cr
|@!nd|&number of words in the depth table;\cr
|@!ni|&number of words in the italic correction table;\cr
|@!nl|&number of words in the lig/kern table;\cr
|@!nk|&number of words in the kern table;\cr
|@!ne|&number of words in the extensible character table;\cr
|@!np|&number of font parameter words.\cr}}$$
They are all nonnegative and less than $2^{15}$. We must have |bc-1<=ec<=255|,
and
$$\hbox{|lf=6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|.}$$
Note that a font may contain as many as 256 characters (if |bc=0| and |ec=255|),
and as few as 0 characters (if |bc=ec+1|). When two or more 8-bit bytes are
combined to form an integer of 16 or more bits, the bytes appear in
BigEndian order.
@^BigEndian order@>
@<Glob...@>=
@!lf,@!lh,@!bc,@!ec,@!nw,@!nh,@!nd,@!ni,@!nl,@!nk,@!ne,@!np:0..@'77777;
{subfile sizes}
@ The rest of the \.{TFM} file may be regarded as a sequence of ten data
arrays having the informal specification
$$\def\arr$[#1]#2${\&{array} $[#1]$ \&{of} #2}
\vbox{\halign{\hfil\\{#}&$\,:\,$\arr#\hfil\cr
header&|[0..lh-1]@t\\{stuff}@>|\cr
char\_info&|[bc..ec]char_info_word|\cr
width&|[0..nw-1]fix_word|\cr
height&|[0..nh-1]fix_word|\cr
depth&|[0..nd-1]fix_word|\cr
italic&|[0..ni-1]fix_word|\cr
lig\_kern&|[0..nl-1]lig_kern_command|\cr
kern&|[0..nk-1]fix_word|\cr
exten&|[0..ne-1]extensible_recipe|\cr
param&|[1..np]fix_word|\cr}}$$
The most important data type used here is a |@!fix_word|, which is
a 32-bit representation of a binary fraction. A |fix_word| is a signed
quantity, with the two's complement of the entire word used to represent
negation. Of the 32 bits in a |fix_word|, exactly 12 are to the left of the
binary point; thus, the largest |fix_word| value is $2048-2^{-20}$, and
the smallest is $-2048$. We will see below, however, that all but two of
the |fix_word| values must lie between $-16$ and $+16$.
@ The first data array is a block of header information, which contains
general facts about the font. The header must contain at least two words,
and for \.{TFM} files to be used with Xerox printing software it must
contain at least 18 words, allocated as described below. When different
kinds of devices need to be interfaced, it may be necessary to add further
words to the header block.
\yskip\hang|header[0]| is a 32-bit check sum that \.{GFtoDVI} will copy into the
\.{DVI} output file whenever it uses the font. Later on when the \.{DVI}
file is printed, possibly on another computer, the actual font that gets
used is supposed to have a check sum that agrees with the one in the
\.{TFM} file used by \.{GFtoDVI}. In this way, users will be warned about
potential incompatibilities. (However, if the check sum is zero in either
the font file or the \.{TFM} file, no check is made.) The actual relation
between this check sum and the rest of the \.{TFM} file is not important;
the check sum is simply an identification number with the property that
incompatible fonts almost always have distinct check sums.
@^check sum@>
\yskip\hang|header[1]| is a |fix_word| containing the design size of the
font, in units of \TeX\ points (7227 \TeX\ points = 254 cm). This number
must be at least 1.0; it is fairly arbitrary, but usually the design size
is 10.0 for a ``10 point'' font, i.e., a font that was designed to look
best at a 10-point size, whatever that really means. When a \TeX\ user
asks for a font `\.{at} $\delta$ \.{pt}', the effect is to override the
design size and replace it by $\delta$, and to multiply the $x$ and~$y$
coordinates of the points in the font image by a factor of $\delta$
divided by the design size. Similarly, specific sizes can be substituted
for the design size by \.{GFtoDVI} commands like `\.{titlefontat}'. {\sl
All other dimensions in the\/\ \.{TFM} file are |fix_word| numbers in
design-size units.} Thus, for example, the value of |param[6]|, one \.{em}
or \.{\\quad}, is often the |fix_word| value $2^{20}=1.0$, since many
fonts have a design size equal to one em. The other dimensions must be
less than 16 design-size units in absolute value; thus, |header[1]| and
|param[1]| are the only |fix_word| entries in the whole \.{TFM} file whose
first byte might be something besides 0 or 255. @^design size@>@^at size@>
\yskip\hang|header[2..11]|, if present, contains 40 bytes that identify
the character coding scheme. The first byte, which must be between 0 and
39, is the number of subsequent ASCII bytes actually relevant in this
string, which is intended to specify what character-code-to-symbol
convention is present in the font. Examples are \.{ASCII} for standard
ASCII, \.{TeX text} for fonts like \.{cmr10} and \.{cmti9}, \.{TeX math
extension} for \.{cmex10}, \.{XEROX text} for Xerox fonts, \.{GRAPHIC} for
special-purpose non-alphabetic fonts, \.{GFGRAY} for \.{GFtoDVI}'s
gray fonts, \.{GFSLANT} for \.{GFtoDVI}'s slant fonts, \.{UNSPECIFIED} for
the default case when there is no information. Parentheses should not
appear in this name. (Such a string is said to be in {\mc BCPL} format.)
@^coding scheme@>@^gray fonts@>@^slant fonts@>
\yskip\hang|header[12..@twhatever@>]| might also be present.
@ Next comes the |char_info| array, which contains one |char_info_word|
per character. Each |char_info_word| contains six fields packed into
four bytes as follows.
\yskip\hang first byte: |@!width_index| (8 bits)\par
\hang second byte: |@!height_index| (4 bits) times 16, plus |@!depth_index|
(4~bits)\par
\hang third byte: |@!italic_index| (6 bits) times 4, plus |@!tag|
(2~bits)\par
\hang fourth byte: |@!remainder| (8 bits)\par
\yskip\noindent
The actual width of a character is \\{width}|[width_index]|, in design-size
units; this is a device for compressing information, since many characters
have the same width. Since it is quite common for many characters
to have the same height, depth, or italic correction, the \.{TFM} format
imposes a limit of 16 different heights, 16 different depths, and
64 different italic corrections.
Incidentally, the relation $\\{width}[0]=\\{height}[0]=\\{depth}[0]=
\\{italic}[0]=0$ should always hold, so that an index of zero implies a
value of zero. The |width_index| should never be zero unless the
character does not exist in the font, since a character is valid if and
only if it lies between |bc| and |ec| and has a nonzero |width_index|.
@ The |tag| field in a |char_info_word| has four values that explain how to
interpret the |remainder| field.
\yskip\hang|tag=0| (|no_tag|) means that |remainder| is unused.\par
\hang|tag=1| (|lig_tag|) means that this character has a ligature/kerning
program starting at |lig_kern[remainder]|.\par
\hang|tag=2| (|list_tag|) means that this character is part of a chain of
characters of ascending sizes, and not the largest in the chain. The
|remainder| field gives the character code of the next larger character.\par
\hang|tag=3| (|ext_tag|) means that this character code represents an
extensible character, i.e., a character that is built up of smaller pieces
so that it can be made arbitrarily large. The pieces are specified in
|@!exten[remainder]|.\par
@d no_tag=0 {vanilla character}
@d lig_tag=1 {character has a ligature/kerning program}
@d list_tag=2 {character has a successor in a charlist}
@d ext_tag=3 {character is extensible}
@ The |lig_kern| array contains instructions in a simple programming language
that explains what to do for special letter pairs. Each word in this array is a
|@!lig_kern_command| of four bytes.
\yskip\hang first byte: |skip_byte|, indicates that this is the final program
step if the byte is 128 or more, otherwise the next step is obtained by
skipping this number of intervening steps.\par
\hang second byte: |next_char|, ``if |next_char| follows the current character,
then perform the operation and stop, otherwise continue.''\par
\hang third byte: |op_byte|, indicates a ligature step if less than~128,
a kern step otherwise.\par
\hang fourth byte: |remainder|.\par
\yskip\noindent
In a kern step, an
additional space equal to |kern[256*(op_byte-128)+remainder]| is inserted
between the current character and |next_char|. This amount is
often negative, so that the characters are brought closer together
by kerning; but it might be positive.
There are eight kinds of ligature steps, having |op_byte| codes $4a+2b+c$ where
$0\le a\le b+c$ and $0\le b,c\le1$. The character whose code is
|remainder| is inserted between the current character and |next_char|;
then the current character is deleted if $b=0$, and |next_char| is
deleted if $c=0$; then we pass over $a$~characters to reach the next
current character (which may have a ligature/kerning program of its own).
If the very first instruction of the |lig_kern| array has |skip_byte=255|,
the |next_char| byte is the so-called right boundary character of this font;
the value of |next_char| need not lie between |bc| and~|ec|.
If the very last instruction of the |lig_kern| array has |skip_byte=255|,
there is a special ligature/kerning program for a left boundary character,
beginning at location |256*op_byte+remainder|.
The interpretation is that \TeX\ puts implicit boundary characters
before and after each consecutive string of characters from the same font.
These implicit characters do not appear in the output, but they can affect
ligatures and kerning.
If the very first instruction of a character's |lig_kern| program has
|skip_byte>128|, the program actually begins in location
|256*op_byte+remainder|. This feature allows access to large |lig_kern|
arrays, because the first instruction must otherwise
appear in a location |<=255|.
Any instruction with |skip_byte>128| in the |lig_kern| array must have
|256*op_byte+remainder<nl|. If such an instruction is encountered during
normal program execution, it denotes an unconditional halt; no ligature
or kerning command is performed.
@d stop_flag=128 {value indicating `\.{STOP}' in a lig/kern program}
@d kern_flag=128 {op code for a kern step}
@ Extensible characters are specified by an |@!extensible_recipe|, which
consists of four bytes called |@!top|, |@!mid|, |@!bot|, and |@!rep| (in this
order). These bytes are the character codes of individual pieces used to
build up a large symbol. If |top|, |mid|, or |bot| are zero, they are not
present in the built-up result. For example, an extensible vertical line is
like an extensible bracket, except that the top and bottom pieces are missing.
@ The final portion of a \.{TFM} file is the |param| array, which is another
sequence of |fix_word| values.
\yskip\hang|param[1]=@!slant| is the amount of italic slant.
For example, |slant=.25| means that when you go
up one unit, you also go .25 units to the right. The |slant| is a pure
number; it's the only |fix_word| other than the design size itself that is
not scaled by the design size.
\hang|param[2]=space| is the normal spacing between words in text.
Note that character |" "| in the font need not have anything to do with
blank spaces.
\hang|param[3]=space_stretch| is the amount of glue stretching between words.
\hang|param[4]=space_shrink| is the amount of glue shrinking between words.
\hang|param[5]=x_height| is the height of letters for which accents don't
have to be raised or lowered.
\hang|param[6]=quad| is the size of one em in the font.
\hang|param[7]=extra_space| is the amount added to |param[2]| at the
ends of sentences.
When the character coding scheme is \.{GFGRAY} or \.{GFSLANT}, the font is
supposed to contain an additional parameter called
|default_rule_thickness|. Other special parameters go with other coding
schemes.
@* Input from binary files.
We have seen that \.{GF} and \.{DVI} and \.{TFM} files are sequences of
8-bit bytes. The bytes appear physically in what is called a `|packed
file of 0..255|' in \PASCAL\ lingo.
Packing is system dependent, and many \PASCAL\ systems fail to implement
such files in a sensible way (at least, from the viewpoint of producing
good production software). For example, some systems treat all
byte-oriented files as text, looking for end-of-line marks and such
things. Therefore some system-dependent code is often needed to deal with
binary files, even though most of the program in this section of
\.{GFtoDVI} is written in standard \PASCAL.
@^system dependencies@>
One common way to solve the problem is to consider files of |integer|
numbers, and to convert an integer in the range $-2^{31}\L x<2^{31}$ to
a sequence of four bytes $(a,b,c,d)$ using the following code, which
avoids the controversial integer division of negative numbers:
$$\vbox{\halign{#\hfil\cr
|if x>=0 then a:=x div @'100000000|\cr
|else begin x:=(x+@'10000000000)+@'10000000000; a:=x div @'100000000+128;|\cr
\quad|end|;\cr
|x:=x mod @'100000000;|\cr
|b:=x div @'200000; x:=x mod @'200000;|\cr
|c:=x div @'400; d:=x mod @'400;|\cr}}$$
The four bytes are then kept in a buffer and output one by one. (On 36-bit
computers, an additional division by 16 is necessary at the beginning.
Another way to separate an integer into four bytes is to use/abuse
\PASCAL's variant records, storing an integer and retrieving bytes that are
packed in the same place; {\sl caveat implementor!\/}) It is also desirable
in some cases to read a hundred or so integers at a time, maintaining a
larger buffer.
We shall stick to simple \PASCAL\ in this program, for reasons of clarity,
even if such simplicity is sometimes unrealistic.
@<Types ...@>=
@!eight_bits=0..255; {unsigned one-byte quantity}
@!byte_file=packed file of eight_bits; {files that contain binary data}
@ The program deals with three binary file variables: |gf_file| is the main
input file that we are converting into a document; |dvi_file| is the main
output file that will specify that document; and |tfm_file| is
the current font metric file from which character-width information is
being read.
@<Glob...@>=
@!gf_file:byte_file; {the character data we are reading}
@!dvi_file:byte_file; {the typesetting instructions we are writing}
@!tfm_file:byte_file; {a font metric file}
@ To prepare these files for input or output, we |reset| or |rewrite|
them. An extension of \PASCAL\ is needed, since we want to associate
it with external files whose names are specified dynamically (i.e., not
known at compile time). The following code assumes that `|reset(f,s)|' and
`|rewrite(f,s)|' do this, when |f| is a file variable and |s| is a string
variable that specifies the file name.
@^system dependencies@>
@p procedure open_gf_file; {prepares to read packed bytes in |gf_file|}
begin reset(gf_file,name_of_file);
cur_loc:=0;
end;
@#
procedure open_tfm_file; {prepares to read packed bytes in |tfm_file|}
begin reset(tfm_file,name_of_file);
end;
@#
procedure open_dvi_file; {prepares to write packed bytes in |dvi_file|}
begin rewrite(dvi_file,name_of_file);
end;
@ If you looked carefully at the preceding code, you probably asked,
``What are |cur_loc| and |name_of_file|?'' Good question. They are global
variables: The integer |cur_loc| tells which byte of the input file will
be read next, and the string |name_of_file| will be set to the current
file name before the file-opening procedures are called.
@<Glob...@>=
@!cur_loc:integer; {current byte number in |gf_file|}
@!name_of_file:packed array[1..file_name_size] of char; {external file name}
@ It turns out to be convenient to read four bytes at a time, when we are
inputting from \.{TFM} files. The input goes into global variables
|b0|, |b1|, |b2|, and |b3|, with |b0| getting the first byte and |b3|
the fourth.
@<Glob...@>=
@!b0,@!b1,@!b2,@!b3: eight_bits; {four bytes input at once}
@ The |read_tfm_word| procedure sets |b0| through |b3| to the next
four bytes in the current \.{TFM} file.
@^system dependencies@>
@p procedure read_tfm_word;
begin read(tfm_file,b0); read(tfm_file,b1);
read(tfm_file,b2); read(tfm_file,b3);
end;
@ We shall use another set of simple functions to read the next byte or
bytes from |gf_file|. There are four possibilities, each of which is
treated as a separate function in order to minimize the overhead for
subroutine calls.
@^system dependencies@>
@p function get_byte:integer; {returns the next byte, unsigned}
var b:eight_bits;
begin if eof(gf_file) then get_byte:=0
else begin read(gf_file,b); incr(cur_loc); get_byte:=b;
end;
end;
@#
function get_two_bytes:integer; {returns the next two bytes, unsigned}
var a,@!b:eight_bits;
begin read(gf_file,a); read(gf_file,b);
cur_loc:=cur_loc+2;
get_two_bytes:=a*256+b;
end;
@#
function get_three_bytes:integer; {returns the next three bytes, unsigned}
var a,@!b,@!c:eight_bits;
begin read(gf_file,a); read(gf_file,b); read(gf_file,c);
cur_loc:=cur_loc+3;
get_three_bytes:=(a*256+b)*256+c;
end;
@#
function signed_quad:integer; {returns the next four bytes, signed}
var a,@!b,@!c,@!d:eight_bits;
begin read(gf_file,a); read(gf_file,b); read(gf_file,c); read(gf_file,d);
cur_loc:=cur_loc+4;
if a<128 then signed_quad:=((a*256+b)*256+c)*256+d
else signed_quad:=(((a-256)*256+b)*256+c)*256+d;
end;
@* Reading the font information.
Now let's get down to brass tacks and consider the more substantial
routines that actually convert \.{TFM} data into a form suitable for
computation. The routines in this part of the program have been borrowed
from \TeX, with slight changes, since \.{GFtoDVI} has to do some of the
things that \TeX\ does.
The \.{TFM} data is stored in a large array called
|font_info|. Each item of |font_info| is a |memory_word|; the |fix_word|
data gets converted into |scaled| entries, while everything else goes into
words of type |four_quarters|. (These data structures are special cases of
the more general memory words of \TeX. On some machines it is necessary to
define |min_quarterword=-128| and |max_quarterword=127| in order to pack
four quarterwords into a single word.)
@^system dependencies@>
@d min_quarterword=0 {change this to allow efficient packing, if necessary}
@d max_quarterword=255 {ditto}
@d qi(#)==#+min_quarterword
{to put an |eight_bits| item into a quarterword}
@d qo(#)==#-min_quarterword
{to take an |eight_bits| item out of a quarterword}
@d title_font=1
@d label_font=2
@d gray_font=3
@d slant_font=4
@d logo_font=5
@d non_char==qi(256)
@d non_address==font_mem_size
@<Types ...@>=
@!font_index = 0..font_mem_size;
@!quarterword = min_quarterword..max_quarterword; {1/4 of a word}
@!four_quarters = packed record@;@/
@!b0:quarterword;
@!b1:quarterword;
@!b2:quarterword;
@!b3:quarterword;
end;
@!memory_word = record@;@/
case boolean of
true: (@!sc:scaled);
false: (@!qqqq:four_quarters);
end;
@!internal_font_number=title_font..logo_font;
@ Besides |font_info|, there are also a number of index arrays that point
into it, so that we can locate width and height information, etc. For
example, the |char_info| data for character |c| in font |f| will be in
|font_info[char_base[f]+c].qqqq|; and if |w| is the |width_index| part of
this word (the |b0| field), the width of the character is
|font_info[width_base[f]+w].sc|. (These formulas assume that
|min_quarterword| has already been added to |w|, but not to |c|.)
@<Glob...@>=
@!font_info:array[font_index] of memory_word; {the font metric data}
@!fmem_ptr:font_index; {first unused word of |font_info|}
@!font_check:array[internal_font_number] of four_quarters; {check sum}
@!font_size:array[internal_font_number] of scaled; {``at'' size}
@!font_dsize:array[internal_font_number] of scaled; {``design'' size}
@!font_bc:array[internal_font_number] of eight_bits;
{beginning (smallest) character code}
@!font_ec:array[internal_font_number] of eight_bits;
{ending (largest) character code}
@!char_base:array[internal_font_number] of integer;
{base addresses for |char_info|}
@!width_base:array[internal_font_number] of integer;
{base addresses for widths}
@!height_base:array[internal_font_number] of integer;
{base addresses for heights}
@!depth_base:array[internal_font_number] of integer;
{base addresses for depths}
@!italic_base:array[internal_font_number] of integer;
{base addresses for italic corrections}
@!lig_kern_base:array[internal_font_number] of integer;
{base addresses for ligature/kerning programs}
@!kern_base:array[internal_font_number] of integer;
{base addresses for kerns}
@!exten_base:array[internal_font_number] of integer;
{base addresses for extensible recipes}
@!param_base:array[internal_font_number] of integer;
{base addresses for font parameters}
@!bchar_label:array[internal_font_number] of font_index;
{start of |lig_kern| program for left boundary character,
|non_address| if there is none}
@!font_bchar:array[internal_font_number] of min_quarterword..non_char;
{right boundary character, |non_char| if there is none}
@ @<Set init...@>=
fmem_ptr:=0;
@ Of course we want to define macros that suppress the detail of how font
information is actually packed, so that we don't have to write things like
$$\hbox{|font_info[width_base[f]+font_info[char_base[f]+c].qqqq.b0].sc|}$$
too often. The \.{WEB} definitions here make |char_info(f)(c)| the
|four_quarters| word of font information corresponding to character
|c| of font |f|. If |q| is such a word, |char_width(f)(q)| will be
the character's width; hence the long formula above is at least
abbreviated to
$$\hbox{|char_width(f)(char_info(f)(c))|.}$$
In practice we will try to fetch |q| first and look at several of its
fields at the same time.
The italic correction of a character will be denoted by
|char_italic(f)(q)|, so it is analogous to |char_width|. But we will get
at the height and depth in a slightly different way, since we usually want
to compute both height and depth if we want either one. The value of
|height_depth(q)| will be the 8-bit quantity
$$b=|height_index|\times16+|depth_index|,$$ and if |b| is such a byte we
will write |char_height(f)(b)| and |char_depth(f)(b)| for the height and
depth of the character |c| for which |q=char_info(f)(c)|. Got that?
The tag field will be called |char_tag(q)|; and the remainder byte will be
called |rem_byte(q)|.
@d char_info_end(#)==#].qqqq
@d char_info(#)==font_info[char_base[#]+char_info_end
@d char_width_end(#)==#.b0].sc
@d char_width(#)==font_info[width_base[#]+char_width_end
@d char_exists(#)==(#.b0>min_quarterword)
@d char_italic_end(#)==(qo(#.b2)) div 4].sc
@d char_italic(#)==font_info[italic_base[#]+char_italic_end
@d height_depth(#)==qo(#.b1)
@d char_height_end(#)==(#) div 16].sc
@d char_height(#)==font_info[height_base[#]+char_height_end
@d char_depth_end(#)==# mod 16].sc
@d char_depth(#)==font_info[depth_base[#]+char_depth_end
@d char_tag(#)==((qo(#.b2)) mod 4)
@d skip_byte(#)==qo(#.b0)
@d next_char(#)==#.b1
@d op_byte(#)==qo(#.b2)
@d rem_byte(#)==#.b3
@ Here are some macros that help process ligatures and kerns.
We write |char_kern(f)(j)| to find the amount of kerning specified by
kerning command~|j| in font~|f|.
@d lig_kern_start(#)==lig_kern_base[#]+rem_byte {beginning of lig/kern program}
@d lig_kern_restart_end(#)==256*(op_byte(#))+rem_byte(#)
@d lig_kern_restart(#)==lig_kern_base[#]+lig_kern_restart_end
@d char_kern_end(#)==256*(op_byte(#)-128)+rem_byte(#)].sc
@d char_kern(#)==font_info[kern_base[#]+char_kern_end
@ Font parameters are referred to as |slant(f)|, |space(f)|, etc.
@d param_end(#)==param_base[#]].sc
@d param(#)==font_info[#+param_end
@d slant==param(1) {slant to the right, per unit distance upward}
@d space==param(2) {normal space between words}
@d x_height==param(5) {one ex}
@d default_rule_thickness==param(8) {thickness of rules}
@ Here is the subroutine that inputs the information on |tfm_file|, assuming
that the file has just been reset. Parameter~|f| tells which metric file is
being read (either |title_font| or |label_font| or |gray_font| or |slant_font|
or |logo_font|); parameter~|s| is the ``at'' size, which will be
substituted for the design size if it is positive.
This routine does only limited checking of the validity of the file,
because another program (\.{TFtoPL}) is available to diagnose errors in
the rare case that something is amiss.
@d bad_tfm=11 {label for |read_font_info|}
@d abend==goto bad_tfm {do this when the \.{TFM} data is wrong}
@p procedure read_font_info(@!f:integer;@!s:scaled); {input a \.{TFM} file}
label done,bad_tfm;
var k:font_index; {index into |font_info|}
@!lf,@!lh,@!bc,@!ec,@!nw,@!nh,@!nd,@!ni,@!nl,@!nk,@!ne,@!np:0..65535;
{sizes of subfiles}
@!bch_label:integer; {left boundary label for ligatures}
@!bchar:0..256; {right boundary character for ligatures}
@!qw:four_quarters;@!sw:scaled; {accumulators}
@!z:scaled; {the design size or the ``at'' size}
@!alpha:integer;@!beta:1..16;
{auxiliary quantities used in fixed-point multiplication}
begin @<Read and check the font data; |abend| if the \.{TFM} file is
malformed; otherwise |goto done|@>;
bad_tfm: print_nl('Bad TFM file for');
@.Bad TFM file...@>
case f of
title_font:abort('titles!');
label_font:abort('labels!');
gray_font:abort('pixels!');
slant_font:abort('slants!');
logo_font:abort('METAFONT logo!');
end; {there are no other cases}
done: {it might be good to close |tfm_file| now}
end;
@ @<Read and check...@>=
@<Read the {\.{TFM}} size fields@>;
@<Use size fields to allocate font information@>;
@<Read the {\.{TFM}} header@>;
@<Read character data@>;
@<Read box dimensions@>;
@<Read ligature/kern program@>;
@<Read extensible character recipes@>;
@<Read font parameters@>;
@<Make final adjustments and |goto done|@>
@ @d read_two_halves_end(#)==#:=b2*256+b3
@d read_two_halves(#)==read_tfm_word; #:=b0*256+b1; read_two_halves_end
@<Read the {\.{TFM}} size fields@>=
begin read_two_halves(lf)(lh);
read_two_halves(bc)(ec);
if (bc>ec+1)or(ec>255) then abend;
if bc>255 then {|bc=256| and |ec=255|}
begin bc:=1; ec:=0;
end;
read_two_halves(nw)(nh);
read_two_halves(nd)(ni);
read_two_halves(nl)(nk);
read_two_halves(ne)(np);
if lf<>6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np then abend;
end
@ The preliminary settings of the index variables |width_base|,
|lig_kern_base|, |kern_base|, and |exten_base| will be corrected later by
subtracting |min_quarterword| from them; and we will subtract 1 from
|param_base| too. It's best to forget about such anomalies until later.
@<Use size fields to allocate font information@>=
lf:=lf-6-lh; {|lf| words should be loaded into |font_info|}
if np<8 then lf:=lf+8-np; {at least eight parameters will appear}
if fmem_ptr+lf>font_mem_size then abort('No room for TFM file!');
@.No room for TFM file@>
char_base[f]:=fmem_ptr-bc;
width_base[f]:=char_base[f]+ec+1;
height_base[f]:=width_base[f]+nw;
depth_base[f]:=height_base[f]+nh;
italic_base[f]:=depth_base[f]+nd;
lig_kern_base[f]:=italic_base[f]+ni;
kern_base[f]:=lig_kern_base[f]+nl;
exten_base[f]:=kern_base[f]+nk;
param_base[f]:=exten_base[f]+ne
@ Only the first two words of the header are needed by \.{GFtoDVI}.
@d store_four_quarters(#)==
begin read_tfm_word;
qw.b0:=qi(b0); qw.b1:=qi(b1); qw.b2:=qi(b2); qw.b3:=qi(b3);
#:=qw;
end
@<Read the {\.{TFM}} header@>=
begin if lh<2 then abend;
store_four_quarters(font_check[f]);
read_tfm_word;
if b0>127 then abend; {design size must be positive}
z:=((b0*256+b1)*256+b2)*16+(b3 div 16);
if z<unity then abend;
while lh>2 do
begin read_tfm_word; decr(lh); {ignore the rest of the header}
end;
font_dsize[f]:=z;
if s>0 then z:=s;
font_size[f]:=z;
end
@ @<Read character data@>=
for k:=fmem_ptr to width_base[f]-1 do
begin store_four_quarters(font_info[k].qqqq);
if (b0>=nw)or(b1 div @'20>=nh)or(b1 mod @'20>=nd)or
(b2 div 4>=ni) then abend;
case b2 mod 4 of
lig_tag: if b3>=nl then abend;
ext_tag: if b3>=ne then abend;
no_tag,list_tag: do_nothing;
end; {there are no other cases}
end
@ A |fix_word| whose four bytes are $(b0,b1,b2,b3)$ from left to right
represents the number
$$x=\left\{\vcenter{\halign{$#$,\hfil\qquad&if $#$\hfil\cr
b_1\cdot2^{-4}+b_2\cdot2^{-12}+b_3\cdot2^{-20}&b_0=0;\cr
-16+b_1\cdot2^{-4}+b_2\cdot2^{-12}+b_3\cdot2^{-20}&b_0=255.\cr}}\right.$$
(No other choices of |b0| are allowed, since the magnitude of a number in
design-size units must be less than 16.) We want to multiply this
quantity by the integer~|z|, which is known to be less than $2^{27}$. Let
$\alpha=16z$. If $|z|<2^{23}$, the individual multiplications $b\cdot z$,
$c\cdot z$, $d\cdot z$ cannot overflow; otherwise we will divide |z| by 2,
4, 8, or 16, to obtain a multiplier less than $2^{23}$, and we can
compensate for this later. If |z| has thereby been replaced by
$|z|^\prime=|z|/2^e$, let $\beta=2^{4-e}$; we shall compute
$$\lfloor(b_1+b_2\cdot2^{-8}+b_3\cdot2^{-16})\,z^\prime/\beta\rfloor$$
if $a=0$, or the same quantity minus $\alpha$ if $a=255$.
@d store_scaled(#)==begin read_tfm_word;
sw:=(((((b3*z)div@'400)+(b2*z))div@'400)+(b1*z))div beta;
if b0=0 then #:=sw@+else if b0=255 then #:=sw-alpha@+else abend;
end
@<Read box dimensions@>=
begin @<Replace |z| by $|z|^\prime$ and compute $\alpha,\beta$@>;
for k:=width_base[f] to lig_kern_base[f]-1 do
store_scaled(font_info[k].sc);
if font_info[width_base[f]].sc<>0 then abend; {\\{width}[0] must be zero}
if font_info[height_base[f]].sc<>0 then abend; {\\{height}[0] must be zero}
if font_info[depth_base[f]].sc<>0 then abend; {\\{depth}[0] must be zero}
if font_info[italic_base[f]].sc<>0 then abend; {\\{italic}[0] must be zero}
end
@ @<Replace |z|...@>=
begin alpha:=16*z; beta:=16;
while z>=@'40000000 do
begin z:=z div 2; beta:=beta div 2;
end;
end
@ @d check_byte_range(#)==begin if (#<bc)or(#>ec) then abend@+end
@<Read ligature/kern program@>=
begin bch_label:=@'77777; bchar:=256;
if nl>0 then
begin for k:=lig_kern_base[f] to kern_base[f]-1 do
begin store_four_quarters(font_info[k].qqqq);
if b0>stop_flag then
begin if 256*b2+b3>=nl then abend;
if b0=255 then if k=lig_kern_base[f] then bchar:=b1;
end
else begin if b1<>bchar then check_byte_range(b1);
if b2<kern_flag then check_byte_range(b3)
else if 256*(b2-128)+b3>=nk then abend;
end;
end;
if b0=255 then bch_label:=256*b2+b3;
end;
for k:=kern_base[f] to exten_base[f]-1 do
store_scaled(font_info[k].sc);
end
@ @<Read extensible character recipes@>=
for k:=exten_base[f] to param_base[f]-1 do
begin store_four_quarters(font_info[k].qqqq);
if b0<>0 then check_byte_range(b0);
if b1<>0 then check_byte_range(b1);
if b2<>0 then check_byte_range(b2);
check_byte_range(b3);
end
@ @<Read font parameters@>=
begin for k:=1 to np do
if k=1 then {the |slant| parameter is a pure number}
begin read_tfm_word;
if b0>127 then sw:=b0-256@+else sw:=b0;
sw:=sw*@'400+b1; sw:=sw*@'400+b2;
font_info[param_base[f]].sc:=(sw*@'20)+(b3 div@'20);
end
else store_scaled(font_info[param_base[f]+k-1].sc);
for k:=np+1 to 8 do font_info[param_base[f]+k-1].sc:=0;
end
@ Now to wrap it up, we have checked all the necessary things about the \.{TFM}
file, and all we need to do is put the finishing touches on the data for
the new font.
@d adjust(#)==#[f]:=qo(#[f])
{correct for the excess |min_quarterword| that was added}
@<Make final adjustments...@>=
font_bc[f]:=bc; font_ec[f]:=ec;
if bch_label<nl then bchar_label[f]:=bch_label+lig_kern_base[f]
else bchar_label[f]:=non_address;
font_bchar[f]:=qi(bchar);
adjust(width_base); adjust(lig_kern_base);
adjust(kern_base); adjust(exten_base);
decr(param_base[f]);
fmem_ptr:=fmem_ptr+lf; goto done
@* The string pool.
\.{GFtoDVI} remembers strings by putting them into an array called
|str_pool|. The |str_start| array tells where each string starts in the pool.
@<Types ...@>=
@!pool_pointer = 0..pool_size; {for variables that point into |str_pool|}
@!str_number = 0..max_strings; {for variables that point into |str_start|}
@ As new strings enter, we keep track of the storage currently used, by
means of two global variables called |pool_ptr| and |str_ptr|. These are
periodically reset to their initial values when we move from one character
to another, because most strings are of only temporary interest.
@<Glob...@>=
@!str_pool:packed array[pool_pointer] of ASCII_code; {the characters}
@!str_start : array[str_number] of pool_pointer; {the starting pointers}
@!pool_ptr : pool_pointer; {first unused position in |str_pool|}
@!str_ptr : str_number; {start of the current string being created}
@!init_str_ptr:str_number; {|str_ptr| setting when a new character starts}
@ Several of the elementary string operations are performed using \.{WEB}
macros instead of using \PASCAL\ procedures, because many of the
operations are done quite frequently and we want to avoid the
overhead of procedure calls. For example, here is
a simple macro that computes the length of a string.
@.WEB@>
@d length(#)==(str_start[#+1]-str_start[#]) {the number of characters
in string number \#}
@ Strings are created by appending character codes to |str_pool|.
The macro called |append_char|, defined here, does not check to see if the
value of |pool_ptr| has gotten too high; that test is supposed to be
made before |append_char| is used.
To test if there is room to append |l| more characters to |str_pool|,
we shall write |str_room(l)|, which aborts \.{GFtoDVI} and gives an
apologetic error message if there isn't enough room.
@d append_char(#) == {put |ASCII_code| \# at the end of |str_pool|}
begin str_pool[pool_ptr]:=#; incr(pool_ptr);
end
@d str_room(#) == {make sure that the pool hasn't overflowed}
begin if pool_ptr+# > pool_size then
abort('Too many strings!');
@.Too many strings@>
end
@ Once a sequence of characters has been appended to |str_pool|, it
officially becomes a string when the function |make_string| is called.
This function returns the identification number of the new string as its
value.
@p function make_string : str_number; {current string enters the pool}
begin if str_ptr=max_strings then
abort('Too many labels!');
@.Too many labels@>
incr(str_ptr); str_start[str_ptr]:=pool_ptr;
make_string:=str_ptr-1;
end;
@ The first strings in the string pool are the keywords that \.{GFtoDVI}
recognizes in the \\{xxx} commands of a \.{GF} file. They are entered
into |str_pool| by means of a tedious bunch of assignment statements,
together with calls on the |first_string| subroutine.
@d init_str0(#)==first_string(#)
@d init_str1(#)==buffer[1]:=#; init_str0
@d init_str2(#)==buffer[2]:=#; init_str1
@d init_str3(#)==buffer[3]:=#; init_str2
@d init_str4(#)==buffer[4]:=#; init_str3
@d init_str5(#)==buffer[5]:=#; init_str4
@d init_str6(#)==buffer[6]:=#; init_str5
@d init_str7(#)==buffer[7]:=#; init_str6
@d init_str8(#)==buffer[8]:=#; init_str7
@d init_str9(#)==buffer[9]:=#; init_str8
@d init_str10(#)==buffer[10]:=#; init_str9
@d init_str11(#)==buffer[11]:=#; init_str10
@d init_str12(#)==buffer[12]:=#; init_str11
@d init_str13(#)==buffer[13]:=#; init_str12
@d longest_keyword=13
@p procedure first_string(@!c:integer);
begin if str_ptr<>c then abort('?'); {internal consistency check}
@.?@>
while l>0 do
begin append_char(buffer[l]); decr(l);
end;
incr(str_ptr); str_start[str_ptr]:=pool_ptr;
end;
@ @<Glob...@>=
@!l:integer; {length of string being made by |first_string|}
@ Here are the tedious assignments just promised.
String number 0 is the empty string.
@d null_string=0 {the empty keyword}
@d area_code=4 {add to font code for the `\.{area}' keywords}
@d at_code=8 {add to font code for the `\.{at}' keywords}
@d rule_code=13 {code for the keyword `\.{rule}'}
@d title_code=14 {code for the keyword `\.{title}'}
@d rule_thickness_code=15 {code for the keyword `\.{rulethickness}'}
@d offset_code=16 {code for the keyword `\.{offset}'}
@d x_offset_code=17 {code for the keyword `\.{xoffset}'}
@d y_offset_code=18 {code for the keyword `\.{yoffset}'}
@d max_keyword=18 {largest keyword code number}
@<Initialize the strings@>=
str_ptr:=0; pool_ptr:=0; str_start[0]:=0;@/
l:=0; init_str0(null_string);@/
l:=9; init_str9("t")("i")("t")("l")("e")("f")("o")("n")("t")(title_font);@/
l:=9; init_str9("l")("a")("b")("e")("l")("f")("o")("n")("t")(label_font);@/
l:=8; init_str8("g")("r")("a")("y")("f")("o")("n")("t")(gray_font);@/
l:=9; init_str9("s")("l")("a")("n")("t")("f")("o")("n")("t")(slant_font);@/
l:=13; init_str13("t")("i")("t")("l")("e")
("f")("o")("n")("t")("a")("r")("e")("a")(title_font+area_code);@/
l:=13; init_str13("l")("a")("b")("e")("l")
("f")("o")("n")("t")("a")("r")("e")("a")(label_font+area_code);@/
l:=12; init_str12("g")("r")("a")("y")
("f")("o")("n")("t")("a")("r")("e")("a")(gray_font+area_code);@/
l:=13; init_str13("s")("l")("a")("n")("t")
("f")("o")("n")("t")("a")("r")("e")("a")(slant_font+area_code);@/
l:=11; init_str11("t")("i")("t")("l")("e")
("f")("o")("n")("t")("a")("t")(title_font+at_code);@/
l:=11; init_str11("l")("a")("b")("e")("l")
("f")("o")("n")("t")("a")("t")(label_font+at_code);@/
l:=10; init_str10("g")("r")("a")("y")
("f")("o")("n")("t")("a")("t")(gray_font+at_code);@/
l:=11; init_str11("s")("l")("a")("n")("t")
("f")("o")("n")("t")("a")("t")(slant_font+at_code);@/
l:=4; init_str4("r")("u")("l")("e")(rule_code);@/
l:=5; init_str5("t")("i")("t")("l")("e")(title_code);@/
l:=13; init_str13("r")("u")("l")("e")
("t")("h")("i")("c")("k")("n")("e")("s")("s")(rule_thickness_code);@/
l:=6; init_str6("o")("f")("f")("s")("e")("t")(offset_code);@/
l:=7; init_str7("x")("o")("f")("f")("s")("e")("t")(x_offset_code);@/
l:=7; init_str7("y")("o")("f")("f")("s")("e")("t")(y_offset_code);@/
@ We will also find it useful to have the following strings. (The names of
default fonts will presumably be different at different sites.)
@^system dependencies@>
@^default fonts@>
@d gf_ext=max_keyword+1 {string number for `\.{.gf}'}
@d dvi_ext=max_keyword+2 {string number for `\.{.dvi}'}
@d tfm_ext=max_keyword+3 {string number for `\.{.tfm}'}
@d page_header=max_keyword+4 {string number for `\.{\ \ Page\ }'}
@d char_header=max_keyword+5 {string number for `\.{\ \ Character\ }'}
@d ext_header=max_keyword+6 {string number for `\.{\ \ Ext\ }'}
@d left_quotes=max_keyword+7 {string number for `\.{\ \ ``}'}
@d right_quotes=max_keyword+8 {string number for `\.{''}'}
@d equals_sign=max_keyword+9 {string number for `\.{ = }'}
@d plus_sign=max_keyword+10 {string number for `\.{ + (}'}
@d default_title_font=max_keyword+11
{string number for the default |title_font|}
@d default_label_font=max_keyword+12
{string number for the default |label_font|}
@d default_gray_font=max_keyword+13 {string number for the default |gray_font|}
@d logo_font_name=max_keyword+14 {string number for the font with \MF\ logo}
@d small_logo=max_keyword+15 {string number for `\.{METAFONT}'}
@d home_font_area=max_keyword+16 {string number for system-dependent font area}
@<Initialize the strings@>=
l:=3; init_str3(".")("g")("f")(gf_ext);@/
l:=4; init_str4(".")("d")("v")("i")(dvi_ext);@/
l:=4; init_str4(".")("t")("f")("m")(tfm_ext);@/
l:=7; init_str7(" ")(" ")("P")("a")("g")("e")(" ")(page_header);@/
l:=12; init_str12(" ")(" ")("C")("h")("a")("r")("a")("c")("t")("e")("r")(" ")
(char_header);@/
l:=6; init_str6(" ")(" ")("E")("x")("t")(" ")(ext_header);@/
l:=4; init_str4(" ")(" ")("`")("`")(left_quotes);@/
l:=2; init_str2("'")("'")(right_quotes);@/
l:=3; init_str3(" ")("=")(" ")(equals_sign);@/
l:=4; init_str4(" ")("+")(" ")("(")(plus_sign);@/
l:=4; init_str4("c")("m")("r")("8")(default_title_font);@/
l:=6; init_str6("c")("m")("t")("t")("1")("0")(default_label_font);@/
l:=4; init_str4("g")("r")("a")("y")(default_gray_font);@/
l:=5; init_str5("l")("o")("g")("o")("8")(logo_font_name);@/
l:=8; init_str8("M")("E")("T")("A")("F")("O")("N")("T")(small_logo);
@ If an \\{xxx} command has just been encountered in the \.{GF} file,
the following procedure interprets its keyword. More precisely, we assume
that |cur_gf| contains an op-code byte just read from the \.{GF} file,
where |xxx1<=cur_gf<=no_op|. The |interpret_xxx| procedure will read the
rest of the command, in the following way:
\smallskip
\item{1)} If |cur_gf| is |no_op| or |yyy|, or if it's an \\{xxx} command with
an unknown keyword, the bytes are simply read and ignored, and the
value |no_operation| is returned.
\item{2)} If |cur_gf| is an \\{xxx} command (either |xxx1| or $\cdots$
or |xxx4|), and if the associated string matches a keyword exactly,
the string number of that keyword is returned (e.g., |rule_thickness_code|).
\item{3)} If |cur_gf| is an \\{xxx} command whose string begins with
keyword and space, the string number of that keyword is returned, and
the remainder of the string is put into the string pool (where it will be
string number |cur_string|. Exception: If the keyword is |null_string|,
the character immediately following the blank space is put into the
global variable |label_type|, and the remaining characters go into the
string pool.
\smallskip\noindent
In all cases, |cur_gf| will then be reset to the op-code byte that
immediately follows the original command.
@d no_operation=max_keyword+1
@<Types ...@>=
@!keyword_code=null_string..no_operation;
@ @<Glob...@>=
@!cur_gf:eight_bits; {the byte most recently read from |gf_file|}
@!cur_string:str_number; {the string following a keyword and space}
@!label_type:eight_bits; {the character following a null keyword and space}
@ We will be using this procedure when reading the \.{GF} file just
after the preamble and just after |eoc| commands.
@p function interpret_xxx:keyword_code;
label done,done1,not_found;
var @!k:integer; {number of bytes in an \\{xxx} command}
@!j:integer; {number of bytes read so far}
@!l:0..longest_keyword; {length of keyword to check}
@!m:keyword_code; {runs through the list of known keywords}
@!n1:0..longest_keyword; {buffered character being checked}
@!n2:pool_pointer; {pool character being checked}
@!c:keyword_code; {the result to return}
begin c:=no_operation; cur_string:=null_string;
case cur_gf of
no_op:goto done;
yyy:begin k:=signed_quad; goto done;
end;
xxx1:k:=get_byte;
xxx2:k:=get_two_bytes;
xxx3:k:=get_three_bytes;
xxx4:k:=signed_quad;
end; {there are no other cases}
@<Read the next |k| characters of the \.{GF} file;
change |c| and |goto done| if a keyword is recognized@>;
done: cur_gf:=get_byte; interpret_xxx:=c;
end;
@ @<Read the next |k|...@>=
j:=0;@+if k<2 then goto not_found;
loop@+ begin l:=j;
if j=k then goto done1;
if j=longest_keyword then goto not_found;
incr(j); buffer[j]:=get_byte;
if buffer[j]=" " then goto done1;
end;
done1:@<If the keyword in |buffer[1..l]| is known, change |c| and |goto done|@>;
not_found: while j<k do
begin incr(j); cur_gf:=get_byte;
end
@ @<If the keyword...@>=
for m:=null_string to max_keyword do if length(m)=l then
begin n1:=0; n2:=str_start[m];
while (n1<l)and(buffer[n1+1]=str_pool[n2]) do
begin incr(n1); incr(n2);
end;
if n1=l then
begin c:=m;
if m=null_string then
begin incr(j); label_type:=get_byte;
end;
str_room(k-j);
while j<k do
begin incr(j); append_char(get_byte);
end;
cur_string:=make_string; goto done;
end;
end
@ When an \\{xxx} command takes a numeric argument, |get_yyy| reads
that argument and puts the following byte into |cur_gf|.
@p function get_yyy:scaled;
var @!v:scaled; {value just read}
begin if cur_gf<>yyy then get_yyy:=0
else begin v:=signed_quad; cur_gf:=get_byte; get_yyy:=v;
end;
end;
@ A simpler method is used for special commands between |boc| and |eoc|,
since \.{GFtoDVI} doesn't even look at them.
@p procedure skip_nop;
label done;
var @!k:integer; {number of bytes in an \\{xxx} command}
@!j:integer; {number of bytes read so far}
begin case cur_gf of
no_op:goto done;
yyy:begin k:=signed_quad; goto done;
end;
xxx1:k:=get_byte;
xxx2:k:=get_two_bytes;
xxx3:k:=get_three_bytes;
xxx4:k:=signed_quad;
end; {there are no other cases}
for j:=1 to k do cur_gf:=get_byte;
done: cur_gf:=get_byte;
end;
@* File names.
It's time now to fret about file names. \.{GFtoDVI} uses the conventions of
\TeX\ and \MF\ to convert file names into strings that can be used to open
files. Three routines called |begin_name|, |more_name|, and |end_name| are
involved, so that the system-dependent parts of file naming conventions are
isolated from the system-independent ways in which file names are used.
(See the \TeX\ or \MF\ program listing for further explanation.)
@^system dependencies@>
@<Glob...@>=
@!cur_name:str_number; {name of file just scanned}
@!cur_area:str_number; {file area just scanned, or |null_string|}
@!cur_ext:str_number; {file extension just scanned, or |null_string|}
@ The file names we shall deal with for illustrative purposes have the
following structure: If the name contains `\.>' or `\.:', the file area
consists of all characters up to and including the final such character;
otherwise the file area is null. If the remaining file name contains
`\..', the file extension consists of all such characters from the first
remaining `\..' to the end, otherwise the file extension is null.
@^system dependencies@>
We can scan such file names easily by using two global variables that keep track
of the occurrences of area and extension delimiters:
@<Glob...@>=
@!area_delimiter:pool_pointer; {the most recent `\.>' or `\.:', if any}
@!ext_delimiter:pool_pointer; {the relevant `\..', if any}
@ Font metric files whose areas are not given
explicitly are assumed to appear in a standard system area called
|home_font_area|. This system area name will, of course, vary from place
to place. The program here sets it to `\.{TeXfonts:}'.
@^system dependencies@>
@.TeXfonts@>
@<Initialize the strings@>=
l:=9; init_str9("T")("e")("X")("f")("o")("n")("t")("s")(":")(home_font_area);@/
@ Here now is the first of the system-dependent routines for file name scanning.
@^system dependencies@>
@p procedure begin_name;
begin area_delimiter:=0; ext_delimiter:=0;
end;
@ And here's the second.
@^system dependencies@>
@p function more_name(@!c:ASCII_code):boolean;
begin if c=" " then more_name:=false
else begin if (c=">")or(c=":") then
begin area_delimiter:=pool_ptr; ext_delimiter:=0;
end
else if (c=".")and(ext_delimiter=0) then ext_delimiter:=pool_ptr;
str_room(1); append_char(c); {contribute |c| to the current string}
more_name:=true;
end;
end;
@ The third.
@^system dependencies@>
@p procedure end_name;
begin if str_ptr+3>max_strings then
abort('Too many strings!');
@.Too many strings@>
if area_delimiter=0 then cur_area:=null_string
else begin cur_area:=str_ptr; incr(str_ptr);
str_start[str_ptr]:=area_delimiter+1;
end;
if ext_delimiter=0 then
begin cur_ext:=null_string; cur_name:=make_string;
end
else begin cur_name:=str_ptr; incr(str_ptr);
str_start[str_ptr]:=ext_delimiter; cur_ext:=make_string;
end;
end;
@ Another system-dependent routine is needed to convert three strings
into the |name_of_file| value that is used to open files. The present code
allows both lowercase and uppercase letters in the file name.
@^system dependencies@>
@d append_to_name(#)==begin c:=#; incr(k);
if k<=file_name_size then name_of_file[k]:=xchr[c];
end
@p procedure pack_file_name(@!n,@!a,@!e:str_number);
var k:integer; {number of positions filled in |name_of_file|}
@!c: ASCII_code; {character being packed}
@!j:integer; {index into |str_pool|}
@!name_length:0..file_name_size; {number of characters packed}
begin k:=0;
for j:=str_start[a] to str_start[a+1]-1 do append_to_name(str_pool[j]);
for j:=str_start[n] to str_start[n+1]-1 do append_to_name(str_pool[j]);
for j:=str_start[e] to str_start[e+1]-1 do append_to_name(str_pool[j]);
if k<=file_name_size then name_length:=k@+else name_length:=file_name_size;
for k:=name_length+1 to file_name_size do name_of_file[k]:=' ';
end;
@ Now let's consider the routines by which \.{GFtoDVI} deals with file names
in a system-independent manner.
The global variable |job_name| contains the \.{GF} file name that is
being input. This name is extended by `\.{dvi}'
in order to make the name of the output file.
@<Glob...@>=
@!job_name:str_number; {principal file name}
@ The |start_gf| procedure prompts the user for the name of the generic
font file to be input. It opens the file, making sure that some input is
present; then it opens the output file.
Although this routine is system-independent, it should probably be
modified to take the file name from the command line (without an initial
prompt), on systems that permit such things.
@p procedure start_gf;
label found,done;
begin loop@+begin print_nl('GF file name: '); input_ln;
@.GF file name@>
buf_ptr:=0; buffer[line_length]:="?";
while buffer[buf_ptr]=" " do incr(buf_ptr);
if buf_ptr<line_length then
begin @<Scan the file name in the buffer@>;
if cur_ext=null_string then cur_ext:=gf_ext;
pack_file_name(cur_name,cur_area,cur_ext); open_gf_file;
if not eof(gf_file) then goto found;
print_nl('Oops... I can''t find file '); print(name_of_file);
@.Oops...@>
@.I can't find...@>
end;
end;
found:job_name:=cur_name; pack_file_name(job_name,null_string,dvi_ext);
open_dvi_file;
end;
@ @<Scan the file name in the buffer@>=
if buffer[line_length-1]="/" then
begin interaction:=true; decr(line_length);
end;
begin_name;
loop@+ begin if buf_ptr=line_length then goto done;
if not more_name(buffer[buf_ptr]) then goto done;
incr(buf_ptr);
end;
done:end_name
@ Special instructions found near the beginning of the \.{GF} file might
change the names, areas, and ``at'' sizes of the fonts that \.{GFtoDVI}
will be using. But when we reach the first |boc| instruction, we input
all of the \.{TFM} files. The global variable |interaction| is set |true|
if a |"/"| was removed at the end of the file name; this means that the
user will have a chance to issue special instructions online just before
the fonts are loaded.
@d check_fonts==@+if fonts_not_loaded then load_fonts
@<Glob...@>=
@!interaction:boolean; {is the user allowed to type specials online?}
@!fonts_not_loaded:boolean; {have the \.{TFM} files still not been input?}
@!font_name:array[internal_font_number] of str_number; {current font names}
@!font_area:array[internal_font_number] of str_number; {current font areas}
@!font_at:array[internal_font_number] of scaled; {current font ``at'' sizes}
@ @<Set init...@>=
interaction:=false; fonts_not_loaded:=true;
font_name[title_font]:=default_title_font;
font_name[label_font]:=default_label_font;
font_name[gray_font]:=default_gray_font;
font_name[slant_font]:=null_string;
font_name[logo_font]:=logo_font_name;
for k:=title_font to logo_font do
begin font_area[k]:=null_string; font_at[k]:=0;
end;
@ After the following procedure has been performed, there will be no
turning back; the fonts will have been firmly established in
\.{GFtoDVI}'s memory.
@<Declare the procedure called |load_fonts|@>=
procedure load_fonts;
label done,continue,found,not_found;
var @!f:internal_font_number;
@!i:four_quarters; {font information word}
@!j,@!k,@!v:integer; {registers for initializing font tables}
@!m:title_font..slant_font+area_code; {keyword found}
@!n1:0..longest_keyword; {buffered character being checked}
@!n2:pool_pointer; {pool character being checked}
begin if interaction then @<Get online special input@>;
fonts_not_loaded:=false;
for f:=title_font to logo_font do
if (f<>slant_font)or(length(font_name[f])>0) then
begin if length(font_area[f])=0 then font_area[f]:=home_font_area;
pack_file_name(font_name[f],font_area[f],tfm_ext);
open_tfm_file; read_font_info(f,font_at[f]);
if font_area[f]=home_font_area then font_area[f]:=null_string;
dvi_font_def(f); {put the font name in the \.{DVI} file}
end;
@<Initialize global variables that depend on the font data@>;
end;
@ @<Get online special input@>=
loop@+ begin not_found: print_nl('Special font substitution: ');
@.Special font subst...@>
continue: input_ln;
if line_length=0 then goto done;
@<Search buffer for valid keyword; if successful, |goto found|@>;
print('Please say, e.g., "grayfont foo" or "slantfontarea baz".');
goto not_found;
found: @<Update the font name or area@>;
print('OK; any more? '); goto continue;
end;
done:
@ @<Search buffer for valid keyword; if successful, |goto found|@>=
buf_ptr:=0; buffer[line_length]:=" ";
while buffer[buf_ptr]<>" " do incr(buf_ptr);
for m:=title_font to slant_font+area_code do if length(m)=buf_ptr then
begin n1:=0; n2:=str_start[m];
while (n1<buf_ptr)and(buffer[n1]=str_pool[n2]) do
begin incr(n1); incr(n2);
end;
if n1=buf_ptr then goto found;
end
@ @<Update the font name or area@>=
incr(buf_ptr); str_room(line_length-buf_ptr);
while buf_ptr<line_length do
begin append_char(buffer[buf_ptr]); incr(buf_ptr);
end;
if m>area_code then font_area[m-area_code]:=make_string
else begin font_name[m]:=make_string; font_area[m]:=null_string;
font_at[m]:=0;
end;
init_str_ptr:=str_ptr
@* Shipping pages out.
The following routines are used to write the \.{DVI} file. They have
been copied from \TeX, but simplified; we don't have to handle
nearly as much generality as \TeX\ does.
Statistics about the entire set of pages that will be shipped out must be
reported in the \.{DVI} postamble. The global variables |total_pages|,
|max_v|, |max_h|, and |last_bop| are used to record this information.
@<Glob...@>=
@!total_pages:integer; {the number of pages that have been shipped out}
@!max_v:scaled; {maximum height-plus-depth of pages shipped so far}
@!max_h:scaled; {maximum width of pages shipped so far}
@!last_bop:integer; {location of previous |bop| in the \.{DVI} output}
@ @<Set init...@>=
total_pages:=0; max_v:=0; max_h:=0; last_bop:=-1;
@ The \.{DVI} bytes are output to a buffer instead of being written directly
to the output file. This makes it possible to reduce the overhead of
subroutine calls.
The output buffer is divided into two parts of equal size; the bytes found
in |dvi_buf[0..half_buf-1]| constitute the first half, and those in
|dvi_buf[half_buf..dvi_buf_size-1]| constitute the second. The global
variable |dvi_ptr| points to the position that will receive the next
output byte. When |dvi_ptr| reaches |dvi_limit|, which is always equal
to one of the two values |half_buf| or |dvi_buf_size|, the half buffer that
is about to be invaded next is sent to the output and |dvi_limit| is
changed to its other value. Thus, there is always at least a half buffer's
worth of information present, except at the very beginning of the job.
Bytes of the \.{DVI} file are numbered sequentially starting with 0;
the next byte to be generated will be number |dvi_offset+dvi_ptr|.
@<Types ...@>=
@!dvi_index=0..dvi_buf_size; {an index into the output buffer}
@ Some systems may find it more efficient to make |dvi_buf| a |packed|
array, since output of four bytes at once may be facilitated.
@^system dependencies@>
@<Glob...@>=
@!dvi_buf:array[dvi_index] of eight_bits; {buffer for \.{DVI} output}
@!half_buf:dvi_index; {half of |dvi_buf_size|}
@!dvi_limit:dvi_index; {end of the current half buffer}
@!dvi_ptr:dvi_index; {the next available buffer address}
@!dvi_offset:integer; {|dvi_buf_size| times the number of times the
output buffer has been fully emptied}
@ Initially the buffer is all in one piece; we will output half of it only
after it first fills up.
@<Set init...@>=
half_buf:=dvi_buf_size div 2; dvi_limit:=dvi_buf_size; dvi_ptr:=0;
dvi_offset:=0;
@ The actual output of |dvi_buf[a..b]| to |dvi_file| is performed by calling
|write_dvi(a,b)|. It is safe to assume that |a| and |b+1| will both be
multiples of 4 when |write_dvi(a,b)| is called; therefore it is possible on
many machines to use efficient methods to pack four bytes per word and to
output an array of words with one system call.
@^system dependencies@>
@p procedure write_dvi(@!a,@!b:dvi_index);
var k:dvi_index;
begin for k:=a to b do write(dvi_file,dvi_buf[k]);
end;
@ To put a byte in the buffer without paying the cost of invoking a procedure
each time, we use the macro |dvi_out|.
@d dvi_out(#)==@+begin dvi_buf[dvi_ptr]:=#; incr(dvi_ptr);
if dvi_ptr=dvi_limit then dvi_swap;
end
@p procedure dvi_swap; {outputs half of the buffer}
begin if dvi_limit=dvi_buf_size then
begin write_dvi(0,half_buf-1); dvi_limit:=half_buf;
dvi_offset:=dvi_offset+dvi_buf_size; dvi_ptr:=0;
end
else begin write_dvi(half_buf,dvi_buf_size-1); dvi_limit:=dvi_buf_size;
end;
end;
@ Here is how we clean out the buffer when \TeX\ is all through; |dvi_ptr|
will be a multiple of~4.
@<Empty the last bytes out of |dvi_buf|@>=
if dvi_limit=half_buf then write_dvi(half_buf,dvi_buf_size-1);
if dvi_ptr>0 then write_dvi(0,dvi_ptr-1)
@ The |dvi_four| procedure outputs four bytes in two's complement notation,
without risking arithmetic overflow.
@p procedure dvi_four(@!x:integer);
begin if x>=0 then dvi_out(x div @'100000000)
else begin x:=x+@'10000000000;
x:=x+@'10000000000;
dvi_out((x div @'100000000) + 128);
end;
x:=x mod @'100000000; dvi_out(x div @'200000);
x:=x mod @'200000; dvi_out(x div @'400);
dvi_out(x mod @'400);
end;
@ Here's a procedure that outputs a font definition.
@d select_font(#)==dvi_out(fnt_num_0+#) {set current font to \#}
@p procedure dvi_font_def(@!f:internal_font_number);
var k:integer; {index into |str_pool|}
begin dvi_out(fnt_def1);
dvi_out(f);@/
dvi_out(qo(font_check[f].b0));
dvi_out(qo(font_check[f].b1));
dvi_out(qo(font_check[f].b2));
dvi_out(qo(font_check[f].b3));@/
dvi_four(font_size[f]);
dvi_four(font_dsize[f]);@/
dvi_out(length(font_area[f]));
dvi_out(length(font_name[f]));
@<Output the font name whose internal number is |f|@>;
end;@/
@t\4@>@<Declare the procedure called |load_fonts|@>@;
@ @<Output the font name whose internal number is |f|@>=
for k:=str_start[font_area[f]] to str_start[font_area[f]+1]-1 do
dvi_out(str_pool[k]);
for k:=str_start[font_name[f]] to str_start[font_name[f]+1]-1 do
dvi_out(str_pool[k])
@ The |typeset| subroutine typesets any eight-bit character.
@p procedure typeset(@!c:eight_bits);
begin if c>=128 then dvi_out(set1);
dvi_out(c);
end;
@ The |dvi_scaled| subroutine takes a |real| value |x| and outputs
a decimal approximation to |x/unity|, correct to one decimal place.
@p procedure dvi_scaled(@!x:real);
var @!n:integer; {an integer approximation to |10*x/unity|}
@!m:integer; {the integer part of the answer}
@!k:integer; {the number of digits in |m|}
begin n:=round(x/6553.6);
if n<0 then
begin dvi_out("-"); n:=-n;
end;
m:=n div 10; k:=0;
repeat incr(k); buffer[k]:=(m mod 10)+"0"; m:=m div 10;
until m=0;
repeat dvi_out(buffer[k]); decr(k);
until k=0;
if n mod 10 <> 0 then
begin dvi_out("."); dvi_out((n mod 10)+"0");
end;
end;
@ At the end of the program, we must finish things off by writing the
post\-amble. An integer variable~|k| will be declared for use by this routine.
@<Finish the \.{DVI} file and |goto final_end|@>=
begin dvi_out(post); {beginning of the postamble}
dvi_four(last_bop); last_bop:=dvi_offset+dvi_ptr-5; {|post| location}
dvi_four(25400000); dvi_four(473628672); {conversion ratio for sp}
dvi_four(1000); {magnification factor}
dvi_four(max_v); dvi_four(max_h);@/
dvi_out(0); dvi_out(3); {`\\{max\_push}' is said to be 3}@/
dvi_out(total_pages div 256); dvi_out(total_pages mod 256);@/
if not fonts_not_loaded then
for k:=title_font to logo_font do
if length(font_name[k])>0 then dvi_font_def(k);
dvi_out(post_post); dvi_four(last_bop); dvi_out(dvi_id_byte);@/
k:=4+((dvi_buf_size-dvi_ptr) mod 4); {the number of 223's}
while k>0 do
begin dvi_out(223); decr(k);
end;
@<Empty the last bytes out of |dvi_buf|@>;
goto final_end;
end
@* Rudimentary typesetting.
One of \.{GFtoDVI}'s little duties is to be a mini-\TeX: It must be able
to typeset the equivalent of `\.{\\hbox\{}$\langle$string$\rangle$\.\}' for
a given string of ASCII characters, using either the title font or the
label font.
The |hbox| procedure does this. The width, height, and depth of the
box defined by string~|s| in font~|f| are computed in global variables
|box_width|, |box_height|, and |box_depth|.
The task would be trivial if it weren't for ligatures and kerns, which
are implemented here in full generality. (Infinite looping is possible
if the \.{TFM} file is malformed; \.{TFtoPL} will diagnose such problems.)
We assume that |" "| is a space character; character code @'40 will not
be typeset unless it is accessed via a ligature.
If parameter |send_it| is |false|, we merely want to know the box dimensions.
Otherwise typesetting commands are also sent to
the \.{DVI} file; we assume in this case that font |f| has already been
selected in the \.{DVI} file as the current font.
@d set_cur_r==if k<end_k then cur_r:=qi(str_pool[k])
else cur_r:=bchar
@p procedure hbox(@!s:str_number;@!f:internal_font_number;@!send_it:boolean);
label continue, done;
var @!k,@!end_k,@!max_k:pool_pointer; {indices into |str_pool|}
@!i,@!j:four_quarters; {font information words}
@!cur_l:0..256; {character to the left of the ``cursor''}
@!cur_r:min_quarterword..non_char; {character to the right of the ``cursor''}
@!bchar:min_quarterword..non_char; {right boundary character}
@!stack_ptr:0..lig_lookahead; {number of entries on |lig_stack|}
@!l:font_index; {pointer to lig/kern instruction}
@!kern_amount:scaled; {extra space to be typeset}
@!hd:eight_bits; {height and depth indices for a character}
@!x:scaled; {temporary register}
@!save_c:ASCII_code; {character temporarily blanked out}
begin box_width:=0; box_height:=0; box_depth:=0;@/
k:=str_start[s]; max_k:=str_start[s+1];
save_c:=str_pool[max_k]; str_pool[max_k]:=" ";
while k<max_k do
begin if str_pool[k]=" " then @<Typeset a space in font |f| and advance~|k|@>
else begin end_k:=k;
repeat incr(end_k); until str_pool[end_k]=" ";
kern_amount:=0; cur_l:=256; stack_ptr:=0; bchar:=font_bchar[f];
set_cur_r; suppress_lig:=false;
continue: @<If there's a ligature or kern at the cursor position,
update the cursor data structures, possibly advancing~|k|; continue
until the cursor wants to move right@>;
@<Typeset character |cur_l|, if it exists in the font;
also append an optional kern@>;
@<Move the cursor to the right and |goto continue|, if there's
more work to do in the current word@>;
end; {now |k=end_k|}
end;
str_pool[max_k]:=save_c;
end;
@ @<Glob...@>=
@!box_width:scaled; {width of box constructed by |hbox|}
@!box_height:scaled; {height of box constructed by |hbox|}
@!box_depth:scaled; {depth of box constructed by |hbox|}
@!lig_stack:array[1..lig_lookahead] of quarterword; {inserted ligature chars}
@!dummy_info:four_quarters; {fake |char_info| for nonexistent character}
@!suppress_lig:boolean; {should we bypass checking for ligatures next time?}
@ @<Set init...@>=
dummy_info.b0:=qi(0); dummy_info.b1:=qi(0); dummy_info.b2:=qi(0);
dummy_info.b3:=qi(0);
@ @<Typeset a space...@>=
begin box_width:=box_width+space(f);
if send_it then
begin dvi_out(right4); dvi_four(space(f));
end;
incr(k);
end
@ @<If there's a ligature...@>=
if(cur_l<font_bc[f])or(cur_l>font_ec[f]) then
begin i:=dummy_info;
if cur_l=256 then l:=bchar_label[f]@+else l:=non_address;
end
else begin i:=char_info(f)(cur_l);
if char_tag(i)<>lig_tag then l:=non_address
else begin l:=lig_kern_start(f)(i); j:=font_info[l].qqqq;
if skip_byte(j)>stop_flag then l:=lig_kern_restart(f)(j);
end;
end;
if suppress_lig then suppress_lig:=false
else while l<qi(kern_base[f]) do
begin j:=font_info[l].qqqq;
if next_char(j)=cur_r then if skip_byte(j)<=stop_flag then
if op_byte(j)>=kern_flag then
begin kern_amount:=char_kern(f)(j); goto done;
end
else @<Carry out a ligature operation, updating the cursor structure
and possibly advancing~|k|; |goto continue| if the cursor doesn't
advance, otherwise |goto done|@>;
if skip_byte(j)>=stop_flag then goto done;
l:=l+skip_byte(j)+1;
end;
done:
@ At this point |i| contains |char_info| for |cur_l|.
@<Typeset character...@>=
if char_exists(i) then
begin box_width:=box_width+char_width(f)(i)+kern_amount;@/
hd:=height_depth(i);
x:=char_height(f)(hd);
if x>box_height then box_height:=x;
x:=char_depth(f)(hd);
if x>box_depth then box_depth:=x;
if send_it then
begin typeset(cur_l);
if kern_amount<>0 then
begin dvi_out(right4); dvi_four(kern_amount);
end;
end;
kern_amount:=0;
end
@ @d pop_stack==begin decr(stack_ptr);
if stack_ptr>0 then cur_r:=lig_stack[stack_ptr]
else set_cur_r;
end
@<Carry out a ligature operation, updating the cursor structure...@>=
begin case op_byte(j) of
1,5:cur_l:=qo(rem_byte(j));
2,6:begin cur_r:=rem_byte(j);
if stack_ptr=0 then
begin stack_ptr:=1;
if k<end_k then incr(k) {a non-space character is consumed}
else bchar:=non_char; {the right boundary character is consumed}
end;
lig_stack[stack_ptr]:=cur_r;
end;
3,7,11:begin cur_r:=rem_byte(j); incr(stack_ptr); lig_stack[stack_ptr]:=cur_r;
if op_byte(j)=11 then suppress_lig:=true;
end;
othercases begin cur_l:=qo(rem_byte(j));
if stack_ptr>0 then pop_stack
else if k=end_k then goto done
else begin incr(k); set_cur_r;
end;
end
endcases;
if op_byte(j)>3 then goto done;
goto continue;
end
@ @<Move the cursor to the right and |goto continue|...@>=
cur_l:=qo(cur_r);
if stack_ptr>0 then
begin pop_stack; goto continue;
end;
if k<end_k then
begin incr(k); set_cur_r; goto continue;
end
@* Gray fonts.
A proof diagram constructed by \.{GFtoDVI}
can be regarded as an array of rectangles, where each rectangle is either
blank or filled with a special symbol that we shall call $x$. A blank
rectangle represents a white pixel, while $x$ represents a black pixel.
Additional labels and reference lines are often superimposed on this
array of rectangles; hence it is usually best to choose a symbol $x$ that
has a somewhat gray appearance, although any symbol can actually be used.
In order to construct such proofs, \.{GFtoDVI} needs to work with
a special type of font known as a ``gray font''; it's possible to
obtain a wide variety of different sorts of proofs by using different
sorts of gray fonts. The next few paragraphs explain exactly what gray
fonts are supposed to contain, in case you want to design your own.
@^gray fonts@>
@ The simplest gray font contains only two characters, namely $x$
and another symbol that is used for dots that identify key points.
If proofs with relatively large pixels are desired, a two-character
gray font is all that's needed. However, if the pixel size is to be
relatively small, practical considerations make a two-character
font too inefficient, since it requires the typesetting of tens
of thousands of tiny little characters; printing device drivers
rarely work very well when they are presented with data that is
so different from ordinary text. Therefore a gray font with small
pixels usually has a number of characters that replicate $x$ in
such a way that comparatively few characters actually need to be
typeset.
Since many printing devices are not able to cope with
arbitrarily large or complex characters, it is not possible for a
single gray font to work well on all machines. In fact,
$x$ must have a width that is an integer multiple of the printing
device's unit of horizontal position, since rounding the positions of grey
characters would otherwise produce unsightly streaks on proof output.
Thus, there is no way to make the gray font as device-independent as
the rest of the system, in the sense that we would expect approximately
identical output on machines with different resolution. Fortunately,
proof sheets are rarely considered to be final documents; hence
\.{GFtoDVI} is set up to provide results that adapt suitably to
local conditions.
@ With such constraints understood, we can now take a look at what
\.{GFtoDVI} expects to see in a gray font. The character~$x$ always
appears in position~1. It must have positive height~$h$ and positive
width~$w$; its depth and italic correction are ignored.
Positions 2--120 of a gray font are reserved for special combinations
of $x$'s and blanks, stacked on top of each other. None of these character
codes need be present in the font; but if they are, the slots should be
occupied by characters of width~$w$ that have certain configurations of
$x$'s and blanks, prescribed for each character position. For example,
position~3 of the font should either contain no character at all,
or it should contain a character consisting of two $x$'s, one above
the other; one of these $x$'s should appear immediately above the
baseline, and the other should appear immediately below.
It will be convenient to use a horizontal notation like `\.{XOXXO}'
to stand for a vertical stack of $x$'s and blanks. The convention
will be that the stack is built from bottom to top, and the topmost
rectangle should sit on the baseline. Thus, `\.{XOXXO}' stands
actually for a character of depth~$4h$ that looks like this:
$$\vcenter{\halign{\hfil#\hfil\cr
blank\cr
$x$\rlap{\qquad\raise8pt\hbox{\smash{\hbox{$\longleftarrow$ baseline}}}}\cr
$x$\cr
blank\cr
$x$\cr
}}$$
(We use a horizontal notation instead of a vertical one in this explanation,
because column
vectors take too much space, and because the horizontal notation corresponds
to binary numbers in a convenient way.)
Positions 1--63 of a gray font are reserved for the patterns \.X, \.{XO},
\.{XX}, \.{XOO}, \.{XOX}, \dots, \.{XXXXXX}, just as in the normal
binary notation of the numbers 1--63. Positions 64--70 are reserved for
the special patterns \.{XOOOOOO}, \.{XXOOOOO}, \dots, \.{XXXXXXO},
\.{XXXXXXX} of length seven; positions 71--78 are, similarly, reserved for
the length-eight patterns \.{XOOOOOOO} through \.{XXXXXXXX}. The
length-nine patterns \.{XOOOOOOOO} through \.{XXXXXXXXX} are assigned
to positions 79--87, the length-ten patterns to positions 88--97,
the length-eleven patterns to positions 98--108, and the length-twelve
patterns to positions 109--120.
The following program sets a global array |c[1..120]| to the bit patterns
just described. Another array |d[1..120]| is set to contain only the next
higher bit; this determines the depth of the corresponding character.
@<Set init...@>=
c[1]:=1; d[1]:=2; two_to_the[0]:=1; m:=1;
for k:=1 to 13 do two_to_the[k]:=2*two_to_the[k-1];
for k:=2 to 6 do @<Add a full set of |k|-bit characters@>;
for k:=7 to 12 do @<Add special |k|-bit characters of the form \.{X..XO..O}@>;
@ @<Glob...@>=
@!c:array[1..120] of 1..4095; {bit patterns for a gray font}
@!d:array[1..120] of 2..4096; {the superleading bits}
@!two_to_the:array[0..13] of 1..8192; {powers of 2}
@ @<Add a full set of |k|-bit...@>=
begin n:=two_to_the[k-1];
for j:=0 to n-1 do
begin incr(m); c[m]:=m; d[m]:=n+n;
end;
end
@ @<Add special |k|-bit...@>=
begin n:=two_to_the[k-1];
for j:=k downto 1 do
begin incr(m); d[m]:=n+n;
if j=k then c[m]:=n
else c[m]:=c[m-1]+two_to_the[j-1];
end;
end
@ Position 0 of a gray font is reserved for the ``dot'' character, which
should have positive height~$h'$ and positive width~$w'$. When \.{GFtoDVI}
wants to put a dot at some place $(x,y)$ on the figure, it positions
the dot character so that its reference point is at $(x,y)$. The
dot will be considered to occupy a rectangle $(x+\delta,y+\epsilon)$
for $-w'\leq\delta\leq w'$ and $-h'\leq\epsilon\leq h'$; the rectangular
box for a label will butt up against the rectangle enclosing the dot.
@ All other character positions of a gray font (namely, positions 121--255)
are unreserved, in the sense that they have no predefined meaning.
But \.{GFtoDVI} may access them via the ``character list'' feature of
\.{TFM} files, starting with any of the characters in positions
1--120. In such a case each succeeding character in a list should be
equivalent to two of its predecessors, horizontally adjacent to each other.
For example, in a character list like
$$53,\;121,\;122,\;123$$
character 121 will stand for two 53's, character 122 for two 121's (i.e.,
four 53's), and character 123 for two 122's (i.e., eight 53's). Since
position~53 contains the pattern \.{XXOXOX}, character~123 in this example
would have height~$h$, depth~$5h$, and width~$8w$, and it would stand for
the pattern
$$\vcenter{\halign{&$\hfil#\hfil$\cr
x&x&x&x&x&x&x&x\cr
&&&&&&&\cr
x&x&x&x&x&x&x&x\cr
&&&&&&&\cr
x&x&x&x&x&x&x&x\cr
x&x&x&x&x&x&x&x\cr}}$$
Such a pattern is, of course, rather unlikely to occur in a \.{GF} file,
but \.{GFtoDVI} would be able to use if it were present. Designers
of gray fonts should provide characters only for patterns that they think
will occur often enough to make the doubling worthwhile. For example,
the character in position 120 (\.{XXXXXXXXXXXX}), or whatever is the
tallest stack of $x$'s present in the font, is a natural candidate for
repeated doubling.
Here's how \.{GFtoDVI} decides what characters of the gray font will be used,
given a configuration of black and white pixels: If there are no black
pixels, stop. Otherwise look at the top row that contains at least one
black pixel, and the eleven rows that follow. For each such column,
find the largest~$k$ such that $1\leq k\leq120$ and the gray font contains
character~$k$ and the pattern assigned to position~$k$ appears in the
given column. Typeset character $k$ (unless no such character exists)
and erase the corresponding black pixels; use doubled characters,
if they are present in the gray font, if two or more consecutive equal
characters need to be typeset. Repeat the same process on the remaining
configuration, until all the black pixels have been erased.
If all characters in positions 1--120 are present, this process is guaranteed to
take care of at least six rows each time; and it usually takes care of
twelve, since all patterns that contain at most one ``run'' of $x$'s
are present.
@ Fonts have optional parameters, as described in Appendix~F of {\sl The
\TeX book}, and some of these are important in gray fonts. The
slant parameter~$s$, if nonzero, will cause \.{GFtoDVI} to skew its
output; in this case the character $x$ will presumably be a parallelogram
with a corresponding slant, rather than the usual rectangle. \MF's
coordinate $(x,y)$ will appear in physical position $(xw+yhs,yh)$
on the proofsheets.
Parameter number~8 of a gray font specifies the thickness of rules
that go on the proofs. If this parameter is zero, \TeX's default
rule thickness (0.4\thinspace pt) will be used.
The other parameters of a gray font are ignored by \.{GFtoDVI}, but
it is conventional to set the font space parameter to~$w$ and the
xheight parameter to~$h$.
@ For best results the designer of a gray font should choose $h$ and~$w$
so that the user's \.{DVI}-to-hardcopy software will not make any
rounding errors. Furthermore, the dot should be an even number~$2m$ of
pixels in diameter, and the rule thickness should work out to an
even number~$2n$ of pixels; then the dots and rules will be centered on
the correct positions, in case of integer coordinates. Gray fonts
are almost always intended for particular output devices, even though
`\.{DVI}' stands for `device independent'; we use \.{DVI} files for \MF\
proofs chiefly because software to print \.{DVI} files is already in place.
@* Slant fonts.
\.{GFtoDVI} also makes use of another special type of font, if it is
necessary to typeset slanted rules. The format of such so-called
``slant fonts'' is quite a bit simpler than the format of gray fonts.
A slant font should contain exactly $n$ characters, in positions 1 to~$n$,
where the character in position~$k$ represents a slanted line $k$ units
tall, starting at the baseline. These lines all have a fixed slant ratio~$s$.
The following simple algorithm is used to typeset a rule that is $m$ units
high: Compute $q=\lceil m/n\rceil$; then typeset $q$~characters of
approximately equal size, namely $(m\bmod q)$ copies of character number
$\lceil m/q\rceil$ and $q-(m\bmod q)$ copies of character number
$\lfloor m/q\rfloor$. For example, if $n=15$ and $m=100$, we have $q=7$;
a 100-unit-high rule will be composed of 7~pieces, using characters
14,~14, 14, 14, 14, 15,~15.
@<Glob...@>=
@!rule_slant:real; {the slant ratio $s$ in the slant font,
or zero if there is no slant font}
@!slant_n:integer; {the number of characters in the slant font}
@!slant_unit:real; {the number of scaled points in the slant font unit}
@!slant_reported:real; {invalid slant ratio reported to the user}
@ \.{GFtoDVI} looks only at the height of character $n$, so the \.{TFM} file
need not be accurate about the heights of the other characters. (This is
fortunate, since \.{TFM} format allows at most 16 different heights per font.)
The width of character~$k$ should be $k/n$ times $s$ times the height of
character~$n$.
The slant parameter of a slant file should be $s$. It is customary to
set the |default_rule_thickness| parameter (number~8) to the thickness of
the slanted rules, but \.{GFtoDVI} doesn't look at it.
@ For best results on a particular output device, it is usually wise to
choose the `unit' in the above discussion to be an integer number of pixels,
and to make it no larger than the default rule thickness in the gray font
being used.
@ @<Initialize glob...@>=
if length(font_name[slant_font])=0 then rule_slant:=0.0
else begin rule_slant:=slant(slant_font)/unity;
slant_n:=font_ec[slant_font];
i:=char_info(slant_font)(slant_n);
slant_unit:=char_height(slant_font)(height_depth(i))/slant_n;
end;
slant_reported:=0.0;
@ The following error message is given when an absent slant has been
requested.
@p procedure slant_complaint(@!r:real);
begin if abs(r-slant_reported)>0.001 then
begin print_nl('Sorry, I can''t make diagonal rules of slant ',r:10:5,'!');
@.Sorry, I can't...@>
slant_reported:=r;
end;
end;
@* Representation of rectangles.
OK---the preliminary spadework has now been done. We're ready at last
to concentrate on \.{GFtoDVI}'s {\sl raison d'\^^Detre}.
One of the most interesting tasks remaining is to make
a ``map'' of the labels that have been allocated.
There usually aren't a great many labels, so we don't need fancy data
structures; but we do make use of linked nodes containing nine fields.
The nodes generally represent rectangular boxes according to the
following conventions:
\smallskip\hang\noindent
|xl|, |xr|, |yt|, and |yb| are the left, right, top, and bottom locations
of a rectangle, expressed in \.{DVI} coordinates. (This program uses
scaled points as \.{DVI} coordinates. Since \.{DVI} coordinates increase
as one moves down the page, |yb| will be greater than |yt|.)
\smallskip\hang\noindent
|xx| and |yy| are the coordinates of the reference point of a box to be
typeset from this node, again in \.{DVI} coordinates.
\smallskip\hang\noindent
|prev| and |next| point to the predecessor and successor of this node.
Sometimes the nodes are singly linked and only |next| is relevant; otherwise
the nodes are doubly linked in order of their |yy| coordinates, so that we
can move down by going to |next|, or up by going to |prev|.
\smallskip\hang\noindent
|info| is the number of a string associated with this node.
\smallskip\noindent
The nine fields of a node appear in nine global arrays.
Null pointers are denoted by |null|, which happens to be zero.
@d null=0
@<Types ...@>=
@!node_pointer=null..max_labels;
@ @<Glob...@>=
@!xl,@!xr,@!yt,@!yb:array[1..max_labels] of scaled; {boundary coordinates}
@!xx,@!yy:array[0..max_labels] of scaled; {reference coordinates}
@!prev,@!next:array[0..max_labels] of node_pointer; {links}
@!info:array[1..max_labels] of str_number; {associated strings}
@!max_node:node_pointer; {the largest node in use}
@!max_height:scaled; {greatest difference between |yy| and |yt|}
@!max_depth:scaled; {greatest difference between |yb| and |yy|}
@ It's easy to allocate a new node (unless no more room is left):
@p function get_avail:node_pointer;
begin incr(max_node);
if max_node=max_labels then abort('Too many labels and/or rules!');
@.Too many labels@>
get_avail:=max_node;
end;
@ The doubly linked nodes are sorted by |yy| coordinates so that we don't have
to work too hard to find nearest neighbors or to determine if rectangles overlap.
The first node in the doubly linked rectangle list is always in location~0,
and the last node is always in location |max_labels|; the |yy| coordinates
of these nodes are very small and very large, respectively.
@d end_of_list==max_labels
@<Set init...@>=
yy[0]:=-@'10000000000; yy[end_of_list]:=@'10000000000;
@ The |node_ins| procedure inserts a new rectangle, represented by node~|p|,
into the doubly linked list. There's a second parameter, |q|; node~|q| should
already be in the doubly linked list, preferably with |yy[q]| near |yy[p]|.
@p procedure node_ins(@!p,@!q:node_pointer);
var @!r:node_pointer; {for tree traversal}
begin if yy[p]>=yy[q] then
begin repeat r:=q; q:=next[q];@+until yy[p]<=yy[q];
next[r]:=p; prev[p]:=r; next[p]:=q; prev[q]:=p;
end
else begin repeat r:=q; q:=prev[q];@+until yy[p]>=yy[q];
prev[r]:=p; next[p]:=r; prev[p]:=q; next[q]:=p;
end;
if yy[p]-yt[p]>max_height then max_height:=yy[p]-yt[p];
if yb[p]-yy[p]>max_depth then max_depth:=yb[p]-yy[p];
end;
@ The data structures need to be initialized for each character in the
\.{GF} file.
@<Initialize variables for the next character@>=
max_node:=0; next[0]:=end_of_list; prev[end_of_list]:=0;
max_height:=0; max_depth:=0;
@ The |overlap| subroutine determines whether or not the rectangle specified
in node~|p| has a nonempty intersection with some rectangle in the doubly
linked list. Again |q|~is a parameter that gives us a starting point
in the list. We assume that |q<>end_of_list|, so that |next[q]| is meaningful.
@p function overlap(@!p,@!q:node_pointer):boolean;
label exit;
var @!y_thresh:scaled; {cutoff value to speed the search}
@!x_left,@!x_right,@!y_top,@!y_bot:scaled; {boundaries to test for overlap}
@!r:node_pointer; {runs through the neighbors of |q|}
begin x_left:=xl[p]; x_right:=xr[p]; y_top:=yt[p]; y_bot:=yb[p];
@<Look for overlaps in the successors of node |q|@>;
@<Look for overlaps in node |q| and its predecessors@>;
overlap:=false;
exit: end;
@ @<Look for overlaps in the successors of node |q|@>=
y_thresh:=y_bot+max_height; r:=next[q];
while yy[r]<y_thresh do
begin if y_bot > yt[r] then if x_left<xr[r] then
if x_right>xl[r] then if y_top<yb[r] then
begin overlap:=true; return;
end;
r:=next[r];
end
@ @<Look for overlaps in node |q| and its predecessors@>=
y_thresh:=y_top-max_depth; r:=q;
while yy[r]>y_thresh do
begin if y_bot > yt[r] then if x_left<xr[r] then
if x_right>xl[r] then if y_top<yb[r] then
begin overlap:=true; return;
end;
r:=prev[r];
end
@ Nodes that represent dots instead of labels satisfy the following
constraints:
$$\vcenter{\halign{#\hfil&\quad#\hfil\cr
|info[p]<0;|&|p>=first_dot|;\cr
|xl[p]=xx[p]-dot_width|,&|xr[p]=xx[p]+dot_width|;\cr
|yt[p]=yy[p]-dot_height|,&|yb[p]=yy[p]+dot_height|.\cr}}$$
The |nearest_dot| subroutine finds a node whose reference point is as
close as possible to a given position, ignoring nodes that are too close.
More precisely, the ``nearest'' node
minimizes$$d(q,p)=\max\bigl(\vert |xx|[q]-|xx|[p]\vert,
\vert |yy|[q]-|yy|[p]\vert\bigr)$$ over all nodes~|q|
with |d(q,p)>=d0|. We call the subroutine |nearest_dot| because it is used only
when the doubly linked list contains nothing but dots.
The routine also sets the global variable |twin| to |true|, if there is a
node |q<>p| with |d(q,p)<d0|.
@ @<Glob...@>=
@!first_dot:node_pointer; {the node address where dots begin}
@!twin:boolean; {is there a nearer dot than the ``nearest'' dot?}
@ If there is no nearest dot, the value |null| is returned;
otherwise a pointer to the nearest dot is returned.
@p function nearest_dot(@!p:node_pointer; @!d0:scaled):node_pointer;
var @!best_q:node_pointer; {value to return}
@!d_min,@!d:scaled; {distances}
begin twin:=false; best_q:=0; d_min:=@'2000000000;
@<Search for the nearest dot in nodes following |p|@>;
@<Search for the nearest dot in nodes preceding |p|@>;
nearest_dot:=best_q;
end;
@ @<Search for the nearest dot in nodes following |p|@>=
q:=next[p];
while yy[q]<yy[p]+d_min do
begin d:=abs(xx[q]-xx[p]);
if d<yy[q]-yy[p] then d:=yy[q]-yy[p];
if d<d0 then twin:=true
else if d<d_min then
begin d_min:=d; best_q:=q;
end;
q:=next[q];
end
@ @<Search for the nearest dot in nodes preceding |p|@>=
q:=prev[p];
while yy[q]>yy[p]-d_min do
begin d:=abs(xx[q]-xx[p]);
if d<yy[p]-yy[q] then d:=yy[p]-yy[q];
if d<d0 then twin:=true
else if d<d_min then
begin d_min:=d; best_q:=q;
end;
q:=prev[q];
end
@* Doing the labels.
Each ``character'' in the \.{GF} file is preceded by a number of special
commands that define labels, titles, rules, etc. We store these away,
to be considered later when the |boc| command appears. The |boc|
command establishes the size information by which labels and rules
can be positioned, so we spew out the label information as soon as
we see the |boc|. The gray pixels will be typeset after all the labels
for a particular character have been finished.
@ Here is the part of \.{GFtoDVI} that stores information preceding a~|boc|.
It comes into play when |cur_gf| is between |xxx1| and~|no_op|, inclusive.
@d font_change(#)==if fonts_not_loaded then
begin #; end
else print_nl('(Tardy font change will be ignored (byte ',
@.Tardy font change...@>
cur_loc:1,')!)')
@<Process a no-op command@>=
begin k:=interpret_xxx;
case k of
no_operation: do_nothing;
title_font,label_font,gray_font,slant_font:font_change(font_name[k]:=cur_string;
font_area[k]:=null_string;font_at[k]:=0;init_str_ptr:=str_ptr);
title_font+area_code,label_font+area_code,gray_font+area_code,
slant_font+area_code:@|
font_change(font_area[k-area_code]:=cur_string;init_str_ptr:=str_ptr);
title_font+at_code,label_font+at_code,gray_font+at_code,
slant_font+at_code:@|
font_change(font_at[k-at_code]:=get_yyy;init_str_ptr:=str_ptr);
rule_thickness_code:rule_thickness:=get_yyy;
rule_code:@<Store a rule@>;
offset_code:@<Override the offsets@>;
x_offset_code:x_offset:=get_yyy;
y_offset_code:y_offset:=get_yyy;
title_code:@<Store a title@>;
null_string:@<Store a label@>;
end; {there are no other cases}
end
@ The following quantities are cleared just before reading the
\.{GF} commands pertaining to a character.
@<Glob...@>=
@!rule_thickness:scaled; {the current rule thickness
(zero means use the default)}
@!offset_x,@!offset_y:scaled; {the current offsets for images}
@!x_offset,@!y_offset:scaled; {the current offsets for labels}
@!pre_min_x,@!pre_max_x,@!pre_min_y,@!pre_max_y:scaled;
{extreme values of coordinates preceding a character, in \MF\ pixels}
@ @<Initialize variables for the next character@>=
rule_thickness:=0;
offset_x:=0; offset_y:=0; x_offset:=0; y_offset:=0;
pre_min_x:=@'2000000000; pre_max_x:=-@'2000000000;
pre_min_y:=@'2000000000; pre_max_y:=-@'2000000000;
@ @<Override the offsets@>=
begin offset_x:=get_yyy; offset_y:=get_yyy;
end
@ Rules that will need to be drawn are kept in a linked list accessible
via |rule_ptr|, in last-in-first-out order. The nodes of this list will
never get into the doubly linked list, and indeed these nodes use different
field conventions entirely (because rules may be slanted).
@d x0==xl {starting |x| coordinate of a stored rule}
@d y0==yt {starting |y| coordinate (in scaled \MF\ pixels)}
@d x1==xr {ending |x| coordinate of a stored rule}
@d y1==yb {ending |y| coordinate of a stored rule}
@d rule_size==xx {thickness of a stored rule, in scaled points}
@<Glob...@>=
@!rule_ptr:node_pointer; {top of the stack of remembered rules}
@ @<Store a rule@>=
begin p:=get_avail; next[p]:=rule_ptr; rule_ptr:=p;@/
x0[p]:=get_yyy; y0[p]:=get_yyy; x1[p]:=get_yyy; y1[p]:=get_yyy;
if x0[p]<pre_min_x then pre_min_x:=x0[p];
if x0[p]>pre_max_x then pre_max_x:=x0[p];
if y0[p]<pre_min_y then pre_min_y:=y0[p];
if y0[p]>pre_max_y then pre_max_y:=y0[p];
if x1[p]<pre_min_x then pre_min_x:=x1[p];
if x1[p]>pre_max_x then pre_max_x:=x1[p];
if y1[p]<pre_min_y then pre_min_y:=y1[p];
if y1[p]>pre_max_y then pre_max_y:=y1[p];
rule_size[p]:=rule_thickness;
end
@ Titles and labels are, likewise, stored temporarily in singly linked lists.
In this case the lists are first-in-first-out.
Variables |title_tail| and |label_tail| point to the most recently inserted
title or label; variables |title_head| and |label_head|
point to the beginning of the list. (A standard coding trick is used
for |label_head|, which is kept in |next[end_of_list]|; we have
|label_tail=end_of_list| when the list is empty.)
The |prev| field in nodes of the temporary label list specifies the
type of label, so we call it |lab_typ|.
@d lab_typ==prev {the type of a stored label (|"/"..."8"|)}
@d label_head==next[end_of_list]
@<Glob...@>=
@!label_tail:node_pointer; {tail of the queue of remembered labels}
@!title_head,@!title_tail:node_pointer; {head and tail of the queue for titles}
@ We must start the lists out empty.
@<Initialize variables for the next char...@>=
rule_ptr:=null;
title_head:=null; title_tail:=null; label_head:=null; label_tail:=end_of_list;
first_dot:=max_labels;
@ @<Store a title@>=
begin p:=get_avail; info[p]:=cur_string;
if title_head=null then title_head:=p
else next[title_tail]:=p;
title_tail:=p;
end
@ We store the coordinates of each label in units of \MF\ pixels; they
will be converted to \.{DVI} coordinates later.
@<Store a label@>=
if (label_type<"/")or(label_type>"8") then
print_nl('Bad label type precedes byte ',cur_loc:1,'!')
@.Bad label type...@>
else begin p:=get_avail; next[label_tail]:=p; label_tail:=p;@/
lab_typ[p]:=label_type; info[p]:=cur_string;@/
xx[p]:=get_yyy; yy[p]:=get_yyy;
if xx[p]<pre_min_x then pre_min_x:=xx[p];
if xx[p]>pre_max_x then pre_max_x:=xx[p];
if yy[p]<pre_min_y then pre_min_y:=yy[p];
if yy[p]>pre_max_y then pre_max_y:=yy[p];
end
@ The process of ferreting everything away comes to an abrupt halt
when a |boc| command is sensed. The following steps are performed
at such times:
@<Process a character@>=
begin check_fonts;
@<Finish reading the parameters of the |boc|@>;
@<Get ready to convert \MF\ coordinates to \.{DVI} coordinates@>;
@<Output the |bop| and the title line@>;
print('[',total_pages:1); update_terminal; {print a progress report}
@<Output all rules for the current character@>;
@<Output all labels for the current character@>;
do_pixels;
dvi_out(eop); {finish the page}
@<Adjust the maximum page width@>;
print(']'); update_terminal;
end
@ @<Finish reading the parameters of the |boc|@>=
if cur_gf=boc then
begin ext:=signed_quad; {read the character code}
char_code:=ext mod 256;
if char_code<0 then char_code:=char_code+256;
ext:=(ext-char_code) div 256;
k:=signed_quad; {read and ignore the prev pointer}
min_x:=signed_quad; {read the minimum $x$ coordinate}
max_x:=signed_quad; {read the maximum $x$ coordinate}
min_y:=signed_quad; {read the minimum $y$ coordinate}
max_y:=signed_quad; {read the maximum $y$ coordinate}
end
else begin ext:=0; char_code:=get_byte; {|cur_gf=boc1|}
min_x:=get_byte; max_x:=get_byte; min_x:=max_x-min_x;@/
min_y:=get_byte; max_y:=get_byte; min_y:=max_y-min_y;
end;
if max_x-min_x>widest_row then abort('Character too wide!')
@.Character too wide@>
@ @<Glob...@>=
@!char_code,@!ext:integer; {the current character code and extension}
@!min_x,@!max_x,@!min_y,@!max_y:integer; {character boundaries, in pixels}
@!x,@!y:integer; {current painting position, in pixels}
@!z:integer; {initial painting position in row, relative to |min_x|}
@ \MF\ coordinates $(x,y)$ are converted to \.{DVI} coordinates by the
following routine. Real values |x_ratio|, |y_ratio|, and |slant_ratio|
will have been calculated based on the gray font; |scaled| values
|delta_x| and |delta_y| will have been computed so that, in the absence
of slanting and offsets, the \MF\ coordinates |(min_x,max_y+1)| will correspond
to the \.{DVI} coordinates $(0,50\,\rm pt)$.
@p procedure convert(@!x,@!y:scaled);
begin x:=x+x_offset; y:=y+y_offset;
dvi_y:=-round(y_ratio*y)+delta_y;
dvi_x:=round(x_ratio*x+slant_ratio*y)+delta_x;
end;
@ @<Glob...@>=
@!x_ratio,@!y_ratio,@!slant_ratio:real; {conversion factors}
@!unsc_x_ratio,@!unsc_y_ratio,@!unsc_slant_ratio:real;
{ditto, times |unity|}
@!fudge_factor:real; {unconversion factor}
@!delta_x,@!delta_y:scaled; {magic constants used by |convert|}
@!dvi_x,@!dvi_y:scaled; {outputs of |convert|, in scaled points}
@!over_col:scaled; {overflow labels start here}
@!page_height,page_width:scaled; {size of the current page}
@ @<Initialize global variables that depend on the font data@>=
i:=char_info(gray_font)(1);
if not char_exists(i) then abort('Missing pixel char!');
@.Missing pixel char@>
unsc_x_ratio:=char_width(gray_font)(i);
x_ratio:=unsc_x_ratio/unity;
unsc_y_ratio:=char_height(gray_font)(height_depth(i));
y_ratio:=unsc_y_ratio/unity;
unsc_slant_ratio:=slant(gray_font)*y_ratio;
slant_ratio:=unsc_slant_ratio/unity;
if x_ratio*y_ratio=0 then abort('Vanishing pixel size!');
@.Vanishing pixel size@>
fudge_factor:=(slant_ratio/x_ratio)/y_ratio;
@ @<Get ready to convert...@>=
if pre_min_x<min_x*unity then offset_x:=offset_x+min_x*unity-pre_min_x;
if pre_max_y>max_y*unity then offset_y:=offset_y+max_y*unity-pre_max_y;
if pre_max_x>max_x*unity then pre_max_x:=pre_max_x div unity
else pre_max_x:=max_x;
if pre_min_y<min_y*unity then pre_min_y:=pre_min_y div unity
else pre_min_y:=min_y;
delta_y:=round(unsc_y_ratio*(max_y+1)-y_ratio*offset_y)+3276800;
delta_x:=round(x_ratio*offset_x-unsc_x_ratio*min_x);
if slant_ratio>=0 then
over_col:=round(unsc_x_ratio*pre_max_x+unsc_slant_ratio*max_y)
else over_col:=round(unsc_x_ratio*pre_max_x+unsc_slant_ratio*min_y);
over_col:=over_col+delta_x+10000000;
page_height:=round(unsc_y_ratio*(max_y+1-pre_min_y))+3276800-offset_y;
if page_height>max_v then max_v:=page_height;
page_width:=over_col-10000000
@ The |dvi_goto| subroutine outputs bytes to the \.{DVI} file that
will initiate typesetting at given \.{DVI} coordinates, assuming that
the current position of the \.{DVI} reader is $(0,0)$. This subroutine
begins by outputting a |push| command; therefore, a |pop| command should
be given later. That |pop| will restore the \.{DVI} position to $(0,0)$.
@p procedure dvi_goto(@!x,@!y:scaled);
begin dvi_out(push);
if x<>0 then
begin dvi_out(right4); dvi_four(x);
end;
if y<>0 then
begin dvi_out(down4); dvi_four(y);
end;
end;
@ @<Output the |bop| and the title line@>=
dvi_out(bop); incr(total_pages); dvi_four(total_pages);
dvi_four(char_code); dvi_four(ext);
for k:=3 to 9 do dvi_four(0);
dvi_four(last_bop); last_bop:=dvi_offset+dvi_ptr-45;@/
dvi_goto(0,655360); {the top baseline is 10\thinspace pt down}
if use_logo then
begin select_font(logo_font); hbox(small_logo,logo_font,true);
end;
select_font(title_font); hbox(time_stamp,title_font,true);@/
hbox(page_header,title_font,true); dvi_scaled(total_pages*65536.0);@/
if (char_code<>0)or(ext<>0) then
begin hbox(char_header,title_font,true); dvi_scaled(char_code*65536.0);
if ext<>0 then
begin hbox(ext_header,title_font,true); dvi_scaled(ext*65536.0);
end;
end;
if title_head<>null then
begin next[title_tail]:=null;
repeat hbox(left_quotes,title_font,true);
hbox(info[title_head],title_font,true);
hbox(right_quotes,title_font,true);
title_head:=next[title_head];
until title_head=null;
end;
dvi_out(pop)
@ @d tol==6554 {one tenth of a point, in \.{DVI} coordinates}
@<Output all rules for the current character@>=
if rule_slant<>0 then select_font(slant_font);
while rule_ptr<>null do
begin p:=rule_ptr; rule_ptr:=next[p];@/
if rule_size[p]=0 then rule_size[p]:=gray_rule_thickness;
if rule_size[p]>0 then
begin convert(x0[p],y0[p]); temp_x:=dvi_x; temp_y:=dvi_y;
convert(x1[p],y1[p]);
if abs(temp_x-dvi_x)<tol then @<Output a vertical rule@>
else if abs(temp_y-dvi_y)<tol then @<Output a horizontal rule@>
else @<Try to output a diagonal rule@>;
end;
end
@ @<Glob...@>=
@!gray_rule_thickness:scaled; {thickness of rules, according to the gray font}
@!temp_x,@!temp_y:scaled; {temporary registers for intermediate calculations}
@ @<Initialize glob...@>=
gray_rule_thickness:=default_rule_thickness(gray_font);
if gray_rule_thickness=0 then gray_rule_thickness:=26214; {0.4\thinspace pt}
@ @<Output a vertical rule@>=
begin if temp_y>dvi_y then
begin k:=temp_y; temp_y:=dvi_y; dvi_y:=k;
end;
dvi_goto(dvi_x-(rule_size[p] div 2), dvi_y);
dvi_out(put_rule); dvi_four(dvi_y-temp_y); dvi_four(rule_size[p]);
dvi_out(pop);
end
@ @<Output a horizontal rule@>=
begin if temp_x<dvi_x then
begin k:=temp_x; temp_x:=dvi_x; dvi_x:=k;
end;
dvi_goto(dvi_x,dvi_y+(rule_size[p] div 2));
dvi_out(put_rule); dvi_four(rule_size[p]); dvi_four(temp_x-dvi_x);
dvi_out(pop);
end
@ @<Try to output a diagonal rule@>=
if (rule_slant=0)or@|
(abs(temp_x+rule_slant*(temp_y-dvi_y)-dvi_x)>rule_size[p]) then
slant_complaint((dvi_x-temp_x)/(temp_y-dvi_y))
else begin if temp_y>dvi_y then
begin k:=temp_y; temp_y:=dvi_y; dvi_y:=k;@/
k:=temp_x; temp_x:=dvi_x; dvi_x:=k;
end;
m:=round((dvi_y-temp_y)/slant_unit);
if m>0 then
begin dvi_goto(dvi_x,dvi_y);
q:=((m-1) div slant_n)+1; k:=m div q;
p:=m mod q; q:=q-p;
@<Vertically typeset |q| copies of character |k|@>;
@<Vertically typeset |p| copies of character |k+1|@>;
dvi_out(pop);
end;
end
@ @<Vertically typeset |q| copies of character |k|@>=
typeset(k); dy:=round(k*slant_unit); dvi_out(z4); dvi_four(-dy);
while q>1 do
begin typeset(k); dvi_out(z0); decr(q);
end
@ @<Vertically typeset |p| copies of character |k+1|@>=
if p>0 then
begin incr(k); typeset(k);
dy:=round(k*slant_unit); dvi_out(z4); dvi_four(-dy);
while p>1 do
begin typeset(k); dvi_out(z0); decr(p);
end;
end
@ Now we come to a more interesting part of the computation, where we
go through the stored labels and try to fit them in the illustration for
the current character, together with their associated dots.
It would simplify font-switching slightly if we were to typeset the labels
first, but we find it desirable to typeset the dots first and then turn to the
labels. This procedure makes it possible for us to allow the dots to
overlap each other without allowing the labels to overlap. After the
dots are in place, we typeset all prescribed labels, that is, labels with a
|lab_typ| of |"1".."8"|; these, too, are allowed to overlap the dots and
each other.
@<Output all labels for the current character@>=
overflow_line:=1;
if label_head<>null then
begin next[label_tail]:=null; select_font(gray_font);
@<Output all dots@>;
@<Find nearest dots, to help in label positioning@>;
select_font(label_font);
@<Output all prescribed labels@>;
@<Output all attachable labels@>;
@<Output all overflow labels@>;
end
@ @<Glob...@>=
@!overflow_line:integer; {the number of labels that didn't fit, plus~1}
@ A label that appears above its dot is considered to occupy a
rectangle of height~$h+\Delta$, depth~$d$, and width~$w+2\Delta$, where
$(h,w,d)$ are the height, width, and depth of the label computed by |hbox|,
and $\Delta$ is an additional amount of blank space that keeps labels from
coming too close to each other. (\.{GFtoDVI} arbitrarily defines $\Delta$
to be one half the width of a space in the label font.) This label is
centered over its dot, with its baseline $d+h'$ above the center of the dot;
here $h'=|dot_height|$ is the height of character~0 in the gray font.
Similarly, a label that appears below its dot is considered to occupy
a rectangle of height~$h$, depth~$d+\Delta$, and width~$w+2\Delta$; the
baseline is $h+h'$ below the center of the dot.
A label at the right of its dot is considered to occupy a rectangle of
height~$h+\Delta$, depth~$d+\Delta$, and width~$w+\Delta$. Its
reference point can be found by starting at the center of the dot and
moving right $w'=|dot_width|$ (i.e., the width of character~0 in the
gray font), then moving down by half the x-height of the label font.
A label at the left of its dot is similar.
A dot is considered to occupy a rectangle of height $2h'$ and width~$2w'$,
centered on the dot.
When the label type is |"1"| or more, the labels
are put into the doubly linked list unconditionally.
Otherwise they are put into the list
only if we can find a way to fit them in without
overlapping any previously inserted rectangles.
@<Glob...@>=
@!delta:scaled; {extra padding to keep labels from being too close}
@!half_x_height:scaled; {amount to drop baseline of label below the dot center}
@!thrice_x_height:scaled; {baseline separation for overflow labels}
@!dot_width,@!dot_height:scaled; {$w'$ and $h'$ in the discussion above}
@ @<Initialize global variables that depend on the font data@>=
i:=char_info(gray_font)(0);
if not char_exists(i) then abort('Missing dot char!');
@.Missing dot char@>
dot_width:=char_width(gray_font)(i);
dot_height:=char_height(gray_font)(height_depth(i));
delta:=space(label_font) div 2;
thrice_x_height:=3*x_height(label_font);
half_x_height:=thrice_x_height div 6;
@ Here is a subroutine that computes the rectangle boundaries
|xl[p]|, |xr[p]|, |yt[p]|, |yb[p]|, and the reference point coordinates
|xx[p]|,~|yy[p]|, for a label that is to be placed above a dot.
The coordinates of the dot's center are assumed given in |dvi_x|
and |dvi_y|; the |hbox| subroutine is assumed to have
already computed the height, width, and depth of the label box.
@p procedure top_coords(@!p:node_pointer);
begin xx[p]:=dvi_x-(box_width div 2); xl[p]:=xx[p]-delta;
xr[p]:=xx[p]+box_width+delta;@/
yb[p]:=dvi_y-dot_height; yy[p]:=yb[p]-box_depth;
yt[p]:=yy[p]-box_height-delta;
end;
@ The other three label positions are handled by similar routines.
@p procedure bot_coords(@!p:node_pointer);
begin xx[p]:=dvi_x-(box_width div 2); xl[p]:=xx[p]-delta;
xr[p]:=xx[p]+box_width+delta;@/
yt[p]:=dvi_y+dot_height; yy[p]:=yt[p]+box_height;
yb[p]:=yy[p]+box_depth+delta;
end;
@#
procedure right_coords(@!p:node_pointer);
begin xl[p]:=dvi_x+dot_width; xx[p]:=xl[p]; xr[p]:=xx[p]+box_width+delta;@/
yy[p]:=dvi_y+half_x_height; yb[p]:=yy[p]+box_depth+delta;
yt[p]:=yy[p]-box_height-delta;
end;
@#
procedure left_coords(@!p:node_pointer);
begin xr[p]:=dvi_x-dot_width; xx[p]:=xr[p]-box_width; xl[p]:=xx[p]-delta;@/
yy[p]:=dvi_y+half_x_height; yb[p]:=yy[p]+box_depth+delta;
yt[p]:=yy[p]-box_height-delta;
end;
@ @<Output all dots@>=
p:=label_head; first_dot:=max_node+1;
while p<>null do
begin convert(xx[p],yy[p]); xx[p]:=dvi_x; yy[p]:=dvi_y;
if lab_typ[p]<"5" then
@<Enter a dot for label |p| in the rectangle list,
and typeset the dot@>;
p:=next[p];
end
@ We plant links between dots and their labels by using (or abusing) the
|xl| and |info| fields, which aren't needed for their normal purposes.
@d dot_for_label==xl
@d label_for_dot==info
@<Enter a dot...@>=
begin q:=get_avail; dot_for_label[p]:=q; label_for_dot[q]:=p;@/
xx[q]:=dvi_x; xl[q]:=dvi_x-dot_width; xr[q]:=dvi_x+dot_width;@/
yy[q]:=dvi_y; yt[q]:=dvi_y-dot_height; yb[q]:=dvi_y+dot_height;@/
node_ins(q,0);@/
dvi_goto(xx[q],yy[q]); dvi_out(0); dvi_out(pop);
end
@ Prescribed labels are now taken out of the singly linked list and
inserted into the doubly linked list.
@<Output all prescribed labels@>=
q:=end_of_list; {|label_head=next[q]|}
while next[q]<>null do
begin p:=next[q];
if lab_typ[p]>"0" then
begin next[q]:=next[p];
@<Enter a prescribed label for node |p| into the rectangle list,
and typeset it@>;
end
else q:=next[q];
end
@ @<Enter a prescr...@>=
begin hbox(info[p],label_font,false); {Compute the size of this label}
dvi_x:=xx[p]; dvi_y:=yy[p];
if lab_typ[p]<"5" then r:=dot_for_label[p]@+else r:=0;
case lab_typ[p] of
"1","5":top_coords(p);
"2","6":left_coords(p);
"3","7":right_coords(p);
"4","8":bot_coords(p);
end; {no other cases are possible}
node_ins(p,r);@/
dvi_goto(xx[p],yy[p]); hbox(info[p],label_font,true); dvi_out(pop);
end
@ \.{GFtoDVI}'s algorithm for positioning the ``floating'' labels
was devised by Arthur~L. Samuel.
@^Samuel, Arthur Lee@>
It tries to place labels in a priority order, based on the position of
the nearest dot to a given dot. If that dot, for example, lies in the first
octant (i.e., east to northeast of the given dot), the given label will
be put into the west slot unless that slot is already blocked; then the
south slot will be tried, etc.
First we need to compute the octants. We also note if two or more dots
are nearly coincident, since Samuel's algorithm modifies the priority
order on that case. The information is temporarily recorded in the |xr| array.
@d octant==xr {octant code for nearest dot, plus 8 for coincident dots}
@<Find nearest dots, to help in label positioning@>=
p:=label_head;
while p<>null do
begin if lab_typ[p]<="0" then
@<Compute the octant code for floating label |p|@>;
p:=next[p];
end;
@ There's a sneaky way to identify octant numbers, represented by the
code shown here. (Remember that |y|~coordinates increase downward
in the \.{DVI} convention.)
@d first_octant=0
@d second_octant=1
@d third_octant=2
@d fourth_octant=3
@d fifth_octant=7
@d sixth_octant=6
@d seventh_octant=5
@d eighth_octant=4
@<Compute the octant code for floating label |p|@>=
begin r:=dot_for_label[p]; q:=nearest_dot(r,10);
if twin then octant[p]:=8@+else octant[p]:=0;
if q<>null then
begin dx:=xx[q]-xx[r]; dy:=yy[q]-yy[r];
if dy>0 then octant[p]:=octant[p]+4;
if dx<0 then incr(octant[p]);
if dy>dx then incr(octant[p]);
if -dy>dx then incr(octant[p]);
end;
end
@ A procedure called |place_label| will try to place the remaining
labels in turn. If it fails, we ``disconnect'' the dot from this
label so that an unlabeled dot will not appear as a reference in the
overflow column.
@<Output all attachable labels@>=
q:=end_of_list; {now |next[q]=label_head|}
while next[q]<>null do
begin p:=next[q]; r:=next[p]; s:=dot_for_label[p];
if place_label(p) then next[q]:=r
else begin label_for_dot[s]:=null; {disconnect the dot}
if lab_typ[p]="/" then next[q]:=r {remove label from list}
else q:=p; {retain label in list for the overflow column}
end;
end
@ Here is the |place_label| routine, which uses the previously computed
|octant| information as a heuristic. If the label can be placed, it
is inserted into the rectangle list and typeset.
@p function place_label(@!p:node_pointer):boolean;
label exit, found;
var @!oct:0..15; {octant code}
@!dfl:node_pointer; {saved value of |dot_for_label[p]|}
begin hbox(info[p],label_font,false); {Compute the size of this label}
dvi_x:=xx[p]; dvi_y:=yy[p];
@<Find non-overlapping coordinates, if possible, and |goto| found;
otherwise set |place_label:=false| and |return|@>;
found:node_ins(p,dfl);@/
dvi_goto(xx[p],yy[p]); hbox(info[p],label_font,true); dvi_out(pop);
place_label:=true;
exit:end;
@ @<Find non-overlapping coordinates, if possible...@>=
dfl:=dot_for_label[p]; oct:=octant[p];
@<Try the first choice for label direction@>;
@<Try the second choice for label direction@>;
@<Try the third choice for label direction@>;
@<Try the fourth choice for label direction@>;
xx[p]:=dvi_x; yy[p]:=dvi_y; dot_for_label[p]:=dfl; {no luck; restore the coordinates}
place_label:=false; return
@ @<Try the first choice for label direction@>=
case oct of
first_octant,eighth_octant,second_octant+8,seventh_octant+8: left_coords(p);
second_octant,third_octant,first_octant+8,fourth_octant+8: bot_coords(p);
fourth_octant,fifth_octant,third_octant+8,sixth_octant+8: right_coords(p);
sixth_octant,seventh_octant,fifth_octant+8,eighth_octant+8: top_coords(p);
end;
if not overlap(p,dfl) then goto found
@ @<Try the second choice for label direction@>=
case oct of
first_octant,fourth_octant,fifth_octant+8,eighth_octant+8: bot_coords(p);
second_octant,seventh_octant,third_octant+8,sixth_octant+8: left_coords(p);
third_octant,sixth_octant,second_octant+8,seventh_octant+8: right_coords(p);
fifth_octant,eighth_octant,first_octant+8,fourth_octant+8: top_coords(p);
end;
if not overlap(p,dfl) then goto found
@ @<Try the third choice for label direction@>=
case oct of
first_octant,fourth_octant,sixth_octant+8,seventh_octant+8: top_coords(p);
second_octant,seventh_octant,fourth_octant+8,fifth_octant+8: right_coords(p);
third_octant,sixth_octant,first_octant+8,eighth_octant+8: left_coords(p);
fifth_octant,eighth_octant,second_octant+8,third_octant+8: bot_coords(p);
end;
if not overlap(p,dfl) then goto found
@ @<Try the fourth choice for label direction@>=
case oct of
first_octant,eighth_octant,first_octant+8,eighth_octant+8: right_coords(p);
second_octant,third_octant,second_octant+8,third_octant+8: top_coords(p);
fourth_octant,fifth_octant,fourth_octant+8,fifth_octant+8: left_coords(p);
sixth_octant,seventh_octant,sixth_octant+8,seventh_octant+8: bot_coords(p);
end;
if not overlap(p,dfl) then goto found
@ @<Output all overflow labels@>=
@<Remove all rectangles from list, except for dots that have labels@>;
p:=label_head;
while p<>null do
begin @<Typeset an overflow label for |p|@>;
p:=next[p];
end
@ When we remove a dot that couldn't be labeled, we set its |next| field
to the preceding node that survives, so that we can use the |nearest_dot|
routine later. (This is a bit of a kludge.)
@<Remove all rectangles from list, except for dots that have labels@>=
p:=next[0];
while p<>end_of_list do
begin q:=next[p];
if (p<first_dot) or (label_for_dot[p]=null) then
begin r:=prev[p]; next[r]:=q; prev[q]:=r; next[p]:=r;
end;
p:=q;
end
@ Now we have to insert |p| into the list temporarily, because of the
way |nearest_dot| works.
@<Typeset an overflow label for |p|@>=
begin r:=next[dot_for_label[p]]; s:=next[r]; t:=next[p];
next[p]:=s; prev[s]:=p; next[r]:=p; prev[p]:=r;@/
q:=nearest_dot(p,0);@/
next[r]:=s; prev[s]:=r; next[p]:=t; {remove |p| again}
incr(overflow_line);
dvi_goto(over_col,overflow_line*thrice_x_height+655360);
hbox(info[p],label_font,true);
if q<>null then
begin hbox(equals_sign,label_font,true);
hbox(info[label_for_dot[q]],label_font,true);
hbox(plus_sign,label_font,true);
dvi_scaled((xx[p]-xx[q])/x_ratio+(yy[p]-yy[q])*fudge_factor);
dvi_out(",");
dvi_scaled((yy[q]-yy[p])/y_ratio);
dvi_out(")");
end;
dvi_out(pop);
end
@ @<Adjust the maximum page width@>=
if overflow_line>1 then page_width:=over_col+10000000;
{overflow labels are estimated to occupy $10^7\,$sp}
if page_width>max_h then max_h:=page_width
@* Doing the pixels.
The most interesting part of \.{GFtoDVI} is the way it makes use of a gray
font to typeset the pixels of a character. In fact, the author must admit having
great fun devising the algorithms below. Perhaps the reader will also
enjoy reading them.
The basic idea will be to use an array of 12-bit integers to represent the next
twelve rows that need to be typeset. The binary expansions of these integers,
reading from least significant bit to most significant bit, will represent
pixels from top to bottom.
@ We have already used such a binary representation in the tables
|c[1..120]| and |d[1..120]| of bit patterns and lengths that are potentially
present in a gray font; we shall now use those tables to compute
an auxiliary array |b[0..4095]|. Given a 12-bit number~$v$, the gray-font
character appropriate to $v$'s binary pattern will be~|b[v]|. If no
character should be typeset for this pattern in the current row,
|b[v]| will be~0.
The array |b| can have many different configurations, depending on how
many characters are actually present in the gray font. But
it's not difficult to compute |b| by going through the existing characters
in increasing order and marking all patterns~$x$ to which they apply.
@<Initialize glob...@>=
for k:=0 to 4095 do b[k]:=0;
for k:=font_bc[gray_font] to font_ec[gray_font] do
if k>=1 then if k<=120 then
if char_exists(char_info(gray_font)(k)) then
begin v:=c[k];
repeat b[v]:=k; v:=v+d[k];
until v>4095;
end;
@ We also compute an auxiliary array |rho[0..4095]| such that $\\{rho}[v]=2^j$
when |v| is an odd multiple of~$2^j$; we also set $\\{rho}[0]=2^{12}$.
@<Initialize g...@>=
for j:=0 to 11 do
begin k:=two_to_the[j]; v:=k;
repeat rho[v]:=k; v:=v+k+k;
until v>4095;
end;
rho[0]:=4096;
@ @<Glob...@>=
@!b:array[0..4095] of 0..120; {largest existing character for a given pattern}
@!rho:array[0..4095] of 1..4096; {the ``ruler function''}
@ But how will we use these tables? Let's imagine that the \.{DVI} file
already contains instructions that have selected the gray font and moved
to the proper horizontal coordinate for the row that we wish to process next.
Let's suppose that 12-bit patterns have been set up in array~|a|, and that
the global variables |starting_col| and |finishing_col| are known such
that |a[j]| is zero unless |starting_col<=j<=finishing_col|. Here's what
we can do, assuming that appropriate local variables and labels have
been declared:
@<Typeset the pixels of the current row@>=
j:=starting_col;
loop@+ begin while (j<=finishing_col)and(b[a[j]]=0) do incr(j);
if j>finishing_col then goto done;
dvi_out(push); @<Move to column |j| in the \.{DVI} output@>;
repeat v:=b[a[j]]; a[j]:=a[j]-c[v];
k:=j; incr(j);
while b[a[j]]=v do
begin a[j]:=a[j]-c[v]; incr(j);
end;
k:=j-k; @<Output the equivalent of |k| copies of character |v|@>;
until b[a[j]]=0;
dvi_out(pop);
end;
done:
@ @<Move to column |j| in the \.{DVI} output@>=
dvi_out(right4);
dvi_four(round(unsc_x_ratio*j+unsc_slant_ratio*y)+delta_x)
@ The doubling-up property of gray font character lists is utilized here.
@<Output the equivalent of |k| copies of character |v|@>=
reswitch: if k=1 then typeset(v)
else begin i:=char_info(gray_font)(v);
if char_tag(i)=list_tag then {|v| has a successor}
begin if odd(k) then typeset(v);
k:=k div 2; v:=qo(rem_byte(i)); goto reswitch;
end
else repeat typeset(v); decr(k);
until k=0;
end
@ @<Glob...@>=
@!a:array[0..widest_row] of 0..4095; {bit patterns for twelve rows}
@ In order to use the approach above, we need to be able to initialize
array~|a|, and we need to be able to keep it up to date as new rows
scroll by. A moment's thought about the problem reveals that we will either
have to read an entire character from the \.{GF} file into memory,
or we'll need to adopt a coroutine-like approach: A single \\{skip}
command in the \.{GF} file might need to be processed in pieces, since
it might generate more rows of zeroes than we are ready to absorb
all at once into~|a|.
The coroutine method actually turns out to be quite simple, so we shall
introduce a global variable |blank_rows|, which tells how many rows of
blanks should be generated before we read the \.{GF} instructions
for another row.
@<Glob...@>=
@!blank_rows:integer;
{rows of blanks carried over from a previous \.{GF} command}
@ Initialization and updating of~|a| can now be handled as follows,
if we introduce another variable~|l| that is set initially to~1:
@<Add more rows to |a|, until 12-bit entries are obtained@>=
repeat @<Put the bits for the next row, times |l|, into |a|@>;
l:=l+l; decr(y);
until l=4096;
@ As before, |cur_gf| will contain the first \.{GF} command that has
not yet been interpreted.
@<Put the bits...@>=
if blank_rows>0 then decr(blank_rows)
else if cur_gf<>eoc then
begin x:=z;
if starting_col>x then starting_col:=x;
@<Read and process \.{GF} commands until coming to the end of this row@>;
end;
@ @d do_skip==z:=0; paint_black:=false
@d end_with(#)==begin #; cur_gf:=get_byte; goto done1;@+end
@d five_cases(#)==#,#+1,#+2,#+3,#+4
@d eight_cases(#)==#,#+1,#+2,#+3,#+4,#+5,#+6,#+7
@d thirty_two_cases(#)==eight_cases(#),eight_cases(#+8),
eight_cases(#+16), eight_cases(#+24)
@d sixty_four_cases(#)==thirty_two_cases(#), thirty_two_cases(#+32)
@<Read and process...@>=
loop @+begin continue: case cur_gf of
sixty_four_cases(0): k:=cur_gf;
paint1:k:=get_byte;
paint2:k:=get_two_bytes;
paint3:k:=get_three_bytes;
eoc:goto done1;
skip0:end_with(blank_rows:=0; do_skip);
skip1:end_with(blank_rows:=get_byte; do_skip);
skip2:end_with(blank_rows:=get_two_bytes; do_skip);
skip3:end_with(blank_rows:=get_three_bytes; do_skip);
sixty_four_cases(new_row_0),sixty_four_cases(new_row_0+64),
thirty_two_cases(new_row_0+128),five_cases(new_row_0+160):
end_with(z:=cur_gf-new_row_0;paint_black:=true);
xxx1,xxx2,xxx3,xxx4,yyy,no_op:begin skip_nop; goto continue;
end;
othercases bad_gf('Improper opcode')
endcases;@/
@<Paint |k| bits and read another command@>;
end;
done1:
@ @<Paint |k| bits and read another command@>=
if x+k>finishing_col then finishing_col:=x+k;
if paint_black then for j:=x to x+k-1 do a[j]:=a[j]+l;
paint_black:=not paint_black;
x:=x+k;
cur_gf:=get_byte
@ When the current row has been typeset, all entries of |a| will be even;
we want to divide them by~2 and incorporate a new row with $l=2^{11}$.
However, if they are all multiples of~4, we actually want to divide by~4
and incorporate two new rows, with $l=2^{10}$ and $l=2^{11}$. In general,
we want to divide by the maximum possible power of~2 and add the corresponding
number of new rows; that's where the |rho|~array comes in handy:
@<Advance to the next row that needs to be typeset;
or |return|, if we're all done@>=
l:=rho[a[starting_col]];
for j:=starting_col+1 to finishing_col do if l>rho[a[j]] then l:=rho[a[j]];
if l=4096 then
if cur_gf=eoc then return
else begin y:=y-blank_rows; blank_rows:=0; l:=1;
starting_col:=z; finishing_col:=z;
end
else begin while a[starting_col]=0 do incr(starting_col);
while a[finishing_col]=0 do decr(finishing_col);
for j:=starting_col to finishing_col do a[j]:=a[j] div l;
l:=4096 div l;
end
@ We now have constructed the major components of the necessary routine;
it simply remains to glue them all together in the proper framework.
@p procedure do_pixels;
label done,done1,reswitch,continue,exit;
var @!paint_black:boolean; {the paint switch}
@!starting_col,@!finishing_col:0..widest_row; {currently nonzero area}
@!j:0..widest_row; {for traversing that area}
@!l:integer; {power of two used to manipulate bit patterns}
@!i:four_quarters; {character information word}
@!v:eight_bits; {character corresponding to a pixel pattern}
begin select_font(gray_font);
delta_x:=delta_x+round(unsc_x_ratio*min_x);
for j:=0 to max_x-min_x do a[j]:=0;
l:=1; z:=0; starting_col:=0; finishing_col:=0; y:=max_y+12; paint_black:=false;
blank_rows:=0; cur_gf:=get_byte;
loop@+ begin @<Add more rows...@>;
dvi_goto(0,delta_y-round(unsc_y_ratio*y)); @<Typeset the pixels...@>;
dvi_out(pop); @<Advance to the next...@>;
end;
exit:end;
@* The main program.
Now we are ready to put it all together. This is where \.{GFtoDVI} starts,
and where it ends.
@p begin initialize; {get all variables initialized}
@<Initialize the strings@>;
start_gf; {open the input and output files}
@<Process the preamble@>;
cur_gf:=get_byte; init_str_ptr:=str_ptr;
loop@+ begin @<Initialize variables for the next character@>;
while (cur_gf>=xxx1)and(cur_gf<=no_op) do @<Process a no-op command@>;
if cur_gf=post then @<Finish the \.{DVI} file and |goto final_end|@>;
if cur_gf<>boc then if cur_gf<>boc1 then abort('Missing boc!');
@.Missing boc@>
@<Process a character@>;
cur_gf:=get_byte; str_ptr:=init_str_ptr; pool_ptr:=str_start[str_ptr];
end;
final_end:end.
@ The main program needs a few global variables in order to do its work.
@<Glob...@>=
@!k,@!m,@!p,@!q,@!r,@!s,@!t,@!dx,@!dy:integer; {general purpose registers}
@!time_stamp:str_number; {the date and time when the input file was made}
@!use_logo:boolean; {should \MF's logo be put on the title line?}
@ \MF\ sets the opening string to 32 bytes that give date and time as follows:
$$\hbox{|' METAFONT output yyyy.mm.dd:tttt'|}$$
We copy this to the \.{DVI} file, but remove the `\.{METAFONT}' part so that
it can be replaced by its proper logo.
@<Process the preamble@>=
if get_byte<>pre then bad_gf('No preamble');
@.No preamble@>
if get_byte<>gf_id_byte then bad_gf('Wrong ID');
@.Wrong ID@>
k:=get_byte; {|k| is the length of the initial string to be copied}
for m:=1 to k do append_char(get_byte);
dvi_out(pre); dvi_out(dvi_id_byte); {output the preamble}
dvi_four(25400000); dvi_four(473628672); {conversion ratio for sp}
dvi_four(1000); {magnification factor}
dvi_out(k); use_logo:=false; s:=str_start[str_ptr];
for m:=1 to k do dvi_out(str_pool[s+m-1]);
if str_pool[s]=" " then
if str_pool[s+1]="M" then
if str_pool[s+2]="E" then
if str_pool[s+3]="T" then
if str_pool[s+4]="A" then
if str_pool[s+5]="F" then
if str_pool[s+6]="O" then
if str_pool[s+7]="N" then
if str_pool[s+8]="T" then
begin incr(str_ptr); str_start[str_ptr]:=s+9; use_logo:=true;
end; {we will substitute `\MF' for \.{METAFONT}}
time_stamp:=make_string
@* System-dependent changes.
This section should be replaced, if necessary, by changes to the program
that are necessary to make \.{GFtoDVI} work at a particular installation.
It is usually best to design your change file so that all changes to
previous sections preserve the section numbering; then everybody's version
will be consistent with the printed program. More extensive changes,
which introduce new sections, can be inserted here; then only the index
itself will get a new section number.
@^system dependencies@>
@* Index.
Here is a list of the section numbers where each identifier is used.
Cross references to error messages and a few other tidbits of information
also appear.
|