summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/doc/generic/knuth/errata/mf84.bug
blob: 0ce8ccbd74839a103e6779e390f208917ff990c6 (plain)
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
This file has been updated periodically ever since METAFONT84 was born.
What you are about to read is "authentic source material" from the
early days before the program converged. Module numbers on the first
entries may bear little relation to those in Volume D.

Entries are in chronological order; thus the most recent news appears
at the bottom of the file.

-------------------------------------------------------------------------------

(rough list of all bugs found in MF after it passed syntax check)
Starting with Version -100.0: [Mar 27, first run, about 00:30]
1. fix_date_and_time was badly patched in INIMF.
2. cur_tok function forgot "cur_tok:=p" at the end; PASCAL doesn't catch that.
3. "multiletter control sequences" msgs should say "symbolic tokens".
Version -99.0: [still Mar 27, done while waiting for WEAVE/TeX output]
4. do_statement should initialize cur_type:=vacuous.
5. find_variable has misplaced p:=equiv(p).
6. one-character primitives shouldn't decrease str_ptr.
7. clear_symbol had "q" at end where I meant to say "p".
8. help message for extra token flushing improved.
9. "buffer[k]" should be "buffer[j]" for 1-character id_lookup.
10. def_delims forgot to get_next afterwards.
11. type_command at beginning of statement wasn't diverted.
12. menu always came out after help message.
13. forgot to return after getting num/str token from token list.
Version -98.0: [March 28]
14. scan_declared_variable flushes too much.
15. ordered pairs: one level of indirection was forgotten.
16. type declarations must add "unknown" bit.
17. semicolon+ added to do_statement cases.
18. base_ident should get max_str_ref.
19. "internal[...]" missing in date for base_ident.
20. do_binary(p,c) should be do_binary(p,d) after continue_path
21. in scan_def after get_clear_symbol I need to get_next.
22. get_next needed at end of scan_def.
23. get_next needed at end of mode_command processing.
24. randomseed missing error typo: `;' for `:='.
25. print_nl("") at beginning of show.
26. refcounts on macro calls were incremented twice.
27. forgot to advance loc after getting num/str token from token list.
28. "/" has the wrong command code.
29. get_x_next needed after, e.g., "1/2" in scan_primary.
30. take_fraction should be make_fraction in call of frac_mult.
31. v:=dep_list(v) forgotten in dep+dep branch of add_or_subtract.
32. q:=link(q) etc misplaced and omitted in p_plus_fq and p_plus_q.
33. dep_finish recycled a dependency list twice.
34. call of dep_finish should use null not cur_exp.
35. decided that "3 3" shouldn't equal 9.
[also put in new code for the addto command]
Version -97.0: [March 29]
36. forget to set q:=qq in scan_expression.
37. first line of print_path: forgot print_ln.
38. typo in set_controls: right_y should be left_y.
39. toss_knot_list forgot that it has a circular list to toss.
40. print_exp shows big nodes backwards.
41. angle brackets didn't look good in print_exp; took them out.
42. left_brace must be between min_tertiary and max_tertiary.
43. prev_dep should point back to tail, not head, of previous list.
  (that error was in encapsulate and <Copy the big node>)
44. nonlinear_eq should leave node p vacant, sometimes.
45. conditional routine forgot that get_boolean starts with get_x_next.
46. forgot get_x_next in processing of else.
47. str_ref not initialized by make_string.
48. param_start not initialized properly.
49. "%EXPR" didn't look good in token list.
50. "{loop}" not necessary in forever loops; there's already enough.
51. macro name didn't come out right when tracing macros.
52. macro parameters weren't shown when tracing macros.
53. quote marks missing when displaying strings.
54. parameter names on macro call trace should look nicer.
55. statement beginning with bad token: error message needed.
56. `->' desired in context lines of macro.
57. forgot q:=loop_list_loc(s) in begin_iteration.
[also put in new code for shipout]
Version -96.0: [March 30]
58. forgot loop_type(s):=null in begin_iteration.
59. forgot value(p):=null after type(p):=type(pp) in find_variable.
60. forgot to delete_pen_ref after filling a contour.
61. check that it's a cycle before calling make_spec.
62. "if tracing_stats>0" should be "if internal[tracing_stats]>0"!
63. forgot get_next after showdependencies.
64. forgot link(r):=p at end of dependency list addition.
65. extra `get_x_next' in <Scan a direction...>.
66. typos in last half of <Remove open types...>: mind the p's and q's.
67. take_fraction should be make_fraction in simple case of two givens.
68. in print_exp of unknown type, stop if v=null.
69. showtoken forgot to stop; also should be consistent with TeX.
70. "continue" label needed in error routine, after all.
71. id_lookup should treat length-one identifiers by simpler method.
  (in particular, this allows it to find unprintable ones!)
72. need psi[n+1]:=psi[1] in cyclic case of make_choices.
73. tension/controls take primaries as arguments, not expressions.
74. print_spec didn't initialize octant.
75. print_spec: break lines into two, since they are quite long.
76. smooth_moves not called in fill_spec.
77. typo < for > in edge_prep.
78. edge tracing misses half the corners, and forgot to set trace_y.
79. edge_prep needs extra logic when rover=head.
80. make_good should compute cur_d based on good values, not original values;
  but we sometimes need the other alternative too.
81. valid_sum: the test was backwards.
82. print_weight blunder: ho(q) should be ho(info(q)).
83. forgot init_gf in shipout.
84. typo in <Finish the GF file>: if total_chars<>1 then print("s").
85. initializations of ww, prev_w, and m were forgotten in ship_out.
86. typos in initialization of prev_m and gf_min_x.
87. forgot to update prev_n in ship_out.
88. relax becomes "expandable".
89. internal[x]>1 should be internal[x]>unity!
90. forgot to restore normal scanner_status in pass_text.
91. (end occurred when if...) was inevitable.
[also put in new code for openwindow, display]
Version -95.0: [April 1]
92. forgot to unscale the window numbers in that new code.
93. had w<0 test instead of w<=0 in <Record a possible transition...>.
94. prev_w:=w should be done in all cases of <Record a possible...>.
95. forgot get_x_next after scanning `1/2'.
96. in do_assignment, after recycle_value(p) I need to set type(p):=something.
97. omit `.' after the equivalent in showtoken.
98. in <Copy the big node p>, I said "until q=p"; I meant "until q=value(p)".
99. print_macro_name said "info(link(a))"; meant "text(info(info(link(a))))".
100. forgot get_x_next after macro_call in scan_primary.
101. scan_primary installed dependent components badly (data structure error).
102. new_structure failed in case of generic_subscript (data structure error).
103. param_type case of print_cmd_mod had bad if/else nesting (language error).
104. null_path forgot to return a value (language error).
105. p_with_x_becoming_q had typos (q and f for x).
106. <Copy the big node...> should end with cur_exp:=t, not r.
107. subscripted definitions: out of sync; scan_primary loop needs revision.
108. secondarydef went through scan_def instead of make_op_def.
109. make_op_def forgot the final get_next.
110. make_op_def also forgot to insert the general_macro preface.
111. showvar shows too much of macro variables.
Version -94.0: [April 4]
112. single_dependency needs to take account of the scale factor.
113. add_or_subtract starts out with wrong v value. [bug 31 was fixed wrong]
114. print_exp needs a case for t=independent.
115. also numeric_type, and case v=null of pair_type, transform_type.
116. end_token_list thought identity_macro and insertions had ref counts.
117. disp_var should display also in case of generic subscripts.
118. find_var should put value(pp):=null when it sets type(pp):=numeric_type.
119. yet another problem in <Copy the big...>: copy_dep_list(dep_list(q)).
120. scan_primary should flush_node_list(q) before make_exp_copy(p).
121. make_scaled arguments reversed in p_over_v.
[also added code for new internals: smoothing, autorounding]
[also added code for showstats]
Version -90.0: [April 5]
122. Should check range of variables when they become known.
123. <Exclaim about...> should include begin...end (WEB language error).
124. forever should be followed by a colon.
125. dangling else problem in make_eq: "abc"="abc" considered false.
126. showstats, showtoken should read the semicolon before stopping.
127. print_variable_name balked at, e.g., xpart of a capsule.
Version -89.0: [April 6]
128. after &foo, shouldn't assume there's an input file present.
129. forever forgot get_next.
130. pair=path and path=pair should coerce the pair to be a path.
131. similarly in the operand to `addto'.
[added new code for cull command]
[minor revision of internal quantities; e.g., labeling is out, fontmaking is in]
Version -88.0: [April 7]
132. "string" operator is renamed "str".
133. min/max coordinates added to boc command.
134. labeling_command removed; it will be implemented in macros.
135. info(p) should be attr_loc(p) in flush_variable.
136. make_spec didn't realize the need for xh and yh.
137. gf_new_row parameters had sign reversed.
138. the "numeric" case was left out of recycle_value.
[added new code for special/numspecial]
Version -87.0: [April 13]
139. q:=qq should apply also after <Splice...>, in scan_expr.
140. param_size: better defined than a constant.
141. surprise: back_input fails when cur_cmd=expr_arg, as it changes limit.
142. <Subdivide...second time wrt x'-y'> forgot to change right_type(r).
143. show <path> shows the whole path.
144. expr like 0..1 leads to <Determine the path join...> with q undefined.
145. typos in <Decide...clockwise>, clobbered dx2 and used right_type(p) twice.
146. need to adjust expr_arg when macro is inside a macro!
147. expr_arg forbidden to be in a text argument.
148. frozen_relax added to prevent premature termination.
[I took out the code used for debugging the screen interface]
[added "cycle", a unary operator taking path to boolean]
[added the code for concatenation and for str and for xpart..yypart]
Version -86.0: [April 25]
149. not_scolded_yet was never set false after scolding.
150. Missing "q:=s" at the end of <Make variable q known>.
151. In @<Worry...@>, add get_next after back_error.
152. New xpart routine didn't recycle other components of the big node.
[added the "hard_times" case of multiplication]
[added the complete set of boolean expressions]
[added the eight transformations, applied to three kinds of expressions]
[added the save command]
[added the interim command]
[added the let command]
[added the pen operations]
153. Incomplete help message on "Not a variable".
154. forgot begin...end in the last section of materialize_pen.
155. blunder <Insert a new line...>: length(p,s,q) should be length(s,q,r).
156. <Construct the offset...>: forgot begin...end here too.
157. "(newly created)" shd be " (newly created)".
158. path_trans: forgot to unstash the capsule p.
159. set_up_trans: transform_type should be transformed_by, in one place.
160. <Install sines...>: had p instead of q, in several places.
161. edges_trans: an edges variable isn't in a capsule.
Version -85.0: [May 2]
162. begingroup ... endgroup should be allowed as compound statement.
163. pausing shouldn't clobber "showit". (WAITS version only)
164. Improved help message for isolated expressions.
165. Bad error recovery after "Not a variable" in showvar.
166. Typo in clear_symbol: name_type(p) instead of name_type(q).
167. "%" and ";" to be left out of file names being input.
168. dep_finish used v for two purposes; wrong declared type.
169. autorounding 2 suppresses correction when the derivative isn't critical.
170. tab characters should be changed to spaces on input. (WAITS version)
171. harmful goto: Forgot to |return| after path_trans and edge_trans.
[added ord, hex, oct, length, char, decimal, and jobname]
Version -80.0: [May 4]
172. showvar still screwed up.
173. don't clobber screen for prompt_input (WAITS only).
174. length of non-cyclic path is one too high.
175. <Evoke an error message...> evoked the wrong message.
176. better error message needed on `Equation cannot be performed'.
177. ">> " inserted before expression displays.
178. <Finish linking...> should dup_offset also when n=0.
179. pencircle was a factor of 2 too big.
180. cosine of 180 should be -1 exactly.
181. ord "" should be -1.
182. shipout should allow expressions as well as variables.
183. "mod outer_tag" needed in various tests on eq_type.
184. merge_edges forgot to adjust for changes in m_offsets.
185. typo, ww for w in print_pen.
186. typo, "outer" for "errhelp" in print_cmd_mod (message case).
[added "also"]
[added "message", "errmessage", "errhelp"]
[added "outer", "inner"]
[added "readterminal", "readstring"]
Version -79.0: [May 6]
187. read_toks forgot to include the general_macro token.
188. offset_prep should treat n=0 like n=1.
189. cusp transitions (from change 169) must be suppressed in envelope case.
190. <Record a line segment...> shouldn't change xp or yp.
191. <Find the initial slope...> was used too late.
192. <Find the index...> had a redundant test (a relic of old code).
193. <Compute test coeff...> wastefully made the same fraction three times.
194. doublepath <cycle> should split the cycle.
195. `if k=0' in fin_offset_prep should have been `if k=1'.
196. `done:' misplaced in <Make the envelope moves...>.
197. also move[move_ptr] should be initialized to 1 there, not 0.
198. skew is used with p=q in fill_envelope.
199. it's no use tracing subdivision for offsets, since everything is skewed.
200. in <Record a line...>, round_unscaled should be floor_unscaled.
201. unskewing: wrong formula (x was .5 too large).
202. elliptical pens: better correction for the case gamma<=abs(alpha).
203. dual env_move was updated badly, in both <Transfer...> and <Record...>.
204. dual env_move to move: subscripts were off by 1.
205. <Insert...dually...> should set ww:=knil(link(h)), not link(h).
[added ++]
Version -70.0: [May 9]
206. suppressed cusp rounding in envelope case too.
207. `show' should use `>> ' when it shows an expression.
208. streamlined the test for bad lambda and mu in |skew|.
209. after linear_eq, must check if type(cur_exp)=known.
210. print_spec surprise: contours might never travel toward the first octant!
211. t0,t1,t2 sign was reversed in <Complete the offset splitting...>.
Version -69.0: [May 10]
212. "showvar" changed to "showvariable".
213. typo: r for r_delim in <Scan a text parameter...>.
214. "newinternal" feature added.
215. <Record a line...dually...> needs to update envmove at end of loop.
216. smooth_moves shouldn't affect the extreme points.
217. floor(unity*(n-1)/n) is unity when n is large; need to be more careful.
218. major improvements to rounding, based on new theory of (x+eps,y+eps^2).
219. pen offsets made symmetrical about the origin.
220. p:=half(p+q) overflow problem in take_fraction, take_scaled.
221. cull_edges now updates the max/min values too.
222. make_spec needs to be more bullet-proof to rounding errors; added `dest's.
223. xmult/ymult/zmult changed to xscaled/yscaled/zscaled.
224. elliptical pens improved by temporarily allowing zero-length lines.
[added edge transposition algorithm]
Version -67.0: [May 17]
225. copy can encounter a vacuous expression, e.g. in a parameter.
226. xy_swap_edges mustn't change w when inserting a large weight.
227. in #222, had typo pp for r in <split ... second time ... x'-y'>.
228. in #222, incorrectly assumed local max = global max of cubic.
Version -66.0: [May 19]
229. bad_binary(c,p) should have been bad_binary(p,c).
230. enabled comparison of unknown strings.
231. fixed ring_delete to avoid unexpected scolding.
232. should store character width info even when proofing<0.
[added all the TFM commands and output routines]
[added the `substring' operation]
[added `point', `precontrol', `postcontrol'; deleted `direction']
Version -65.0: [May 24]
233. Change error message `(t)point(u)' to `point(t)of(u)'.
234. newinternal to allow a list of tokens.
235. In <Feed...>, should check for overflow before begin_token_list.
236. scan_def didn't allow for the case warning_info=null.
Version -60.0: [May 25]
237. increased param_size.
238. added <boolean><relation><boolean>.
239. <Remove dead cubics> stopped too early if the first cubic was dead.
240. bad_unary, bad_binary should distinguish pair from unknown pair.
241. yet another "m<env_move[move_ptr]" test needs to be inserted.
242. newinternal names need to go in the dump file.
243. delete_mac_ref(v) should be delete_mac_ref(value(p)) in recycle_value.
244. constant in <Decide...clockwise> was scaled instead of fraction.
Version -59.0: [May 27]
245. break up initialize routine into two parts (cf init_prim in TeX)
Version -58.0: [May 28]
246. do_ship_out should scan_expression, not scan_primary.
247. offset_prep might clobber node q, so we need to search for q again.
248. pair "1" = true! (blunder in type_test)
249. allow strings x in `def f(expr x)=def g=x enddef enddef'.
250. allow exprs in text parameters, in sufficiently easy cases.
251. check right delimiters in macro_call.
252. "Bad window number" message gave unscaled value.
253. turnaround feature improves automatic rounding slightly.
254. primaries changed to expressions in window and cull commands.
255. scan_expression should make (0,0){0,0} a path, not a future path.
256. showvariable and showtoken to allow lists; all shows made consistent.
257. new internal quantity "windingcheck".
258. delete warning message about edges never used.
259. vardef: group the righthand side.
260. show commands stop once each.
261. cur_type should be vacuous after equation or assignment on outer level.
Version -57.0: [June 4]
262. added xyzzy diagnostic about effect of autorounding.
263. make_moves now puts xi_corr,eta_corr into halving.
[otherwise "draw (0,0)..(9,-.00002)" and "draw (0,-.00002)..(9,0)" fail badly!]
Version -56.0: [June 6]
264. smooth_moves changed completely; now is LR symmetric, cleaner.
265. changed "unknown" to "known".
266. pair to path conversion now done on length, makepen, reverse, etc.
267. cycle now defined on arguments of any type.
268. (re 218) sign was flipped in ceiling correction of <insert downward...>.
[added union, subpath, penoffset, directiontime, intersectiontimes]

Note: the first two draw statements in PENS.mf show an interesting effect.
With autorounding, the curves are noticeably better, esp the small one.
But there are two "holes", because of tiny discrepancies that I believe
are unavoidable.
Added later: Actually these are avoided by the new smooth_moves, but
certain others will not be.
Version -50.0 [June 30]
269. smoothing to be shut off at the retrograde transitions
270. more care needed in the rootfinding part of find_direction_time.
271. improved error recovery after "Isolated expression".
Version -40.0 [July 3] --- the first version to be "complete"!
272. trivial change in <Exit...if the derivative $B(x_1,x_2,x_3;t)$...>.
273. check that halfwords are large enough to hold edge/weight data.
274. `path reverse (0,1)' should be true.
275. xy_swap_edges might empty the structure; then x_reflect will fail!
276. fix_offset was being done too often, due to improper range test.
277. parameters come out even when tracingonline=0.
278. step-until wasted r and didn't check syntax carefully.
279. <Scan a group...> had typo: `line' for `group_line'.
280. "You can't dump in a group" error was impossible.
281. need better ETC cutoff in showmacro.
282. print_exp needs to handle independents, because it's used by disp_var.
283. suppress `#### xpart %CAPSULEnnnn' printouts.
[added code for everyjob; this version wasn't complete after all!]
Version -30.0 [July 9]
284. need better error/help after ` if s1=s2' when the strings are unknown.
285. removed autorounding>2; it was leading to more glitches than it was worth.
286. envelope filling of a cycle to be done by two calls of fill_envelope.
287. "null" changed to "vacuous".
288. cyclic path inserted in another path should retain its last arc.
289. introduce several dozen "put_get" errors for improved recovery.
290. suppress "with autorounding" when autorounding hasn't been set.
291. {loop value} came out even when tracingonline=0.
292. show commands should wake up the terminal before showing their output.
293. forgot error message in `if true else'.
Version -20.0 [July 14]
294. need to catch pens that are too large.
295. make_eq dassn't change lhs (because this clobbers the memory links later).
296. string usage is reported too high by showstats.
297. bilin1 and add_mult_dep can call p_plus_fq with type(q)=proto_dependent.
298. <Transform a known big node> forgot to recycle pp.
299. in change number 286, the weight of the two paths should be the same.
300. print_ln sometimes changed to print_nl("") in order to avoid blank lines.
301. xyzzy to be combined with tracingedges.
302. good3 entries should be 1 and 2 (not 1 and 0), to give desired symmetry.
Version -10.0 [July 17]
303. had to add `new_if_limit' to `conditional'.
304. `else' can be incomplete as well as `if' and `elseif'.
305. new help "You can't redefine a parameter."
306. print_edges should use cur_edges, because print_weight does.
307. cull shouldn't round; it should use ordinary inequalities.
308. obliterated variable left `0' token hanging in scan_primary.
309. forgot recycle_value(p) in <Evoke...>.
310. forgot to check improper culling amounts.
311. `on' to be changed to `inwindow'.
312. >=max_tfm_dimen should be simply >.
Version -9.0 [July 19]
313. max_tfm_dimen needs to be decreased by design_size div 2^21.
314. merge test data reporting into the screen display routines.
315. use @# in printout at time of macro expansion tracing.
316. bad recovery after "Incomplete string" error.
317. @ should be usable as a parameter.
318. spacing bad on `missing of' and `too many parameters' errors messages.
319. keep track of largest str_ptr and pool_ptr values; showstats on two lines.
Version -8.0 [July 26] [introduced new test routines to study memory usage]
320. make_pen doesn't recycle the knots
321. flush_below often says free_node(2) on node of size 3.
322. make_eq should recycle and free; do_equation shouldn't
323. re #298 and #309: should also free the value nodes!
324. the replacement text of a bad_var definition should be recycled.
325. token lists left unrecycled in error recovery of addto, cull, display.
Version -7.0 [July 27]
326. showall to put "(see the transcript file)" after >> if not tracingonline.
327. remove redundant code: hex in print_the_digs; second l=1 in idlookup.
328. procedures never called: b_open_in; round_scaled.
329. need to zero cur_mod after back_expr in <Put the left bracket...>.
330. <Print the coefficient...> now catches also numbers that round to 1.0.
331. known_pair logic was obsolete; now it is massively simpler.
332. fix_check_sum now zeroes the negative bytes; this simplifies other code.
333. show_dependencies not to show parts of capsules.
334. forgot to set fix_needed:=false!
335. move fix_needed from add_or_subtract to dep_finish.
336. test fix_needed in bilin1 and add_mult_dep.
337. after back_expr in <Scan a mediation...>, forgot to unstash p.
Version 0.0 [July 28] [Hurray! The preliminary TRAP test is fully passed.]
338. corrected blunder in definition of trans_spec type. (found by Karney)
339. less extreme starting values of gf_min_x and its cousins.
340. uninitialized left_curl was possible. (found by John Hobby)
341. In <Reduce...straight line...>, need to test sign before the `div 3' ops.
342. In pyth_add, remove `+2' when dividing by 4, to prevent overflow.
343. "Not a variable" changed to "Not a suitable variable".
344. known_pair forgot to reset cur_type.
345. round and floor procedures need to work in the presence of huge arguments.
346. major revision to allow independent variables to disappear silently:
346a. delete null_path and <Declare the null value routines>.
346b. delete the hard part of ring_delete, and delete <Scold...for using...>.
346c. stash/unstash/flush_cur_exp routines to allow independent type.
346d. print_exp to allow a ring that contains only capsules.
346e. <Zero out...> becomes <Recycle an independent variable> (major new code).
346f. stash_in needs code to handle the case cur_type=independent.
346g. negation needs code to handle the case cur_type=independent.
346h. take_part needs code to handle the case cur_type=independent.
346i. do_binary needs code to handle either or both operands independent.
346j. frac_mult needs code to handle the case cur_type=independent.
346k. make_eq and try_eq too.
346l. linear_eq needs to check if cur_exp=x and cur_type=independent.
346m. linear_eq displays new dependency only when lhs is interesting.
347. minor improvement for coding style/brevity: the "interesting" function.
348. test `if t<independent' had been left out of print_exp (was dirty PASCAL).
349. (begingroup save x;x+1000 endgroup,0) caused subtle bug during unsave.
350. print_type(known) changed to "known numeric" for consistency.
351. In <Change...to proto_dependent>, didn't watch for coefficients zeroed.
352. check_mem now checks also the links in the dependency lists.
353. null_pen initialization belongs in <Initialize tab...>, not <Set init...>.
354. fix_dependencies has to worry about coefficients dropping to zero.
355. add tracing to frac_mult.
356. need cur_sym>0 at the time of end_read_terminal. (found by S Robinson)
Version 0.1 [August 30]
357. Don't complain about winding_number<=0 when doing a doublepath.
358. Need to test for max_coef=0 in offset_prep.
359. Cusp detection should allow for more rounding error.
360. Major change to path syntax, allowing {dir}..{dir} path joins.
360a. `Fragments' disappear; new_fragment becomes new_knot.
360b. print_path has simpler conventions.
360c. future_path type disappears.
360d. left_brace renumbered and removed from scan_tertiary.
360e. some scan_tertiary code moves to new subroutine scan_direction.
360f. scan_expression has a bunch of new code.
361. scan_expression shouldn't have returned after cycle_hit.
362. abort_path, scrap_knot logic removed from scan_expression.
Version 0.2 [September 12]
363. new operator: makepath <pen primary>.
364. define point/precontrol/postcontrol at endpoints and beyond. (JDH)
365. union replaced by +; negation and subtraction allowed on edges.
366. another new operator: totalweight <edges primary>. (JDH's idea)
367. undelimited parameters may be preceded by an optional = or :=.
368. base_area_length was wrong. (affects CH files)(found by Pavel)
369. internal names to be allowable in suffixes.
370. label not_found was misplaced in do_add_to. (found by PasMESA translator)
371. progress report should be given at time of shipout.
372. procedures make_choices, make_spec,fill_envelope split into shorter pieces.
373. locals of cubic_intersection made global so that people could split it.
Version 0.3 [September 27]
374. allow <future pen> ::= <pen> <transform>
375. equation that's off by .0001 shouldn't be called inconsistent.
376. bug in skew: must compute x_coord(q) and y_coord(q) exactly.
377. right/left/up/down to be assigned to octants 1/5/2/6; was 1/4/2/7.
378. boundedness to be allowed with any tension, and one-sidedly.
379. eliminate coordinate nodes in path lists by passing angles instead (JDH).
380. known_pair to free cur_exp after error msgs that might showdependencies.
381. scan_primary sometimes accessed num before it had a value (found by Pavel).
382. invalid characters should cause error message (suggested by PMB).
Version 0.4 [October 12]
383. allow `0' in response to error prompts.
384. put loop value on error context lines.
385. change `ord' to `ASCII'.
386. scantokens <string primary> to be permitted; readterminal goes away.
387. expandafter <token> to be permitted.
388. improved overflow conventions on make_fraction, make_scaled.
389. variable=<value over 4096> should get its own error message.
390. nice_pair first argument can be any integer.
391. new feature, shortshow commands that don't pause.
392. "harmless" bug in negate_edges, the sorted list can get out of sorts.
393. ni too skimpy (15 instead of 63). (JDH)
394. loop_ptr not initialized. (found by Paul Richards)
395. bug in <Find the approximate type...>, q=null should goto done1. (Richards)
396. empty_edges macro added for readability.
397. x_reflect_edges might as well fix the offset as it goes.
398. blunder: frozen_bad_vardef had the wrong eq_type.
399. "name" changed to "tag".
400. check_arith inserted after division of numeric tokens.
401. stop_bit was not initialized in <Compile a ligature/kern...>.
402. char 127 to be a string of length 1; slow_print added (therefore).
403. pyth_sub added to the repertoire.
404. minor change to calls on "confusion" in make_fraction, make_scaled. (JJW)
Version 0.5 [November 9]
405. 4095.999999 should be erroneous.
406. length <pair> to give the absolute value; argd changed to "angle".
407. get_next changed to get_x_next wherever possible.
408. z1..z2{curl 0} should be equivalent to z1..{curl 0}z2.
409. scantokens "" should be fast.
410. allow undelimited suffix and text parameters.
411. warningcheck to allow large variable values passed over silently.
412. "edges" changed to "picture".
413. "winding" changed to "turning".
414. <If consecutive knots...> had typo, "p" for "q".
415. elliptical pens should have axis symmetry.
416. slow_add introduced to catch arithmetic overflow on addition.
417. add a turningnumber primitive.
418. no carriage return between ">>" and "Edge structure...".
419. install new memory management routines (from TeX version 1.3).
420. generalized cull command. (suggested by Bruce Leban)
421. bad goto: `x..' reports that x is vacuous, loses value of x.
422. shortshows replaced by an internal variable "showstopping".
423. major change, capsule tokens: lots of code and restrictions gone! (JDH)
424. substring(a,b), subpath(a,b) to reverse the result when a>b.
425. new GF format: z goes away. (suggested by ALS)
426. another GF mod: chardw replaced by chardx/chardy, which are scaled. (PMB)
427. make `&' have the same precedence always (not different for strings).
428. wrong error message for 2"s" (bug introduced in change 369).
429. variable l in show_context has to be declared type integer.
430. bug in chop_path when both limits are large.
Version 0.6 [December 10]
431. xoffset and yoffset to be added by shipout. [this affects GF comments]
432. wake_up_terminal, not t_open_out, before "Ouch..." (Scott Robinson)
433. undelimited suffix parameters to allow an optional delimiter, disallow =.
434. showall... to be eliminated; tracingcapsules added.
435. allow undelimited parameters after delimited ones.
436. nullpen test in addto should test for any one-point pen.
437. granularity parameter to affect autorounding (Bruce Leban)
[this leads to major improvements suggested by JDH; lots of code changes!]
[basically, make_spec is now responsible for autorounding; fill_spec just fills]
438. node_size overflow problem must be prevented. (Paul Richards)
439. allow unary + with a picture.
440. nullpen should transform quickly to itself, if not shifted.
441. print_edges should skip over null rows, if it doesn't already.
442. open_base_file improved (following TeX's change number 302).
443. output initialization improved (following TeX's change number 303).
444. operators shouldn't fail because future pen isn't a pen. (JDH)
445. intersection routine to quit in hard cases. (DRF)
446. angle routine was off by epsilon on negative arguments. (Karney)
447. octant assignment should look ahead further in ambiguous cases. (JDH)
448. <Compute the incoming...> forgot that right_type(r)=endpoint could happen.
449. turning_number calculated directly, not times 8.
450. floor_scaled made more efficient by trading subtraction for multiplication.
451. doublepath autorounding to compromise between east and west. (JDH)
452. codes of picture_type and path_type interchanged, to simplify a "case".
Version 0.7 [January 17, 1985]
453. def to allow both := and =. (NB)
454. "keeping" and "dropping" instead of "including" and "excluding". (HWT)
455. (see the transcript...): why, when tracingonline>0?
456. dead cubics need to be removed also before xy_round. (NB)
457. [re 433] I said get_x_next twice; a blunder.
Version 0.75 [January 23, 1985]
458. Abbreviated boc command makes GF format more attractive for lowres. (GusF)
Version 0.76 [February 2]
459. known and unknown might as well both be primitive.
460. ab_vs_cd(a-d,b,c-b,d) simplifies to ab_vs_cd(a,b,c,d). (JDH)
461. (from change 435) <Absorb undelimited...> must use k, not n.
462. (from change 458) max_new_row added, since 165 wasn't updated to 164.
Version 0.77 [February 16]
463. abbreviated version of tracingspecs is desired for turning number errors.
464. improved octant number in pathological cases of quadrant_subdivide (JDH)
465. xoffset,yoffset communicated to GF file when proofing>0.
466. Poirot changed to Marple.
467. reverse<cycle> starts the reversed path at the wrong time.
468. Extra help given after `undefined coordinate' errors.
469. Keep segment numbers from overflowing max_halfword. (JDH)
470. Ditto for pen offset slope numbers.
471. n_magic had min_halfword with wrong sign. (John Johnson)
Version 0.80 [April 1]
472. In errhelp, % means <return>, %% means %. (BPL)
473. tracing of envelopes should give symbolic octant names.
474. (-x mod y) should be ((-x) mod y) in good_val.
475. crossingpoint could overflow on 32-bit machines. (BPL)
476. Improvements to abbreviated format of number 463.
Version 0.81 [April 4]
477. `I hide(showdependencies)' in hint to become `I ???'.
478. print_strange shouldn't wake up the terminal in scroll mode. (cf 463)
479. flush_list procedure made a bit faster. (DRF)
480. bounded velocities to be multiplied by .999 for safety.
481. Detect error in declaration that tries to extend a vardef.
482. print_strange puts turns in parentheses (cf 463).
483. make_name_string shouldn't ever cause string space overflow.
484. allow <picture primary> xscaled m yscaled n.
485. checksum should consider values relative to designsize. (DRF)
[I also increased max_strings to 2000.]

[Note: Neenie found a case where missing pixels can occur, due to
inconsistent rounding between left-to-right and right-to-left subdivision:
pickup pencircle; draw
(0,126)..controls (130.29451,126) and (288,126.00002)
 ..(288,36)..controls (288,143.99998) and (132.97438,144)
 ..(0,144)..controls (0,138) and (0,132)
 ..cycle;
The "right" way to fix this would be to develop a make_spec routine for
non-cycles, and to copy a reversed spec, so that double paths would be
guaranteed self-inverse. However, my later experiments showed that
autorounding wasn't nearly as useful as I had expected it to be, hence I
decided not to waste time beefing up this routine; no satisfactory
automatic approach to rounding occurs to me.]
Version 0.90 [May 10]
486. 180-degree turns to be clockwise for half of doublepath cycles.
487. introduce fillin parameter.
488. `numeric_type' moved before `known', so that print_exp works (Richards).
489. numeric_type as unary op should include independent in its range (cf 346).
Version 0.91 [May 13]
490. show_token_list gets null_tally parameter.
491. if bad>0, change the code as in TeX changes 315, 316.
492. batchmode change as in TeX 317.
493. "and double autorounding" to be traced, if appropriate.
494. introduce tracingrestores.
         *`restoring a bad variable'?
495. put decimal number into gf extension
496. mediation put into scan_primary, so that round .5[a,b] works properly.
497. cubic_intersection now has |tol| to compensate for rounding errors.
498. find_direction_time needs to worry about degenerate case x3=y3=0.
499. crossing_point(a,b,0) now yields fraction_one if a,b>0.
500. diag_round shouldn't insist that b-a is even (see below).
501. macro_call will show_macro with much larger limit.
502. TFM file statistics are logged too.

* Here's an example (found by Neenie) explaining bugfix 500:
autorounding:=2; draw
(7.03159,-9.31831)..controls (12.14732,-9.4386) and (17.4299,-6.82948)
 ..(21.60132,0)..controls (27.47417,9.61507) and (37.87402,15.58647)
 ..(43.74687,25.20154)..controls (51.16223,37.34201) and (57.31,50.171)
 ..(63.45776,63.00002) withpen pencircle;
The missing pixels are due to the following curious circumstances: (1) the
middle cubic splits into three, when subdividing into octants; (2) the reverse
curve splits too but with slightly different rounding, off by 1; (3) the old
diag_round routine, when it ensures that b-a is even, computes aa=a+1 on
one side of the curve, but aa=a-1 on the other side, thus making the
rounding "safe" on only one side. (Namely, on one side we have consecutive
values
  b=1317666 a=1310720
  b=1329617 a=1310721
and on the other side,
  b=-1329618 a=-1310720
  b=-1317667 a=-1310721.)

* Here's an example (by JDH) showing the necessary of bugfix 497:
path p[];
p1 = (1,0)..controls (1,0.10493) and (0.98347,0.20921)
     ..(0.95105,0.30902)..controls (0.91862,0.40881) and (0.8707,0.50288)
     ..(0.80902,0.58778);
p2 = (0,0)..controls (0.63403,0.20601) and (1.26807,0.41203)
     ..(1.9021,0.61804);
show p1 intersectiontimes p2;    % (-1,-1), without `tol'
pickup pencircle;
currenttransform := identity scaled 150;
draw p1; draw p2;
showit;          % but they clearly intersect
Version 0.95 [Aug 12]
503. `Se' changed to `SSE', etc. (suggested by RFS)
504. Inconsisting diagonal rounding was introduced in bugfix 500.

[the following lines from @<Determine the before...@> in diag_round:
    if aa>bb then cc:=dd-half(aa-bb-1)@+else cc:=dd-half(aa-bb+1)
  if a>b then c:=d-half(a-b-1)@+else c:=d-half(a-b+1)
were replaced respectively by:
    if right_type(p)>switch_x_and_y then cc:=dd-half(aa-bb+1)
    else cc:=dd-half(aa-bb-1)
  if right_type(p)>switch_x_and_y then c:=d-half(a-b-1)
  else c:=d-half(a-b+1)
in order to make the rounding consistent on adjacent octants;
the following command caused `this can't happen':
fill (33,7)..controls (32.63094,5.70827) and (32.06163,3.716)
 ..(31.59488,3.36667)..controls (31.10509,3.00009) and (29.14824,3)
 ..(27.85318,3)..controls (27.85286,3) and (23.84952,3)
 ..(23.8492,3)..controls (23.73282,2) and (23.61646,1)
 ..(23.50008,0)..controls (26.66672,0) and (29.83336,0)
 ..(33,0)..controls (33.66667,2.33333) and (34.33333,4.66667)
 ..(35,7)..controls (34.33333,7) and (33.66667,7)
 ..cycle;]
Version 0.96 [Aug 17]
505. allow comparison of transforms. [test by trying t=t when t is new...]
506. {restoring...} shouldn't get through when tracingonline=0.
507. better error message needed on `interim alpha:=0', `interim 0:=0'.
508. make_op_def should put parameters in the other order.
509. <Worry about...> should say get_x_next, not get_next.
510. unif_rand to allow negative x, save on error messages.
511. tidy up chop_string when b<0 and/or a>l.
512. randomseed is automatically logged.
513. change 495 messed up if gf file couldn't be opened. (found by DRF)
[In INIMF.CH, 3-character extensions now have 0--9 or A--Z as leading digit.]
Version 0.97 [Sep 5]
514. a[b,c] to be tried only if a is numeric type.
515. simplified the code for length_op(string_type).
516. citations of `Chapter xx' now replaced by correct references.
517. <Log the subfile sizes...> to be in stat...tats version only.
518. remove extra space after <insert> and <scantokens>.
519. offsets should be included in the tracingoutput output.
520. a vacuous expression should be considered known.
521. charlist syntax changed from commas to colons.
[also the WAITS version command-line reader was fixed to handle `^^W']
Version 0.99 [Sep 24]
522. vardef's begingroup...endgroup should be accessible.
523. allow an empty expression in for loops.
Version 0.999 [Oct 1]
524. "charfam" changed to "charext".
525. variable tt makes get_node slightly faster. (PROFILE suggests this)
526. cur_cmd<=max should be tested before cur_cmd>=min. (PROFILE)
527. fast_get_avail used in cur_tok and scan_primary. (PROFILE)
Version 0.9999 [Oct 27]
528. Major change to representation of independent variables
 ("serial number" added so that MF's equation solving doesn't depend
 on vagaries of storage allocation)
 [module number change: new module between old 585 and 586]
 [in terms of new numbering, modules 232, 585--587, 589, 594, 597,
    601, 608, 610, 816--817, 855, 1198--1199 were affected]
[I also reordered some of the cases in print_op, module 189,
so that the program could be condensed in published version]
Version 0.99999 [Nov 13]
529. forgot to decrease three_l in change 497!
530. cubic_intersection to give approximation if max_patience exceeded.
[the following example, found by NB, motivated this change:
 show (
  (36.00104,26.99951)..controls (36.00131,26.99979) and (36.00146,27.00017)
   ..(36.00146,27.00055)
   )intersectiontimes(
  (36,27.00055)..controls (45.17148,21.12364) and (55.83588,18)
   ..(66.72873,18)
  );]
Version 0.999999 [Dec 2]
531. hold_head needed (scan_toks calls cur_tok calls copy_edges). (D. Kosower)
Version 1.0 [January 4, 1986]
532. Optimization in module 1174, suggested by LER (3 Feb 86)
@x
  if delta=0 then gf_out(skip0)
  else  begin gf_out(skip1); gf_out(delta);
    end
@y
  begin gf_out(skip1); gf_out(delta);
  end
@z
*** Late copies of version 1.0 include this correction;
in particular, the program listing in Volume D was updated (with scissors)!
Changes subsequent to `Version 1.0' as published in C&T, Volume D:
533. Inconsistent punctuation in user messages (found by Karl Berry, June 86)
@x module 1134
print_nl("Font metrics written on "); print(metric_file_name);
@y
print_nl("Font metrics written on "); print(metric_file_name); print_char(".");
@z (that was installed in version 1.1)

534. Possible arithmetic overflows (found by Klaus Guntermann, July 86)
@x module 496
while max_coef<fraction_one do
@y
while max_coef<fraction_half do
@z (that was installed in version 1.2)

535. Possible loop in nonstopmode (found by Chris Thompson, July 86)
@x module 1206
    @<Finish the \.{TFM} file@>;
@y
    internal[fontmaking]:=0; {avoid loop in case of fatal error}
    @<Finish the \.{TFM} file@>;
@z (that too was installed in version 1.2)

536. Double rounding error should be avoided in make_ellipse (JDH, 22 Nov 86)
@x module 533
d:=take_fraction(d,delta);
alpha:=abs(u); beta:=abs(v);
if alpha<beta then
  begin delta:=alpha; alpha:=beta; beta:=delta;
  end; {now $\alpha=\max(\vert u\vert,\vert v\vert)$,
      $\beta=\min(\vert u\vert,\vert v\vert)$}
if internal[fillin]<>0 then d:=d-take_fraction(internal[fillin],beta+beta);
d:=(d+4) div 8; alpha:=alpha div half_unit;
@y
alpha:=abs(u); beta:=abs(v);
if alpha<beta then
  begin alpha:=abs(v); beta:=abs(u);
  end; {now $\alpha=\max(\vert u\vert,\vert v\vert)$,
      $\beta=\min(\vert u\vert,\vert v\vert)$}
if internal[fillin]<>0 then
  d:=d-take_fraction(internal[fillin],make_fraction(beta+beta,delta));
d:=take_fraction((d+4) div 8,delta); alpha:=alpha div half_unit;
@z (That was the reason for version 1.3)

537. Trivial change to a help message (version number is still 1.3).
@x module 1086
  ("Pretend that you're Miss Marple, examine all clues,")@/
@y
  ("Pretend that you're Miss Marple: Examine all clues,")@/
@z

538. Storage allocation can be more elegant and efficient (4/21/87)
@x module 169
if r=p then if ((rlink(p)<>rover) or (llink(p)<>rover)) then
@y
if r=p then if rlink(p)<>p then
@z

539. Unused variables can be eliminated. (Found by John Sauter, 5/5/87)
@x module 158
@<Glob...@>=
@!temp_ptr:pointer; {a pointer variable for occasional emergency use}

@y (I used it only in my change file!)
@z
@x module 280
@!r,@!s,@!t:pointer; {registers for list traversal}
@y
@!s,@!t:pointer; {registers for list traversal}
@z
@x module 284
@!sine,@!cosine:fraction; {trig functions of various angles}
@y (the declarations in module 281 are correct, but in 284 they're superfluous)
@z
@x module 497
var @!q,@!ww:pointer; {for list manipulation}
@!du,@!dv:scaled; {for slope calculation}
@!t0,@!t1,@!t2:integer; {test coefficients}
@!t:fraction; {place where the derivative passes a critical slope}
@!s:fraction; {slope or reciprocal slope}
@!v:integer; {intermediate value for updating |x0..y2|}
begin loop
  begin q:=link(p); right_type(p):=k;
@y
var @!ww:pointer; {for list manipulation}
@!du,@!dv:scaled; {for slope calculation}
@!t0,@!t1,@!t2:integer; {test coefficients}
@!t:fraction; {place where the derivative passes a critical slope}
@!s:fraction; {slope or reciprocal slope}
@!v:integer; {intermediate value for updating |x0..y2|}
begin loop
  begin right_type(p):=k;
@z
@x module 652
@!s:0..param_size; {value of |param_start| on the current level}
@y who knows why that line was there?
@z
@x module 862
var @!p,@!q,@!r:pointer; {for list manipulation}
@y
var @!p:pointer; {for list manipulation}
@z
@x module 985
@!vv:scaled; {initial value of |v|}
@!q:pointer; {successor of |p|}
begin vv:=v; p:=cur_exp;@/
@y
@!q:pointer; {successor of |p|}
begin p:=cur_exp;@/
@z
@x module 1059
@!t:small_number; {variant of |with_option|}
@y
@z

540. Typo suppresses an error detection (Chris Thompson, 2May88)
@x module 963
 if txy mod unity=0 then if tyy mod unity=0 then
@y
 if txx mod unity=0 then if tyy mod unity=0 then
@z

541. get_x_token can lose a scanned declared variable (Chris Thompson, 4May88)
@x module 1011
if equiv(x)=null then new_root(x);
@y
@z
@x module 1011
done:scan_declared_variable:=h;
@y
done: if eq_type(x)<>tag_token then clear_symbol(x,false);
if equiv(x)=null then new_root(x);
scan_declared_variable:=h;
@z

542. Avoid negative divisor rounding upward (Chris Thompson, fixed 19Jun88)
@x module 168
else t:=(lo_mem_max+hi_mem_min+2) div 2; {|lo_mem_max+2<=t<hi_mem_min|}
@y
else t:=lo_mem_max+1+(hi_mem_min-lo_mem_max)div 2; {|lo_mem_max+2<=t<hi_mem_min|}
@z

543. Better strategy when near memory overflow (Chris Thompson)
@x module 168
begin if lo_mem_max+1000<hi_mem_min then t:=lo_mem_max+1000
@y
begin if hi_mem_min-lo_mem_max>=1998 then t:=lo_mem_max+1000
@z

544. Avoid fatal_error after terminal eof (Tim Morgan, reported 25Oct88)
@x module 66 [serious problem occurred if this was called in open_log_file]
if not input_ln(term_in,true) then fatal_error("End of file on the terminal!");
@y
if not input_ln(term_in,true) then t_open_in;
@z

545. Force terminal output when open_log_file aborts (6Nov88)
@x module 789
  begin print_err("I can't write on file `");
@y
  begin selector:=term_only; print_err("I can't write on file `");
@z

546. By popular request, undo #544 and fix the bug a more complex way.
@x module 66 [this undoes change #544]
if not input_ln(term_in,true) then t_open_in;
@y
if not input_ln(term_in,true) then fatal_error("End of file on the terminal!");
@z
@x module 87 [now we get to the new stuff]
begin if job_name>0 then selector:=term_and_log
@y
begin if log_opened then selector:=term_and_log
@z
@x module 88
  error;
@y
  if log_opened then error;
@z
@x module 782
@!job_name:str_number; {principal file name}
@y
@!job_name:str_number; {principal file name}
@!log_opened:boolean; {has the transcript file been opened?}
@z
@x module 783
@<Initialize the output...@>=job_name:=0;
@y
@<Initialize the output...@>=job_name:=0; log_opened:=false;
@z
@x module 788
selector:=log_only;
@y
selector:=log_only; log_opened:=true;
@z
@x module 789
begin if interaction<scroll_mode then {bypass |fatal_error|}
  begin selector:=term_only; print_err("I can't write on file `");
@.I can't write on file x@>
  print_file_name(cur_name,cur_area,cur_ext); print("'.");@/
  job_name:=0; history:=fatal_error_stop; jump_out;
  end; {abort the program without a log file}
@y
begin selector:=term_only;
@z
@x module 1023 [this change is optional, but it's a slight improvement]
  if job_name<>0 then selector:=selector+2;
@y
  if log_opened then selector:=selector+2;
@z
@x module 1205
if job_name>0 then
@y
if log_opened then
@z
@x module 1208
if job_name>0 then {the log file is open}
@y
if log_opened then
@z

547. String startup problems corresponding to TeX change 355 (17 Jul 89)
@x module 30 (Warning: This affects most change files!)
        overflow("buffer size",buf_size);
@:METAFONT capacity exceeded buffer size}{\quad buffer size@>
@y
        @<Report overflow of the input buffer, and abort@>;
@z
@x module 34
consist of the remainder of the command line, after the part that invoked \MF.
@y
consist of the remainder of the command line, after the part that invoked \MF.

The first line is special also because it may be read before \MF\ has
input a base file. In such cases, normal error messages cannot yet
be given. The following code uses concepts that will be explained later.

@<Report overflow of the input buffer, and abort@>=
if base_ident=0 then
  begin write_ln(term_out,'Buffer size exceeded!'); goto final_end;
@.Buffer size exceeded@>
  end
else begin cur_input.loc_field:=first; cur_input.limit_field:=last-1;
  overflow("buffer size",buf_size);
@:METAFONT capacity exceeded buffer size}{\quad buffer size@>
  end
@z
@x module 1193
k:=pool_ptr-4; undump_four_ASCII
@y
k:=pool_ptr-4; undump_four_ASCII;
init_str_ptr:=str_ptr; init_pool_ptr:=pool_ptr;@/
max_str_ptr:=str_ptr; max_pool_ptr:=pool_ptr
@z
@x module 1204
tini@/
@y
init_str_ptr:=str_ptr; init_pool_ptr:=pool_ptr;@/
max_str_ptr:=str_ptr; max_pool_ptr:=pool_ptr; fix_date_and_time;
tini@/
@z
@x module 1204
init_str_ptr:=str_ptr; init_pool_ptr:=pool_ptr;@/
max_str_ptr:=str_ptr; max_pool_ptr:=pool_ptr;@/
@y
@z

548. Major changes to allow 8-bit input, cf. TeX82 #359 (11 Sep 89).
@x module 18
@!ASCII_code=0..127; {seven-bit numbers}
@y
@!ASCII_code=0..255; {eight-bit numbers}
@z
@x module 19
@d last_text_char=127 {ordinal number of the largest element of |text_char|}

@<Local variables for init...@>=
@!i:0..last_text_char;
@y
@d last_text_char=255 {ordinal number of the largest element of |text_char|}

@<Local variables for init...@>=
@!i:integer;
@z
@x module 21
xchr[0]:=' '; xchr[@'177]:=' ';
  {ASCII codes 0 and |@'177| do not appear in text}
@y
@z
@x module 22
for i:=1 to @'37 do xchr[i]:=' ';
@y changing ' ' to chr(i) here will allow all 8-bit characters to get in
for i:=0 to @'37 do xchr[i]:=' ';
for i:=@'177 to @'377 do xchr[i]:=' ';
@z
@x module 23
for i:=1 to @'176 do xord[xchr[i]]:=i;
@y
for i:=@'200 to @'377 do xord[xchr[i]]:=i;
for i:=0 to @'176 do xord[xchr[i]]:=i;
@z
@x module 37
@<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|}

@ @<Glob...@>=
@!str_pool:packed array[pool_pointer] of ASCII_code; {the characters}
@y [OK to make si(#)==#-128 and so(#)==#+128 (without parens) in change files]
Some \PASCAL\ compilers won't pack integers into a single byte unless the
integers lie in the range |-128..127|. To accommodate such systems
we access the string pool only via macros that can easily be redefined.

@d si(#) == # {convert from |ASCII_code| to |packed_ASCII_code|}
@d so(#) == # {convert from |packed_ASCII_code| to |ASCII_code|}

@<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|}
@!packed_ASCII_code = 0..255; {elements of |str_pool| array}

@ @<Glob...@>=
@!str_pool:packed array[pool_pointer] of packed_ASCII_code; {the characters}
@z
@x module 41
begin str_pool[pool_ptr]:=#; incr(pool_ptr);
@y
begin str_pool[pool_ptr]:=si(#); incr(pool_ptr);
@z
@x module 45
  begin if str_pool[j]<>buffer[k] then
@y
  begin if so(str_pool[j])<>buffer[k] then
@z
@x module 47
var k,@!l:0..127; {small indices or counters}
@y
var k,@!l:0..255; {small indices or counters}
@z
@x module 47
@<Make the first 128 strings@>;
@y
@<Make the first 256 strings@>;
@z
@x module 48
@ @<Make the first 128...@>=
for k:=0 to 127 do
  begin if (@<Character |k| cannot be printed@>) then
    begin append_char("^"); append_char("^");
    if k<@'100 then append_char(k+@'100)
    else append_char(k-@'100);
@y
@ @d app_lc_hex(#)==l:=#;
  if l<10 then append_char(l+"0)@+else append_char(l-10+"a")

@<Make the first 256...@>=
for k:=0 to 255 do
  begin if (@<Character |k| cannot be printed@>) then
    begin append_char("^"); append_char("^");
    if k<@'100 then append_char(k+@'100)
    else if k<@'200 then append_char(k-@'100)
    else begin app_lc_hex(k div 16); app_lc_hex(k mod 16);
      end;
@z
@x module 59
  begin print_char(str_pool[j]); incr(j);
@y
  begin print_char(so(str_pool[j])); incr(j);
@z
@x module 60
  begin print(str_pool[j]); incr(j);
@y
  begin print(so(str_pool[j])); incr(j);
@z
@x module 85
  begin if str_pool[j]<>"%" then print(str_pool[j])
  else if j+1=str_start[err_help+1] then print_ln
  else if str_pool[j+1]<>"%" then print_ln
@y
  begin if str_pool[j]<>si("%") then print(so(str_pool[j]))
  else if j+1=str_start[err_help+1] then print_ln
  else if str_pool[j+1]<>si("%") then print_ln
@z
@x module 199
char_class[127]:=invalid_class;
@y
for k:=127 to 255 do char_class[k]:=invalid_class;
@z
@x module 200
@d hash_is_full == (hash_used=1) {test if all positions are occupied}
@d eq_type(#) == eqtb[#].lh {the current ``meaning'' of a symbolic token}
@d equiv(#) == eqtb[#].rh {parametric part of a token's meaning}
@d hash_base=129 {hashing actually starts here}
@y [incidentally I fixed a bug re hash overflow here]
@d eq_type(#) == eqtb[#].lh {the current ``meaning'' of a symbolic token}
@d equiv(#) == eqtb[#].rh {parametric part of a token's meaning}
@d hash_base=257 {hashing actually starts here}
@d hash_is_full == (hash_used=hash_base) {are all positions occupied?}
@z
@x module 210
for j:=0 to l-1 do buffer[j]:=str_pool[k+j];
cur_sym:=id_lookup(0,l);@/
if s>=128 then {we don't want to have the string twice}
@y
for j:=0 to l-1 do buffer[j]:=so(str_pool[k+j]);
cur_sym:=id_lookup(0,l);@/
if s>=256 then {we don't want to have the string twice}
@z
@x module 223
begin c:=char_class[str_pool[str_start[r]]];
@y
begin c:=char_class[so(str_pool[str_start[r]])];
@z
@x module 717
  begin buffer[first]:=str_pool[j]; incr(j); incr(first);
@y
  begin buffer[first]:=so(str_pool[j]); incr(j); incr(first);
@z
@x module 774
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]);
@y
for j:=str_start[a] to str_start[a+1]-1 do append_to_name(so(str_pool[j]));
for j:=str_start[n] to str_start[n+1]-1 do append_to_name(so(str_pool[j]));
for j:=str_start[e] to str_start[e+1]-1 do append_to_name(so(str_pool[j]));
@z
@x module 912
  else  begin cur_exp:=round_unscaled(cur_exp) mod 128; cur_type:=string_type;
    if cur_exp<0 then cur_exp:=cur_exp+128;
@y
  else  begin cur_exp:=round_unscaled(cur_exp) mod 256; cur_type:=string_type;
    if cur_exp<0 then cur_exp:=cur_exp+256;
@z
@x module 913
  else n:=str_pool[str_start[cur_exp]]
@y
  else n:=so(str_pool[str_start[cur_exp]])
@z
@x ibid
    begin m:=str_pool[k];
@y
    begin m:=so(str_pool[k]);
@z
@x module 976
for k:=str_start[a] to str_start[a+1]-1 do append_char(str_pool[k]);
for k:=str_start[b] to str_start[b+1]-1 do append_char(str_pool[k]);
@y
for k:=str_start[a] to str_start[a+1]-1 do append_char(so(str_pool[k]));
for k:=str_start[b] to str_start[b+1]-1 do append_char(so(str_pool[k]));
@z
@x module 977
  for k:=str_start[s]+b-1 downto str_start[s]+a do append_char(str_pool[k])
else for k:=str_start[s]+a to str_start[s]+b-1 do append_char(str_pool[k]);
@y
  for k:=str_start[s]+b-1 downto str_start[s]+a do append_char(so(str_pool[k]))
else for k:=str_start[s]+a to str_start[s]+b-1 do append_char(so(str_pool[k]));
@z
@x module 1103
  begin c:=str_pool[str_start[cur_exp]]; goto found;
@y
  begin c:=so(str_pool[str_start[cur_exp]]); goto found;
@z
@x module 1160
  for k:=str_start[s] to str_start[s+1]-1 do gf_out(str_pool[k]);
  end;
if t<>0 then for k:=str_start[t] to str_start[t+1]-1 do gf_out(str_pool[k]);
@y
  for k:=str_start[s] to str_start[s+1]-1 do gf_out(so(str_pool[k]));
  end;
if t<>0 then for k:=str_start[t] to str_start[t+1]-1 do gf_out(so(str_pool[k]));
@z
@x module 1192
  w.b0:=str_pool[k]; w.b1:=str_pool[k+1];
  w.b2:=str_pool[k+2]; w.b3:=str_pool[k+3];
@y [often qi(so(x))=x, but not e.g. when "quarterwords" are two bytes]
  w.b0:=qi(so(str_pool[k])); w.b1:=qi(so(str_pool[k+1]));
  w.b2:=qi(so(str_pool[k+2])); w.b3:=qi(so(str_pool[k+3]));
@z
@x module 1193
  str_pool[k]:=w.b0; str_pool[k+1]:=w.b1;
  str_pool[k+2]:=w.b2; str_pool[k+3]:=w.b3
@y
  str_pool[k]:=si(qo(w.b0)); str_pool[k+1]:=si(qo(w.b1));
  str_pool[k+2]:=si(qo(w.b2)); str_pool[k+3]:=si(qo(w.b3))
@z

549. Make ".base" more easily switchable (see TeX82 log #369).
@x module 775 gets a new definition
@y
@d base_extension=".base" {the extension, as a \.{WEB} constant}
@z now replace ".base" by base_extension in modules 784 and 1200.

550. "This can't happen" happened because of nonmonotonic rounding
 (bug found by Mark Eklof, fixed 7 Oct 89)
@x module 411
left_x(r):=x_coord(r);
@y
left_x(r):=x_coord(r);
if right_x(p)>x_coord(r) then right_x(p):=x_coord(r);
 {we always have |x_coord(p)<=right_x(p)|}
@z
@x ibid
else if x_coord(r)>dest_x then x_coord(r):=dest_x;
@y
else begin if x_coord(r)>dest_x then
    begin x_coord(r):=dest_x; left_x(r):=-x_coord(r); right_x(r):=x_coord(r);
    end;
  if left_x(q)>dest_x then left_x(q):=dest_x
  else if left_x(q)<x_coord(r) then left_x(q):=x_coord(r);
  end;
@z
@x module 412
left_x(s):=x_coord(s);
negate(x_coord(s)); right_x(s):=x_coord(s);
negate(left_x(q));
@y
left_x(s):=x_coord(s); {now |x_coord(r)=right_x(r)<=left_x(s)|}
if left_x(q)<dest_x then left_x(q):=-dest_x
else if left_x(q)>x_coord(s) then left_x(q):=-x_coord(s)
else negate(left_x(q));
negate(x_coord(s)); right_x(s):=x_coord(s);
@z
@x module 415
if x_coord(r)>dest_x then x_coord(r):=dest_x
else if x_coord(r)<x_coord(pp) then x_coord(r):=x_coord(pp);
if y_coord(r)<y_coord(pp) then y_coord(r):=y_coord(pp);
left_y(r):=y_coord(r);
@y
if y_coord(r)<y_coord(pp) then y_coord(r):=y_coord(pp);
left_y(r):=y_coord(r);
if right_y(pp)>y_coord(r) then right_y(pp):=y_coord(r);
 {we always have |y_coord(pp)<=right_y(pp)|}
@z
@x ibid
else if y_coord(r)>dest_y then y_coord(r):=dest_y;
@y
else begin if y_coord(r)>dest_y then
    begin y_coord(r):=dest_y; left_y(r):=-y_coord(r); right_y(r):=y_coord(r);
    end;
  if left_y(qq)>dest_y then left_y(qq):=dest_y
  else if left_y(qq)<y_coord(r) then left_y(qq):=y_coord(r);
  end;
@z
@x module 416
if x_coord(s)>dest_x then x_coord(s):=dest_x
else if x_coord(s)<x_coord(r) then x_coord(s):=x_coord(r);
if y_coord(s)<dest_y then y_coord(s):=dest_y;
if y_coord(s)<y_coord(r) then y_coord(s):=y_coord(r);
right_type(s):=right_type(pp);
left_y(s):=y_coord(s);
negate(y_coord(s)); right_y(s):=y_coord(s);
negate(left_y(qq));
@y
if y_coord(s)<dest_y then y_coord(s):=dest_y;
if y_coord(s)<y_coord(r) then y_coord(s):=y_coord(r);
right_type(s):=right_type(pp);
left_y(s):=y_coord(s); {now |y_coord(r)=right_y(r)<=left_y(s)|}
if left_y(qq)<dest_y then left_y(qq):=-dest_y
else if left_y(qq)>y_coord(s) then left_y(qq):=-y_coord(s)
else negate(left_y(qq));
negate(y_coord(s)); right_y(s):=y_coord(s);
@z
@x module 424
if y_coord(r)>dest_y then y_coord(r):=dest_y
else if y_coord(r)<y_coord(p) then y_coord(r):=y_coord(p);
if x_coord(r)<x_coord(p) then x_coord(r):=x_coord(p);
left_x(r):=x_coord(r);@/
y_coord(r):=y_coord(r)+x_coord(r); negate(x_coord(r));@/
right_x(r):=x_coord(r); right_y(r):=right_y(r)-right_x(r);@/
left_y(q):=left_y(q)+left_x(q); negate(left_x(q));@/
dest_y:=dest_y+dest_x; negate(dest_x);
@y
if x_coord(p)+y_coord(r)>dest_x+dest_y then
  begin y_coord(r):=dest_x+dest_y-x_coord(p);
  if left_y(r)>y_coord(r) then
    begin left_y(r):=y_coord(r);
    if right_y(p)>y_coord(r) then right_y(p):=y_coord(r);
    end;
  end;
if x_coord(r)<x_coord(p) then x_coord(r):=x_coord(p)
else if x_coord(r)+y_coord(r)>dest_x+dest_y then
  x_coord(r):=dest_x+dest_y-y_coord(r);
left_x(r):=x_coord(r);
if right_x(p)>x_coord(r) then right_x(p):=x_coord(r);
 {we always have |x_coord(p)<=right_x(p)|}
y_coord(r):=y_coord(r)+x_coord(r); right_y(r):=right_y(r)+x_coord(r);@/
negate(x_coord(r)); right_x(r):=x_coord(r);@/
left_y(q):=left_y(q)+left_x(q); negate(left_x(q));@/
dest_y:=dest_y+dest_x; negate(dest_x);
if right_y(r)>dest_y then right_y(r):=dest_y;
if left_y(q)>dest_y then left_y(q):=dest_y
else if left_y(q)<y_coord(r) then left_y(q):=y_coord(r);
if right_y(r)>left_y(q) then right_y(r):=left_y(q);
@z
@x ibid
else if x_coord(r)>dest_x then x_coord(r):=dest_x
@y
else begin if x_coord(r)>dest_x then
    begin x_coord(r):=dest_x; left_x(r):=-x_coord(r); right_x(r):=x_coord(r);
    end;
  if left_x(q)>dest_x then left_x(q):=dest_x
  else if left_x(q)<x_coord(r) then left_x(q):=x_coord(r);
  end;
@z
@x module 425 is entirely replaced
@y by the following code:
@ @<Subdivide the cubic a second time with respect to $x'-y'$@>=
begin split_cubic(r,t,dest_x,dest_y); s:=link(r);@/
if x_coord(r)+y_coord(s)>dest_x+dest_y then
  begin y_coord(s):=dest_x+dest_y-x_coord(r);
  if left_y(s)>y_coord(s) then
    begin left_y(s):=y_coord(s);
    if right_y(r)>y_coord(s) then right_y(r):=y_coord(s);
    end;
  end;
if x_coord(s)+y_coord(s)>dest_x+dest_y then x_coord(s):=dest_x+dest_y-y_coord(s)
else begin if x_coord(s)<dest_x then x_coord(s):=dest_x;
  if x_coord(s)<x_coord(r) then x_coord(s):=x_coord(r);
  end;
right_type(s):=right_type(p);
left_x(s):=x_coord(s); {now |x_coord(r)=right_x(r)<=left_x(s)|}
if left_x(q)<dest_x then
  begin left_y(q):=left_y(q)+dest_x; left_x(q):=-dest_x;@+end
else if left_x(q)>x_coord(s) then
  begin left_y(q):=left_y(q)+x_coord(s); left_x(q):=-x_coord(s);@+end
else begin left_y(q):=left_y(q)+left_x(q); negate(left_x(q));@+end;
y_coord(s):=y_coord(s)+x_coord(s); right_y(s):=right_y(s)+x_coord(s);@/
negate(x_coord(s)); right_x(s):=x_coord(s);@/
dest_y:=dest_y+dest_x;
if right_y(s)>dest_y then right_y(s):=dest_y;
if left_y(q)>dest_y then left_y(q):=dest_y
else if left_y(q)<y_coord(s) then left_y(q):=y_coord(s);
if right_y(s)>left_y(q) then right_y(s):=left_y(q);
end
@z

551. Major change for extended ligatures.
@x module 11 (this may affect change files)
@!lig_table_size=300; {maximum number of ligature/kern steps}
@y
@!lig_table_size=5000; {maximum number of ligature/kern steps, must be
  at least 255 and at most 32510}
@!max_kerns=500; {maximum number of distinct kern amounts}
@z
@x module 14 gets a new line of code
@y
if(lig_table_size<255)or(lig_table_size>32510)then bad:=7;
@z
@x module 186
@d lig_kern_token=76 {the operators `\&{kern}' and `\.{=:}'}
@d assignment=77 {the operator `\.{:=}'}
@d colon=78 {the operator `\.:'}
@#
@d comma=79 {the operator `\.,'}
@d end_of_statement==cur_cmd>comma
@d semicolon=80 {the operator `\.;', must be |comma+1|}
@d end_group=81 {end a group (\&{endgroup}), must be |semicolon+1|}
@d stop=82 {end a job (\&{end}, \&{dump}), must be |end_group+1|}
@y
@d lig_kern_token=76
  {the operators `\&{kern}' and `\.{=:}' and `\.{=:\char'174}, etc.}
@d assignment=77 {the operator `\.{:=}'}
@d skip_to=78 {the operation `\&{skipto}'}
@d bchar_label=79 {the operator `\.{\char'174\char'174:}'}
@d double_colon=80 {the operator `\.{::}'}
@d colon=81 {the operator `\.:'}
@#
@d comma=82 {the operator `\.,', must be |colon+1|}
@d end_of_statement==cur_cmd>comma
@d semicolon=83 {the operator `\.;', must be |comma+1|}
@d end_group=84 {end a group (\&{endgroup}), must be |semicolon+1|}
@d stop=85 {end a job (\&{end}, \&{dump}), must be |end_group+1|}
@z
@x module 190
@d max_given_internal=warning_check
@y
@d boundary_char=41 {the right boundary character for ligatures}
@d max_given_internal=41
@z
@x module 192 gets two new lines of code
@y
primitive("boundarychar",internal_quantity,boundary_char);@/
@!@:boundary_char_}{\&{boundarychar} primitive@>
@z
@x and module 193 gets one too
@y
int_name[boundary_char]:="boundarychar";
@z
@x and module 211 gets several
@y (to be inserted in appropriate places)
primitive("::",double_colon,0);
@!@::: }{\.{::} primitive@>
primitive("||:",bchar_label,0);
@!@:::: }{\.{\char'174\char'174:} primitive@>
primitive("skipto",skip_to,0);@/
@!@:skip_to_}{\&{skipto} primitive@>
@z
@x as does module 212
@y
bchar_label:print("||:");
double_colon:print("::");
skip_to:print("skipto");
@z
@x module 1093 has new text (see TeX change 362 for module 545) and also this:
@d stop_bit(#)==lig_kern[#].b0
@d next_char(#)==lig_kern[#].b1
@d op_bit(#)==lig_kern[#].b2
@y
@d skip_byte(#)==lig_kern[#].b0
@d next_char(#)==lig_kern[#].b1
@d op_byte(#)==lig_kern[#].b2
@z
@x module 1096 gets a new definition
@y
@d undefined_label==lig_table_size {an undefined local label}
@z
@x ...and some changed declarations
@!char_remainder:array[eight_bits] of eight_bits; {the |remainder| byte}
@!header_byte:array[1..header_size] of -1..255;
  {bytes of the \.{TFM} header, or $-1$ if unset}
@!lig_kern:array[0..lig_table_size] of four_quarters; {the ligature/kern table}
@!nl:0..lig_table_size; {the number of ligature/kern steps so far}
@!kern:array[eight_bits] of scaled; {distinct kerning amounts}
@!nk:0..256; {the number of distinct kerns so far}
@y
@!char_remainder:array[eight_bits] of 0..lig_table_size; {the |remainder| byte}
@!header_byte:array[1..header_size] of -1..255;
  {bytes of the \.{TFM} header, or $-1$ if unset}
@!lig_kern:array[0..lig_table_size] of four_quarters; {the ligature/kern table}
@!nl:0..32767-256; {the number of ligature/kern steps so far}
@!kern:array[0..max_kerns] of scaled; {distinct kerning amounts}
@!nk:0..max_kerns; {the number of distinct kerns so far}
@z
@x ...and some new declarations
@y
@!skip_table:array[eight_bits] of 0..lig_table_size; {local label status}
@!lk_started:boolean; {has there been a lig/kern step in this command yet?}
@!bchar:integer; {right boundary character}
@!bch_label:0..lig_table_size; {left boundary starting location}
@!ll,@!lll:0..lig_table_size; {registers used for lig/kern processing}
@!label_loc:array[0..256] of -1..lig_table_size; {lig/kern starting addresses}
@!label_char:array[1..256] of eight_bits; {characters for |label_loc|}
@!label_ptr:0..256; {highest position occupied in |label_loc|}
@z
@x module 1097
  end;
for k:=1 to header_size do header_byte[k]:=-1;
bc:=255; ec:=0; nl:=0; nk:=0; ne:=0; np:=0;
@y
  skip_table[k]:=undefined_label;
  end;
for k:=1 to header_size do header_byte[k]:=-1;
bc:=255; ec:=0; nl:=0; nk:=0; ne:=0; np:=0;@/
internal[boundary_char]:=-unity;
bch_label:=undefined_label;@/
label_loc[0]:=-1; label_ptr:=0;
@z
@x module 1104
procedure set_tag(@!c:eight_bits;@!t:small_number;@!r:eight_bits);
begin if char_tag[c]=no_tag then
  begin char_tag[c]:=t; char_remainder[c]:=r;
@y
procedure set_tag(@!c:halfword;@!t:small_number;@!r:halfword);
begin if char_tag[c]=no_tag then
  begin char_tag[c]:=t; char_remainder[c]:=r;
  if t=lig_tag then
    begin incr(label_ptr); label_loc[label_ptr]:=r; label_char[label_ptr]:=c;
    end;
@z
@x module  1105
if (c>" ")and(c<128) then print(c)
@y
if (c>" ")and(c<127) then print(c)
else if c=256 then print("||")
@z
@x module 1106
label continue;
var @!c,@!cc:eight_bits; {character codes}
@!k:0..256; {index into the |kern| array}
@y
label continue,done;
var @!c,@!cc:0..256; {character codes}
@!k:0..max_kerns; {index into the |kern| array}
@z
% also the previous code of module 1107 is inserted into 1106
@x modules 1107--1111 are completely replaced
@y by the following new code:
@ @<Store a list of ligature/kern steps@>=
begin lk_started:=false;
continue: get_x_next;
if(cur_cmd=skip_to)and lk_started then
 @<Process a |skip_to| command and |goto done|@>;
if cur_cmd=bchar_label then
  begin c:=256; cur_cmd:=colon;@+end
else begin back_input; c:=get_code;@+end;
if(cur_cmd=colon)or(cur_cmd=double_colon)then
  @<Record a label in a lig/kern subprogram and |goto continue|@>;
if cur_cmd=lig_kern_token then @<Compile a ligature/kern command@>
else  begin print_err("Illegal ligtable step");
@.Illegal ligtable step@>
  help1("I was looking for `=:' or `kern' here.");
  back_error; next_char(nl):=qi(0); op_byte(nl):=qi(0); rem_byte(nl):=qi(0);@/
  skip_byte(nl):=stop_flag+1; {this specifies an unconditional stop}
  end;
if nl=lig_table_size then overflow("ligtable size",lig_table_size);
@:METAFONT capacity exceeded ligtable size}{\quad ligtable size@>
incr(nl);
if cur_cmd=comma then goto continue;
if skip_byte(nl-1)<stop_flag then skip_byte(nl-1):=stop_flag;
done:end

@ @<Put each...@>=
primitive("=:",lig_kern_token,0);
@!@:=:_}{\.{=:} primitive@>
primitive("=:|",lig_kern_token,1);
@!@:=:/_}{\.{=:\char'174} primitive@>
primitive("=:|>",lig_kern_token,5);
@!@:=:/>_}{\.{=:\char'174>} primitive@>
primitive("|=:",lig_kern_token,2);
@!@:=:/_}{\.{\char'174=:} primitive@>
primitive("|=:>",lig_kern_token,6);
@!@:=:/>_}{\.{\char'174=:>} primitive@>
primitive("|=:|",lig_kern_token,3);
@!@:=:/_}{\.{\char'174=:\char'174} primitive@>
primitive("|=:|>",lig_kern_token,7);
@!@:=:/>_}{\.{\char'174=:\char'174>} primitive@>
primitive("|=:|>>",lig_kern_token,11);
@!@:=:/>_}{\.{\char'174=:\char'174>>} primitive@>
primitive("kern",lig_kern_token,128);
@!@:kern_}{\&{kern} primitive@>
  
@ @<Cases of |print_cmd...@>=
lig_kern_token: case m of
0:print("=:");
1:print("=:|");
2:print("|=:");
3:print("|=:|");
5:print("=:|>");
6:print("|=:>");
7:print("|=:|>");
11:print("|=:|>>");
othercases print("kern")
endcases;
  
@ Local labels are implemented by maintaining the |skip_table| array,
where |skip_table[c]| is either |undefined_label| or the address of the
most recent lig/kern instruction that skips to local label~|c|. In the
latter case, the |skip_byte| in that instruction will (temporarily)
be zero if there were no prior skips to this label, or it will be the
distance to the prior skip.

We may need to cancel skips that span more than 127 lig/kern steps.

@d cancel_skips(#)==ll:=#;
  repeat lll:=qo(skip_byte(ll)); skip_byte(ll):=stop_flag; ll:=ll-lll;
  until lll=0
@d skip_error(#)==begin print_err("Too far to skip");
@.Too far to skip@>
  help1("At most 127 lig/kern steps can separate skipto1 from 1::.");
  error; cancel_skips(#);
  end

@<Process a |skip_to| command and |goto done|@>=
begin c:=get_code;
if nl-skip_table[c]>128 then {|skip_table[c]<<nl<=undefined_label|}
  begin skip_error(skip_table[c]); skip_table[c]:=undefined_label;
  end;
if skip_table[c]=undefined_label then skip_byte(nl-1):=qi(0)
else skip_byte(nl-1):=qi(nl-skip_table[c]-1);
skip_table[c]:=nl-1; goto done;
end

@ @<Record a label in a lig/kern subprogram and |goto continue|@>=
begin if cur_cmd=colon then
  if c=256 then bch_label:=nl
  else set_tag(c,lig_tag,nl)
else if skip_table[c]<undefined_label then
  begin ll:=skip_table[c]; skip_table[c]:=undefined_label;
  repeat lll:=qo(skip_byte(ll));
  if nl-ll>128 then
    begin skip_error(ll); goto continue;
    end;
  skip_byte(ll):=qi(nl-ll-1); ll:=ll-lll;
  until lll=0;
  end;
goto continue;
end
@x module 1112
next_char(nl):=qi(c); op_bit(nl):=qi(cur_mod); stop_bit(nl):=qi(0);
if cur_mod=0 then rem_byte(nl):=qi(get_code)
@y
begin next_char(nl):=qi(c); skip_byte(nl):=qi(0);
if cur_mod<128 then {ligature op}
  begin op_byte(nl):=qi(cur_mod); rem_byte(nl):=qi(get_code);
  end
@z
@x ibid
    begin if nk=256 then overflow("kern",256);
@:METAFONT capacity exceeded kern}{\quad kern@>
    incr(nk);
    end;
  rem_byte(nl):=qi(k);
  end
@y
    begin if nk=max_kerns then overflow("kern",max_kerns);
@:METAFONT capacity exceeded kern}{\quad kern@>
    incr(nk);
    end;
  op_byte(nl):=kern_flag+(k div 256);
  rem_byte(nl):=qi((k mod 256));
  end;
lk_started:=true;
end
@z
@x module 1135
tfm_two(6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np);
  {this is the total number of file words that will be output}
tfm_two(lh); tfm_two(bc); tfm_two(ec); tfm_two(nw); tfm_two(nh);
tfm_two(nd); tfm_two(ni); tfm_two(nl); tfm_two(nk); tfm_two(ne); tfm_two(np);
@y
@<Compute the ligature/kern program offset and implant the
  left boundary label@>;
tfm_two(6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+lk_offset+nk+ne+np);
  {this is the total number of file words that will be output}
tfm_two(lh); tfm_two(bc); tfm_two(ec); tfm_two(nw); tfm_two(nh);
tfm_two(nd); tfm_two(ni); tfm_two(nl+lk_offset); tfm_two(nk); tfm_two(ne);
tfm_two(np);
@z
% modules 1137&1138 are combined into a single module
% and so are modules 1140--1141, to make room for two new modules.
@x module 1136 is moved to after old module 1141
@y and changed to the following code:
@ @<Log the subfile sizes of the \.{TFM} file@>=
if bch_label<undefined_label then decr(nl);
wlog_ln('(You used ',nw:1,'w,',@| nh:1,'h,',@| nd:1,'d,',@| ni:1,'i,',@|
 nl:1,'l,',@| nk:1,'k,',@| ne:1,'e,',@|
 np:1,'p metric file positions');
wlog_ln('  out of ',@| '256w,16h,16d,64i,',@|
 lig_table_size:1,'l,',max_kerns:1,'k,256e,',@|
 max_font_dimen:1,'p)');
end
@z
@x module 1139 is completely replaced
@y by the following three modules:
@ We need to output special instructions at the beginning of the
|lig_kern| array in order to specify the right boundary character
and/or to handle starting addresses that exceed 255. The |label_loc|
and |label_char| arrays have been set up to record all the
starting addesses; we have $-1=|label_loc|[0]<|label_loc|[1]\le\cdots
\le|label_loc|[|label_ptr]|$.

@<Compute the ligature/kern program offset...@>=
bchar:=round_unscaled(internal[boundary_char]);
if(bchar<0)or(bchar>255)then
  begin bchar:=-1; lk_started:=false; lk_offset:=0;@+end
else begin lk_started:=true; lk_offset:=1;@+end;
@<Find the minimum |lk_offset| and adjust all remainders@>;
if bch_label<undefined_label then
  begin skip_byte(nl):=qi(255); next_char(nl):=qi(0);
  op_byte(nl):=qi(((bch_label+lk_offset)div 256));
  rem_byte(nl):=qi(((bch_label+lk_offset)mod 256));
  incr(nl); {possibly |nl=lig_table_size+1|}
  end

@ @<Find the minimum |lk_offset|...@>=
k:=label_ptr; {pointer to the largest unallocated label}
if label_loc[k]+lk_offset>255 then
  begin lk_offset:=0; lk_started:=false; {location 0 can do double duty}
  repeat char_remainder[label_char[k]]:=lk_offset;
  while label_loc[k-1]=label_loc[k] do
    begin decr(k); char_remainder[label_char[k]]:=lk_offset;
    end;
  incr(lk_offset); decr(k);
  until lk_offset+label_loc[k]<256;
    {N.B.: |lk_offset=256| satisfies this when |k=0|}
  end;
if lk_offset>0 then
  while k>0 do
    begin char_remainder[label_char[k]]
     :=char_remainder[label_char[k]]+lk_offset;
    decr(k);
    end

@ @<Output the ligature/kern program@>=
for k:=0 to 255 do if skip_table[k]<undefined_label then
  begin print_nl("(local label "); print_int(k); print(":: was missing)");
@.local label l:: was missing@>
  cancel_skips(skip_table[k]);
  end;
if lk_started then {|lk_offset=1| for the special |bchar|}
  begin tfm_out(255); tfm_out(bchar); tfm_two(0);
  end
else for k:=1 to lk_offset do {output the redirection specs}
  begin ll:=label_loc[label_ptr];
  if bchar<0 then
    begin tfm_out(254); tfm_out(0);
    end
  else begin tfm_out(255); tfm_out(bchar);
    end;
  tfm_two(ll+lk_offset);
  repeat decr(label_ptr);
  until label_loc[label_ptr]<ll;
  end;
for k:=0 to nl-1 do tfm_qqqq(lig_kern[k]);
for k:=0 to nk-1 do tfm_four(dimen_out(kern[k]))
@z
@x module 1205 gets a new declaration
@y
@!lk_offset:0..256; {extra words inserted at beginning of |lig_kern| array}
@z

552. Improved the covering/shortening routines. (18 Dec 89)
@x module 1119 gets a new global variable
@y
@!excess:integer; {the list is this much too long}
@z
@x module 1120 gives it a value
begin if min_cover(0)<=m then threshold:=0
@y
begin excess:=min_cover(0)-m;
if excess<=0 then threshold:=0
@z
@x and module 1122 uses it
begin repeat p:=link(p); info(p):=m;
@y
begin repeat p:=link(p); info(p):=m;
decr(excess);@+if excess=0 then d:=0;
@z
@x and module 1122 also avoids overflow/ambiguous halving
v:=half(l+value(p));
@y
v:=l+half(value(p)-l);
@z

553. Global variable used prematurely in do_add_to (Alan Jeffrey, 9 Feb 90)
@x module 403
@!cur_path_type:double_path_code..also_code; {likewise}
@y
@!cur_path_type:double_path_code..contour_code; {likewise}
@z
@x module 1059
begin get_x_next; var_flag:=thing_to_add; scan_primary;
if cur_type<>token_list then
  @<Abandon edges command because there's no variable@>
else  begin lhs:=cur_exp; cur_path_type:=cur_mod;@/
  cur_type:=vacuous; get_x_next; scan_expression;
  if cur_path_type=also_code then @<Augment some edges by others@>
@y
@!add_to_type:double_path_code..also_code; {modifier of \&{addto}}
begin get_x_next; var_flag:=thing_to_add; scan_primary;
if cur_type<>token_list then
  @<Abandon edges command because there's no variable@>
else  begin lhs:=cur_exp; add_to_type:=cur_mod;@/
  cur_type:=vacuous; get_x_next; scan_expression;
  if add_to_type=also_code then @<Augment some edges by others@>
@z
@x module 1064
else  begin lhs:=null;
@y
else  begin lhs:=null; cur_path_type:=add_to_type;
@z

554. Balance the parens showing on the terminal (for Lispers).
@x module 631
@!in_open : 0..max_in_open; {the number of lines in the buffer, less one}
@y
@!in_open : 0..max_in_open; {the number of lines in the buffer, less one}
@!open_parens : 0..max_in_open; {the number of open text files}
@z
@x module 657
in_open:=0; max_buf_stack:=0;
@y
in_open:=0; open_parens:=0; max_buf_stack:=0;
@z
@x module 681
  begin print_char(")"); force_eof:=false;
  update_terminal; {show user that file has been read}
@y
  begin print_char(")"); decr(open_parens);
  update_terminal; {show user that file has been read}
  force_eof:=false;
@z
@x module 793
print_char("("); print(name); update_terminal;
@y
print_char("("); incr(open_parens); print(name); update_terminal;
@z
@x module 1209
if job_name=0 then open_log_file;
@y
if job_name=0 then open_log_file;
while open_parens>0 do
  begin print(" )"); decr(open_parens);
  end;
@z

-----------Here I draw the line with respect to further changes

555. Don't try system area if an area was given (see tex82.bug number 312;
found by Jonathan Kew, May 1990)
@x module 793
  pack_file_name(cur_name,MF_area,cur_ext);
  if a_open_in(cur_file) then goto done;
@y
  if cur_area="" then
    begin pack_file_name(cur_name,MF_area,cur_ext);
    if a_open_in(cur_file) then goto done;
    end;
@z

556. Report correct line number when buffer overflows (CET, Jul 90).
@x module 794
begin if not input_ln(cur_file,false) then do_nothing;
firm_up_the_line;
buffer[limit]:="%"; first:=limit+1; loc:=start; line:=1;
@y
begin line:=1;
if input_ln(cur_file,false) then do_nothing;
firm_up_the_line;
buffer[limit]:="%"; first:=limit+1; loc:=start;
@z

557. TeX82 bug 308, corrected in 1985, is also in MF! (Lutz Birkhahn, May91)
@x module 176
var_used:=lo_mem_stat_max+1-mem_min; dyn_used:=mem_top+1-hi_mem_stat_min;
@y
var_used:=lo_mem_stat_max+1-mem_min; dyn_used:=mem_top+1-hi_mem_min;
@z

558. Allow unprintable file names, as in TeX change 396 (19 Sep 91)
(Much of this is redundant except for people who make nonportable
versions that allow other 8-bit codes to be in variable names---and for
those people only if they allow input of more codes than they can print!
Still, it seems best to make the programs for TeX and MF as alike as possible.)
@x module 59
j:=str_start[s];
while j<str_start[s+1] do
  begin print_char(so(str_pool[j])); incr(j);
  end;
@y
if (s<256)and(selector>pseudo) then print_char(s)
else begin j:=str_start[s];
  while j<str_start[s+1] do
    begin print_char(so(str_pool[j])); incr(j);
    end;
  end;
@z
@x module 60
j:=str_start[s];
while j<str_start[s+1] do
  begin print(so(str_pool[j])); incr(j);
  end;
@y
if (s<256)and(selector>pseudo) then print_char(s)
else begin j:=str_start[s];
  while j<str_start[s+1] do
    begin print(so(str_pool[j])); incr(j);
    end;
  end;
@z
@x module 61
else  begin print(base_ident); print_ln;
@y
else  begin slow_print(base_ident); print_ln;
@z
@x module 79
  print(input_stack[file_ptr].name_field);
@y
  slow_print(input_stack[file_ptr].name_field);
@z
@x module 223
print(r);
@y
slow_print(r);
@z
@x module 254
      print(int_name[q-(hash_end)]); print_char("=");
@y
      slow_print(int_name[q-(hash_end)]); print_char("=");
@z
@x module 254 again
      print(text(q)); print_char("}");
@y
      slow_print(text(q)); print_char("}");
@z
@x module 638
  if name<>null then print(text(name))
@y
  if name<>null then slow_print(text(name))
@z
@x module 664
  if scanner_status=op_defining then print(text(warning_info))
@y
  if scanner_status=op_defining then slow_print(text(warning_info))
@z
@x module 664 again
loop_defining: begin print("the text of a "); print(text(warning_info));
@y
loop_defining: begin print("the text of a "); slow_print(text(warning_info));
@z
@x module 722
begin if n<>null then print(text(n))
@y
begin if n<>null then slow_print(text(n))
@z
@x module 722 again
  if p=null then print(text(info(info(link(a)))))
@y
  if p=null then slow_print(text(info(info(link(a)))))
@z
@x module 725
  print_nl("  Missing `"); print(text(r_delim));
@y
  print_nl("  Missing `"); slow_print(text(r_delim));
@z
@x module 773
begin print(a); print(n); print(e);
@y
begin slow_print(a); slow_print(n); slow_print(e);
@z
@x module 790
print(base_ident); print("  ");
@y
slow_print(base_ident); print("  ");
@z
@x module 793
print_char("("); incr(open_parens); print(name); update_terminal;
@y
print_char("("); incr(open_parens); slow_print(name); update_terminal;
@z
@x module 998
if info(lhs)>hash_end then print(int_name[info(lhs)-(hash_end)])
@y
if info(lhs)>hash_end then slow_print(int_name[info(lhs)-(hash_end)])
@z
@x module 999
  print(int_name[info(lhs)-(hash_end)]);
@y
  slow_print(int_name[info(lhs)-(hash_end)]);
@z
@x module 1032
else  begin print_err("The token `"); print(text(r_delim));
@y
else  begin print_err("The token `"); slow_print(text(r_delim));
@z
@x module 1034
  else print(text(cur_sym));
@y
  else slow_print(text(cur_sym));
@z
@x module 1041
else  begin print(text(cur_sym)); print_char("=");
@y
else  begin slow_print(text(cur_sym)); print_char("=");
@z
@x module 1042
else  begin print_char(""""); print(cur_mod); print_char("""");
@y
else  begin print_char(""""); slow_print(cur_mod); print_char("""");
@z
@x module 1043
  print("t delimiter that matches "); print(text(m));
@y
  print("t delimiter that matches "); slow_print(text(m));
@z
@x module 1043 again
internal_quantity:print(int_name[m]);
@y
internal_quantity:slow_print(int_name[m]);
@z
@x module 1134
print_nl("Font metrics written on "); print(metric_file_name); print_char(".");
@y
print_nl("Font metrics written on "); slow_print(metric_file_name);
print_char(".");
@z
@x module 1182
print_nl("Output written on "); print(output_file_name);
@y
print_nl("Output written on "); slow_print(output_file_name);
@z
@x module 1200
print(w_make_name_string(base_file)); flush_string(str_ptr-1);
print_nl(base_ident)
@y
slow_print(w_make_name_string(base_file)); flush_string(str_ptr-1);
print_nl(""); slow_print(base_ident)
@z
@x module 1205
    print(log_name); print_char(".");
@y
    slow_print(log_name); print_char(".");
@z
@x module 1213
10: print(n);
@y
10: slow_print(n);
@z

------ The third printing of Volume D (October 1991) incorporated the above.

559. Debugging routine never used since change 528; needed update then (JDH).
@x module 617
  p:=dep_list(p); r:=hi_mem_min;
  repeat if info(p)>=r then
@y
  p:=dep_list(p); r:=inf_val;
  repeat if value(info(p))>=value(r) then
@z

560. Corrections to blunders in change 550 (noted by B Jackowski, Jul 91).
@x module 415 can use more paranoia even though no problems have occurred yet
negate(left_y(qq)); negate(dest_y);@/
@y
negate(left_y(qq)); negate(dest_y);@/
if x_coord(r)<x_coord(pp) then x_coord(r):=x_coord(pp)
else if x_coord(r)>dest_x then x_coord(r):=dest_x;
if left_x(r)>x_coord(r) then
  begin left_x(r):=x_coord(r);
  if right_x(pp)>x_coord(r) then right_x(pp):=x_coord(r);
  end;
if right_x(r)<x_coord(r) then
  begin right_x(r):=x_coord(r);
  if left_x(qq)<x_coord(r) then left_x(qq):=x_coord(r);
  end;
@z
@x module 416 similarly
negate(y_coord(s)); right_y(s):=y_coord(s);
@y
negate(y_coord(s)); right_y(s):=y_coord(s);
if x_coord(s)<x_coord(r) then x_coord(s):=x_coord(r)
else if x_coord(s)>dest_x then x_coord(s):=dest_x;
if left_x(s)>x_coord(s) then
  begin left_x(s):=x_coord(s);
  if right_x(r)>x_coord(s) then right_x(r):=x_coord(s);
  end;
if right_x(s)<x_coord(s) then
  begin right_x(s):=x_coord(s);
  if left_x(qq)<x_coord(s) then left_x(qq):=x_coord(s);
  end;
@z
@x module 424 similarly
if x_coord(p)+y_coord(r)>dest_x+dest_y then
  begin y_coord(r):=dest_x+dest_y-x_coord(p);
  if left_y(r)>y_coord(r) then
    begin left_y(r):=y_coord(r);
    if right_y(p)>y_coord(r) then right_y(p):=y_coord(r);
    end;
  end;
@y
if y_coord(r)<y_coord(p) then y_coord(r):=y_coord(p)
else if y_coord(r)>dest_y then y_coord(r):=dest_y;
if x_coord(p)+y_coord(r)>dest_x+dest_y then
  y_coord(r):=dest_x+dest_y-x_coord(p);
if left_y(r)>y_coord(r) then
  begin left_y(r):=y_coord(r);
  if right_y(p)>y_coord(r) then right_y(p):=y_coord(r);
  end;
if right_y(r)<y_coord(r) then
  begin right_y(r):=y_coord(r);
  if left_y(q)<y_coord(r) then left_y(q):=y_coord(r);
  end;
@z
@x in module 424, here's the serious bug introduced in change #550.
if right_y(r)>dest_y then right_y(r):=dest_y;
if left_y(q)>dest_y then left_y(q):=dest_y
else if left_y(q)<y_coord(r) then left_y(q):=y_coord(r);
if right_y(r)>left_y(q) then right_y(r):=left_y(q);
@y
if right_y(r)<y_coord(r) then
  begin right_y(r):=y_coord(r);
  if left_y(q)<y_coord(r) then left_y(q):=y_coord(r);
  end;
@z
@x module 425 is analogous
if x_coord(r)+y_coord(s)>dest_x+dest_y then
  begin y_coord(s):=dest_x+dest_y-x_coord(r);
  if left_y(s)>y_coord(s) then
    begin left_y(s):=y_coord(s);
    if right_y(r)>y_coord(s) then right_y(r):=y_coord(s);
    end;
  end;
@y
if y_coord(s)<y_coord(r) then y_coord(s):=y_coord(r)
else if y_coord(s)>dest_y then y_coord(s):=dest_y;
if x_coord(r)+y_coord(s)>dest_x+dest_y then
  y_coord(s):=dest_x+dest_y-x_coord(r);
if left_y(s)>y_coord(s) then
  begin left_y(s):=y_coord(s);
  if right_y(r)>y_coord(s) then right_y(r):=y_coord(s);
  end;
if right_y(s)<y_coord(s) then
  begin right_y(s):=y_coord(s);
  if left_y(q)<y_coord(s) then left_y(q):=y_coord(s);
  end;
@z
@x module 425, the analogous bug
dest_y:=dest_y+dest_x;
if right_y(s)>dest_y then right_y(s):=dest_y;
if left_y(q)>dest_y then left_y(q):=dest_y
else if left_y(q)<y_coord(s) then left_y(q):=y_coord(s);
if right_y(s)>left_y(q) then right_y(s):=left_y(q);
@y
if right_y(s)<y_coord(s) then
  begin right_y(s):=y_coord(s);
  if left_y(q)<y_coord(s) then left_y(q):=y_coord(s);
  end;
@z

561. serious longstanding bug caused overflows and bad rounding (1 Mar 95)
@x module 815
begin if (max_c[dependent]>=fraction_one)or@|
 (max_c[dependent] div @'10000 >= max_c[proto_dependent]) then
@y
begin if (max_c[dependent] div @'10000 >=
          max_c[proto_dependent]) then
@z

562. final cleanup should not retain spurious reference counts (20 Mar 95)
@x module 1209
while open_parens>0 do
@y
while input_ptr>0 do
  if token_state then end_token_list@+else end_file_reading;
while loop_ptr<>null do stop_iteration;
while open_parens>0 do
@z
@x module 1209
  cur_if:=name_type(cond_ptr); cond_ptr:=link(cond_ptr);
@y
  cur_if:=name_type(cond_ptr); loop_ptr:=cond_ptr;
  cond_ptr:=link(cond_ptr); free_node(loop_ptr,if_node_size);
@z

563. unprintable strings of length 1 need to be truly length 1 (27 Nov 95,
pointed out by Ulrik Vieth)
@x module 671
  if loc=k+1 then cur_mod:=buffer[k]
@y
  if (loc=k+1) and (length(buffer[k])=1) then cur_mod:=buffer[k]
@z

564. minor improvement to pythagorean addition (22 Jan 97)
@x module 124
if a>0 then
@y
if b>0 then
@z

565. we need not raise hackles about two-digit years (23 Nov 98)
@x module 1200
print_int(round_unscaled(internal[year]) mod 100); print_char(".");
@y
print_int(round_unscaled(internal[year])); print_char(".");
@z

566. "this can't happen" can happen if coordinates are half vast
 (Julian Gilbey, January 2001)
@x module 402
@!chopped:boolean; {have we truncated any of the data?}
@y
@!chopped:integer; {positive if data truncated,
          negative if data dangerously large}
@z
@x module 402
if internal[autorounding]>0 then xy_round;
octant_subdivide; {complete the subdivision}
if internal[autorounding]>unity then diag_round;
@<Remove dead cubics@>;
@<Insert octant boundaries and compute the turning number@>;
while left_type(cur_spec)<>endpoint do cur_spec:=link(cur_spec);
if tracing>0 then
  if internal[autorounding]<=0 then print_spec(", after subdivision")
@y
if (internal[autorounding]>0)and(chopped=0) then xy_round;
octant_subdivide; {complete the subdivision}
if (internal[autorounding]>unity)and(chopped=0) then diag_round;
@<Remove dead cubics@>;
@<Insert octant boundaries and compute the turning number@>;
while left_type(cur_spec)<>endpoint do cur_spec:=link(cur_spec);
if tracing>0 then
  if (internal[autorounding]<=0)or(chopped<>0) then
    print_spec(", after subdivision")
@z
@x module 404
@d procrustes(#)==if abs(#)>max_allowed then
    begin chopped:=true;
    if #>0 then #:=max_allowed@+else #:=-max_allowed;
    end

@<Truncate the values of all coordinates that exceed...@>=
p:=cur_spec; k:=1; chopped:=false;
@y
@d procrustes(#)==if abs(#)>=dmax then
  if abs(#)>max_allowed then
    begin chopped:=1;
    if #>0 then #:=max_allowed@+else #:=-max_allowed;
    end
  else if chopped=0 then chopped:=-1

@<Truncate the values of all coordinates that exceed...@>=
p:=cur_spec; k:=1; chopped:=0; dmax:=half(max_allowed);
@z
@x module 404
if chopped then
@y
if chopped>0 then
@z

567. I forgot to update curtype in e.g. boolean b[]; b1=true=b2;
 (Thorsten Dahlheimer, June 2004)
@x 1003
    begin nonlinear_eq(v,cur_exp,false); goto done;
@y
    begin nonlinear_eq(v,cur_exp,false); unstash_cur_exp(cur_exp); goto done;
@z

568. Wrong handling of extreme TFM values (T. Dahlheimer, June 2004)
@x 1128
max_tfm_dimen:=16*internal[design_size]-internal[design_size] div @'10000000;
@y
max_tfm_dimen:=16*internal[design_size]-1-internal[design_size] div @'10000000;
@z
@x 1129
  if x>0 then x:=three_bytes-1@+else x:=1-three_bytes;
  end
else x:=make_scaled(x*16,internal[design_size]);
@y
  if x>0 then x:=max_tfm_param@+else x:=-max_tfm_param;
  end;
x:=make_scaled(x*16,internal[design_size]);
@z

569. Bug in make_ellipse when theta=180 (T. Dahlheimer, June 2004)
@x 530
  else  begin beta:=minor_axis; gamma:=major_axis;
@y
  else  begin beta:=minor_axis; gamma:=major_axis; theta:=0;
@z

570. Forgot outer_tag in scan_declared variable (T. Dahlheimer, June 2004)
@x 1011
done: if eq_type(x)<>tag_token then clear_symbol(x,false);
@y
done: if eq_type(x) mod outer_tag<>tag_token then clear_symbol(x,false);
@z

571. Apparent bug if init_gf called at incredibly unlikely time (T. Dahlheimer,
June 2004); not REALLY a bug, because str_ptr cannot equal max_strings here
(because this was checked by end_name, and area_delimiter=0 there because
cur_area="" in the output file name); but anyway I'll make a patch to be clean
@x 1163
str_start[str_ptr+1]:=pool_ptr; gf_string(0,str_ptr);
@y
gf_string(0,make_string); decr(str_ptr);
@z

572. Memory leak in make_ellipse on symmetric pens that don't have
a point on the x-axis (Eberhard Mattes, 03 June 2008)
@x module 536
done1: link(p):=s; beta:=-y_coord(h);
@y
done1: if (link(p)<>null) then free_node(link(p),knot_node_size);
link(p):=s; beta:=-y_coord(h);
@z

-------------
999. The absolutely final change (to be made after my death)
@x module 2
@d banner=='This is METAFONT, Version 2.7182818' {printed when \MF\ starts}
@y
@d banner=='This is METAFONT, Version $e$' {printed when \MF\ starts}
@z
When this change is made, the corresponding line should be changed in
Volume D, and also on page 31 of The METAFONTbook.
My last will and testament for METAFONT is that no further changes be made
under any circumstances. Improved systems should not be called simply
`METAFONT'; that name, unqualified, should refer only to the program for which
I have taken personal responsibility.  -- Don Knuth