summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/bigfoot/bigfoot.dtx
blob: 769653fe784b412aaec728726f565c7c40a9d555 (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
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
% \iffalse
%%
%% bigfoot is part of the bigfoot bundle for critical typesetting
%% Copyright 2004--2015  David Kastrup <dak@gnu.org>
%%
%% The license notice and corresponding source code for this file are
%% contained in bigfoot.dtx.
%%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
% \fi
% \CheckSum{4580}
% \GetFileInfo{bigfoot.sty}
% \title{The \texttt{bigfoot} package\\version \fileversion}
% \date{\filedate}
% \author{David Kastrup\thanks{dak@gnu.org}}
% \maketitle
% Purpose of this package is to provide a one-stop solution to almost
% all problems related to footnotes.  You can use it as a drop-in
% replacement of the \texttt{manyfoot} package, but without many of
% its shortcomings, and quite a few features of its own.  It uses the
% existing document class layouts for footnotes, so you can usually
% use it without having to worry about the looks.
%
% Features are:
% \begin{itemize}
% \item You can specify and use multiple footnote apparatus.
%   Footnotes for an apparatus lower on the
%   page\footnoteB{like this one} can be anchored in an
%   apparatus\footnote{The plural of ``apparatus'' is actually
%     ``apparatus''\footnoteB{Well, actually ``apparat\=us'' with a
%       long ``u'', but that's just obvious in spoken Latin.}}
%   that is higher on the page.
% \item The last footnote in each apparatus may be broken to the next
%   page.\footnote{This will probably be interesting for footnotes
%     that contain stuff like math equations\footnoteB+{Like
%       \begin{equation}
%         \label{eq:1}
%         \sum_{k=1}^\infty \frac{1}{k^2} = \frac{\pi^2}{6}
%       \end{equation}} or lists\footnoteB+{Like
%       \begin{itemize}
%       \item This, or
%       \item this.
%       \end{itemize}}.}
%   Any subordinate footnote anchors that get moved to the next page
%   will take the corresponding footnote with them.
% \item The order of footnotes in an apparatus is `natural': it starts
%   with any footnote that may have been broken from the next page,
%   followed by footnotes from the current page in the order of the
%   appearance of their footnote
%   marks.\footnoteB{This footnote appears above notes on notes.}
%   Where the order of appearance in the document differs from the
%   order in the source code, you will usually want to use the
%   \cmd{\MakeSorted} command from the |perpage| package to get the
%   numbering fixed appropriately.
% \item Footnotes can be formatted in separate paragraphs, or be run
%   into a single paragraph.  The choice is made per footnote
%   apparatus, but can be overridden for single
%   footnotes.\footnote{I.e., footnotes with display
%     math\footnoteB{We had this already, right?} or list
%     environments\footnoteB{And this looks familiar, too.} have to be
%     done in vertical mode.}
% \item If footnotes are run into one paragraph, a variety of criteria
%   makes sure that this formatting is only chosen when it saves
%   noticeable space and delivers visually attractive results.
% \item Parameters for footnote formatting can be specified globally,
%   or separately for each footnote.
% \item The material in footnotes can contain |\verb|-like material
%   without problems.\footnote{We wrote \verb+|\verb|-like+ above in
%     the main text.\footnoteB{Well, this is not so impressive.  But we
%       wrote \verb/\verb+|\verb|-like+/ in the footnote then.}}
% \item You can use color in footnotes.  If a footnote gets broken
%   across pages, the color at the point of the break will get resumed
%   on the next page.  Actually, the whole color stack will get
%   reinstated.
% \end{itemize}
% As an example of how simple the usage can be, here is the
% documentation driver for this document:
%    \begin{macrocode}
%<*driver>
\documentclass{ltxdoc}
\usepackage{bigfoot}
\usepackage{tabularx}
\usepackage{hyperref}
%    \end{macrocode}
% After loading the packages, we declare two footnote blocks.  One is
% the default footnote block, another block is called~|B| and is
% numbered with letters.  The letters start new on each page.  Both
% footnote blocks default to in-paragraph footnotes.  Since the
% block~|B| can get entries from both the main text as well as the
% default footnote block, the entries are not necessarily generated in
% page order.  So we need to use a sorted counter to fix this (feel
% free to try what happens when using an unsorted counter).
%    \begin{macrocode}
\DeclareNewFootnote[para]{default}
\DeclareNewFootnote[para]{B}[alph]
\MakeSortedPerPage{footnoteB}
%    \end{macrocode}
% In addition, we add an alternate footnote sequence that can be
% interspersed with the normal footnotes by use of the
% \cmd{\footnote'} command which we effectively define here.
%    \begin{macrocode}
\newcounter{footalt}
\def\thefootalt{\fnsymbol{footalt}}
\MakeSortedPerPage[2]{footalt}
\WithSuffix\def\footnotedefault'{\refstepcounter{footalt}%
  \Footnotedefault{\thefootalt}}
%    \end{macrocode}
% Actually, that already was all.  We can now start the document.  The
% following makes sure that we get the full documentation only by
% compiling the separate driver file:
%    \begin{macrocode}
\begin{document}
\OnlyDescription
%<driver> \AlsoImplementation
\DocInput{bigfoot.dtx}
\end{document}
%</driver>
%    \end{macrocode}
% In order to be useful without additional hassle, the normal footnote
% level will be called |default|.  If no such style has been defined
% at the start of the document, it will get defined and used for
% ordinary footnotes, fixing quite a few problems of \LaTeX's own
% footnote placement algorithms.
%
% Apart from that, usage is very much like that of |manyfoot|, so for
% the customization possibilities of |bigfoot| with regards to
% multiple footnote blocks and rules between them, refer to
% |manyfoot|'s documentation.
%
% |bigfoot| contains a lot of bells and whistles for defining your
% footnote formats and can use different formats for different
% footnote blocks.  Those expert options are not documented separately
% yet: look through the code sections to see them explained.
% \StopEventually{}
% \section{The implementation}
% \subsection{Startup code}
% We declare the package and several compatibility options supposed to
% make |bigfoot| a drop-in replacement for |manyfoot|.
%    \begin{macrocode}
%<*style>
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{bigfoot}[2015/08/30 2.1 makes footnotes work]

\DeclareOption{para}{\PackageInfo{bigfoot}{Compatibility option `para'
  has no effect:^^J%
  Spacing will be guessed from `\string\@makefntext' unless^^J%
  `\string\@preparefnhtext' is redefined}}

\DeclareOption{para*}{\PackageInfo{bigfoot}{Compatibility option
    `para*':^^J%
    Redefining `\string\@preparefnhtext'}%
  \def\@preparefnhtext{\ifx\@thefnmark\@empty
    \else\@makefnmark\nobreak\fi}}

\DeclareOption{ruled}{\PassOptionsToPackage{ruled}{manyfoot}}
%    \end{macrocode}
% The normal processing makes footnote text macros allow verbatim and
% similar.  We call this |robust| processing though it is not totally
% accurate.  This is the default.  There is also an option |fragile|
% which will not allow this, but may be required for some definitions
% of \cmd{\@makefntext}.  It turns out that most document classes work
% with the `robust' option, but there might be some that fail, and
% there might be some footnote-modifying packages that also can cause
% failure.
%    \begin{macrocode}
\DeclareOption{robust}{\def\FN@makefncall{\FN@makefnrobust}}
\DeclareOption{fragile}{\def\FN@makefncall{\FN@makefnfragile}}
\ExecuteOptions{robust}
%    \end{macrocode}
% The |verbose| option talks about changed labels at the end of a
% run.  It is for debugging instable configurations that fail to
% converge after a number of \TeX\ runs.  The output is probably
% obscure.
%    \begin{macrocode}
\DeclareOption{verbose}{\AtBeginDocument{%
    \def\@testdef #1#2#3{%
      \def\reserved@a{#3}%
      \expandafter \ifx \csname #1@#2\endcsname
        \reserved@a
      \else \@tempswatrue
        \typeout{Changed label #1/#2:
          \csname #1@#2\endcsname->#3}%
      \fi}}}
%    \end{macrocode}
% The |trace| option is only available if you used |docstrip| while
% explicitly requesting |trace| functionality.  If you set the |trace|
% option, the next option specifies a bit map of trace bits.
%
% The following bits can be set in tracing:
% \begin{tabular}{rl}
%   1&break decisions\\
%   2&horizontal box building\\
%   4&allocation stuff\\
%   8&output routine stuff\\
%  16&retained and kept boxes
% \end{tabular}
%    \begin{macrocode}
%<trace>\DeclareOption{trace}{%
%<trace>\DeclareOption*{\ftflags=\CurrentOption\relax
%<trace>  \DeclareOption*{\OptionNotUsed}}%
%<trace>  \AtEndOfPackage{\RequirePackage{trace}\relax
%<trace>  \errorcontextlines\maxdimen
%<trace>  \showboxdepth4
%<trace>  \showboxbreadth100
%<trace>  \tracingonline=\@ne}%
%<trace>}
%    \end{macrocode}
% The |tracepage| option is followed by another option specifying the
% page to be traced.  If you use it, tracing happens only on the
% specified page.  Only a single page can be specified.
%    \begin{macrocode}
%<trace>\def\FN@tracepage{\c@page}
%<trace>\DeclareOption{tracepage}{%
%<trace>  \DeclareOption*{\edef\FN@tracepage{\CurrentOption}%
%<trace>    \DeclareOption*{\OptionNotUsed}}}
%<trace>\newcount\ftflags
%<trace>\def\foottrace#1{\ifnum\numexpr(\ftflags+(#1))/(2*#1)*(2*#1)%
%<trace>  =\numexpr(\ftflags+3*#1/2)/#1*#1\relax
%<trace>  f\else t\fi\ifnum\FN@tracepage=\c@page t\else n\fi}
\ProcessOptions*
%    \end{macrocode}
% |hyperref|'s footnote support will just cause trouble.  So if
% |hyperref| was already loaded or is going to be loaded, we turn off
% its footnote support.  If you think you know what you are doing, you
% can use \cmd{\hypersetup} to turn it on again before the start of
% the document.  Unfortunately, it appears like \cmd{\hypersetup}
% refuses to be called more than once, so this actually does not work
% unless you load |hyperref| last.
%    \begin{macrocode}
\ifx\hypersetup\@undefined
  \PassOptionsToPackage{hyperfootnotes=false}{hyperref}
\else
  \hypersetup{hyperfootnotes=false}
\fi
%    \end{macrocode}
% We require the |etex| package because
% \begin{enumerate}
% \item We need the facilities of the \eTeX\ engine; and where they
%   are not available, the error messages from not finding the |etex|
%   package or from loading it into the wrong engine make much more
%   sense than what would happen otherwise.
% \item We allocate quite a few registers, and the danger of running
%   out of them is smaller when the extra registers of \eTeX\ are
%   taken into account.  Now unfortunately the LaTeX team has decided
%   in 2015 to do its own extended allocation scheme incompatible with
%   the |etex| package, so we need to guard against this load in case
%   the new LaTeX allocation scheme is detected.
% \end{enumerate}
% We need the |manyfoot| package to build on.  The |suffix| and
% |perpage| package are needed for some small stuff.
%    \begin{macrocode}
\ifx\e@alloc\@undefined
\RequirePackage{etex}
\fi
\RequirePackage{manyfoot}
\RequirePackage{suffix}
\RequirePackage{perpage}
%    \end{macrocode}
% \subsection{Fixes to the \texttt{manyfoot} package}
% While those fixes have been submitted once to the author of
% |manyfoot|, they have not made it into its distribution at the
% current point of time.  In the interest of stability, it would
% probably be best just to incorporate the parts from |manyfoot| that
% get used by |bigfoot|.  This has not yet been done.
%
% \begin{macro}{\MFL@reinsout}
%   We need the appropriate splitting parameters set for the footnote
%   again.  \cmd{\MFL@realinsert} does that, but it has the disadvantage
%   that it uses \cmd{\strutbox}, and that may be set to arbitrary
%   values at the time the output routine is invoked.  |manyfoot|
%   already has this problem with minipages: the split sizes will be
%   those of the font at the end of the minipage instead of those at the
%   time the footnote body was set up.  So we do this here, and see
%   later for more info about how to do this right:
%    \begin{macrocode}
\def\MFL@reinsout#1#2{\ifvoid#2\else
    \ifnum\count\@currbox>\z@
      \advance\@pageht \ht#2%
      \advance\@pageht \skip#2%
      \advance\@pageht \dp#2%
    \fi
    \MFL@realinsert{#2}{\unvbox#2}%
  \fi
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\MFL@reins}
%   Actually, I don't get the purpose of the following line in the
%   first place.  But if we do need it for some reason, it is rather
%   certain that we don't want this empty insert to float.  Use
%   \cmd{\MFL@realinsert}, or set the floatingpenalty the hard way.
%    \begin{macrocode}
\def\MFL@reins#1#2{\ifvoid#2\else\insert#2{\floatingpenalty\@MM}\fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\MFL@mpinsert}
% \begin{macro}{\MFL@minipage}
%   The structure of the \cmd{\MFL@mpinsert} box is overly
%   complicated, and it is a bad idea to unpack the boxes put into it
%   too early: the \cmd{\lastbox} command is pretty inefficient when
%   the list before it is long due to unpacking.  So we just leave
%   everything packed in its own boxes, and unpack only at the moment
%   when we are reinserting.
%    \begin{macrocode}
\long\def\MFL@mpinsert#1#2{%
  \global\setbox#1\vbox{%
    \unvbox#1%
    \nointerlineskip
    \vbox{#2}%
  }%
}

\def\FN@divert{%
  \let\MFL@mpinsertsave\MFL@insert
  \MFL@reinsert \let\MFL@insert\MFL@mpinsert}
\def\FN@enddivert{{\let\@elt\MFL@mpreinsert \MFL@list}}

\def\MFL@minipage{\ifinner\else \FN@divert\fi}
\def\MFL@endminipage{\ifinner\else \FN@enddivert\fi}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \begin{macro}{\MFL@mpreinsert}
%   When reinserting, we put all but the last insertion into one
%   humongous blob.  This is so that the last insertion can be split
%   by \TeX's paragraph splitting routines.  The footnote types that
%   |bigfoot| supports will never get split by \TeX, anyhow, but it is
%   conceivable that other extension packages for manyfoot work
%   differently.  There is one difference, though: we let a slave mark
%   escape into the main vertical list.
%    \begin{macrocode}
\def\MFL@mpreinsert#1#2{%
  \ifvoid#2\else
    \setbox\@tempboxa\vbox\bgroup\unvbox#2%
      \global\setbox#2\lastbox
      \setbox\z@\lastbox
      \ifvoid\z@
        \egroup
        \setbox\z@\box#2%
      \else
        \MFL@removevboxes \unvbox\z@
        \egroup
        \setbox\z@\box#2%
        \MFL@mpinsertsave#2{\unvbox\@tempboxa}%
      \fi
    \ifvoid\z@\else
      \MFL@mpinsertsave#2{\unvbox\z@}%
    \fi
    \marks\FN@slave{\number\FN@id}%
  \fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\MFL@removevboxes}
%   This trick works like \cmd{\removehboxes} in the \TeX book's
%   appendix~D.
%    \begin{macrocode}
\def\MFL@removevboxes{{\setbox\z@\lastbox
    \ifvbox\z@ \MFL@removevboxes \unvbox\z@\fi}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\NCC@makefnmark}
%   This provides the command in case it is not present (some versions
%   did not have it).
%    \begin{macrocode}
\ifx\NCC@makemark\@undefined
  \ifx\NCC@makefnmark\@undefined \else
    \def\NCC@makemark{\NCC@makefnmark}
  \fi
\fi
%    \end{macrocode}
% \end{macro}
%
% While the above operations actually were fixes to |manyfoot|, now we
% actually patch it for our own purposes.  When allocating a new
% footnote, we set its maximum dimension to \cmd{\maxdimen} (since no
% hard limit makes sense, given that we recalculate all respective
% sizes at output time) and allocate a cache box to go with it.  We
% also add the insertion to the list of insertions in
% \cmd{\FN@nestlist}.
% \begin{macro}{\MFL@startplain}
% \begin{macro}{\MFL@startpara}
%    \begin{macrocode}
\def\MFL@startplain#1{\global\dimen#1\maxdimen
  \@cons\FN@nestlist{{}#1}%
  \expandafter\expandafter\expandafter\newbox\FN@cache#1}

\let\MFL@startpara\MFL@startplain
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \begin{macro}{\RestyleFootnote}
%   This macro gets two arguments: a footnote \meta{type}, and the
%   style to be used for it.  It works by redefining the corresponding
%   |Footnotetext|\meta{type} macro.
%    \begin{macrocode}
\def\RestyleFootnote#1#2{\expandafter\xdef
  \csname Footnotetext#1\endcsname{\expandafter
    \noexpand\csname MFL@fnote#2\endcsname{\csname footins#1\endcsname}}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@stripfootins}
% \begin{macro}{\FN@restylefootnote}
%   We need the same kind of functionality for a footnote specified by
%   its footnote insertion.  So we strip the footnote \meta{type} from
%   the insertion macro name.  Kind of ugly.
%    \begin{macrocode}
\expandafter\def\expandafter\FN@stripfootins\string\footins{}

\def\FN@restylefootnote#1#2{{\edef\next{%
      \noexpand\RestyleFootnote{\expandafter\FN@stripfootins
        \string#1}{#2}}\next}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Dealing with footnote-specific code}
% The formatting of footnotes is determined by macros such as
% \cmd{\@makefntext}.  For several blocks of footnotes, we might want
% to have several different ways for formatting them.  Whenever this
% is the case, we call them with
% \begin{quote}
%   |\FN@specific|\marg{insert\#}\marg{macroname}
% \end{quote}
% This will use the default \meta{macroname} unless a special macro has
% been defined with something like
% \begin{quote}
%   |\FootnoteSpecific\marg{type}|\def|\meta{macroname}\dots
% \end{quote}
% A number of other defining commands and constructs are available:
% those are pretty much like the ones for the \cmd{\WithSuffix} command
% implemented by the |suffix| package.
% \begin{macro}{\FN@specific}
%   We use |\romannumeral| here just for the purpose of sustaining
%   expansion.  It expands to nothing when followed by |\z@|
%   eventually.  Thus expanding the expansion of \cmd{\FN@specific}
%   again delivers the (unexpanded) final token to use.
%    \begin{macrocode}
\def\FN@specific#1#2{\romannumeral
  \ifcsname FN\string#2\number#1\endcsname
  \expandafter
    \z@\csname FN\string#2\number#1\expandafter\endcsname
  \else\expandafter\z@
    \expandafter#2\fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FootnoteSpecific}
% \begin{macro}{\FN@specific@ii}
%   This is all a bit muddy, but quite similar to what the |suffix|
%   package does, so you might want to look there for the explanation.
%    \begin{macrocode}
\def\FootnoteSpecific#1{\count@\csname footins#1\endcsname\toks@{}%
  \FN@specific@ii}

\long\def\FN@specific@ii#1#2{\toks@\expandafter{\the\toks@#1}%
  \the\expandafter\toks@
  \csname FN\string#2\number\count@\endcsname}

\WithSuffix\def\FN@specific@ii\long{\toks@\expandafter
  {\the\toks@\long}\FN@specific@ii}

\WithSuffix\def\FN@specific@ii\global{\toks@\expandafter
  {\the\toks@\global}\FN@specific@ii}

\WithSuffix\def\FN@specific@ii\expandafter{\expandafter
  \FN@specific@ii\expandafter}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Putting footnotes into insertions}
% \subsubsection{Dealing with Ids}
%   Since we have to store additional information for each footnote as
%   long as it is not yet typeset, we allocate and deallocate numeric
%   `id's on an as-needed base, since we do not want to store this
%   sort of information indefinitely, with a large toll on hash space.
%   So we work with indirect ids, where the unique ids are just
%   referenced indirectly.  We do this with `slots'.
% \begin{macro}{\FN@slotxdef}
% \begin{macro}{\FN@slotget}
%   New slots are assigned values with \cmd{\FN@slotxdef}, which can
%   be retrieved again with \cmd{\FN@slotget}.
%    \begin{macrocode}
\def\FN@slotxdef#1{%
  \global\expandafter\xdef\csname FN@slot#1\endcsname}

\def\FN@slotget#1{\csname FN@slot#1\endcsname}
%<trace>\def\FN@slotget#1{%
%<trace>  \expandafter\FN@slotgetii\expandafter
%<trace>     \FN@slotfreelist\expandafter
%<trace>     {\number\number#1}}
%<trace>\def\FN@slotgetii#1#2{%
%<trace>  \ifx#1\@empty \csname FN@slot#2\endcsname\else
%<trace>    \ifnum#1=#2 \errmessage{Use after freed: #1}\else
%<trace>       \expandafter\FN@slotgetii
%<trace>         \csname FN@slot#1\endcsname{#2}\fi\fi}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \begin{macro}{\FN@slotfreelist}
% \begin{macro}{\FN@nextslot}
%   \cmd{\FN@slotfreelist} point to the first already allocated
%   available id to be reused.  If it is empty, none exist.  In that
%   case, \cmd{FN@nextslot} contains the next slot number to use.
%    \begin{macrocode}
\def\FN@slotfreelist{}
\def\FN@nextslot{1}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \begin{macro}{\FN@newslot}
%   This allocates a new slot by setting the given macro to a
%   currently unused slot number in decimal form.  If there is
%   something left in the freelist, it is assigned, otherwise a new
%   slot gets allocated.
%    \begin{macrocode}
\def\FN@newslot#1{%
  \ifx\FN@slotfreelist\@empty
    \edef#1{\FN@nextslot}%
    \xdef\FN@nextslot{\number\numexpr \FN@nextslot+\@ne}%
  \else
    \let#1\FN@slotfreelist
    \xdef\FN@slotfreelist{\csname FN@slot\FN@slotfreelist\endcsname}%
  \fi
%<trace>  \if\foottrace4\message{^^JAllocated #1^^J}\fi
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@freeslot}
%   This frees a given slot (by number) again by adding it to the
%   freelist.
%    \begin{macrocode}
\def\FN@freeslot#1{%
%<trace>  \if\foottrace4\message{^^JFreeing #1^^J}\fi
  \global\expandafter\let\csname FN@slot#1\endcsname=\FN@slotfreelist
  \xdef\FN@slotfreelist{#1}}
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{Dealing with footnote stacks}
% Footnote stacks are used for paired footnotes that refer to a text
% range instead of a single text point.  For example, you can use
% something like
% \begin{verbatim}
% Text \var<{was there}is here\var>
% \end{verbatim}
% To have a text variant ``was there'' for the original passage ``is
% here'', and mark it, say, as ``\textsuperscript{a}is
% here\textsuperscript{\textsl{a}}'' by employing the |suffix| package
% suitably.  This would anchor the footnote at the start of the
% passage.  It would also be imaginable to implement the syntax
% \begin{verbatim}
% Text \var<is here\var>{was there}
% \end{verbatim}
% for anchoring it at the end of the given passage.
%    \begin{macrocode}
\global\let\FN@stacklist\@empty
%    \end{macrocode}
% \begin{macro}{\DefineFootnoteStack}
%   This command is used for defining a footnote stack.  It gets a
%   single argument which is the name of the stack and should consist
%   just of ordinary character tokens.
%    \begin{macrocode}
\def\DefineFootnoteStack#1{%
  \global\expandafter\let\csname FN@stack@#1\endcsname\@empty
  \@cons\FN@stacklist{{#1}}%
}
%    \end{macrocode}
% \end{macro}
% At the end of the document, all stacks are checked to make sure they
% have been used up completely.
%    \begin{macrocode}
\AtEndDocument{\FN@checkstacklist}

\def\FN@checkstacklist{{\let\@elt\FN@checkstack
  \FN@stacklist}}

\def\FN@checkstack#1{{\let\@elt\FN@checkstackentry
    \csname FN@stack#1@\endcsname}}

\def\FN@checkstackentry#1#2#3{%
  \PackageError{bigfoot}{Unfinished #1 #2 from line #3}%
  {The specified footnote range is uncomplete}}
%    \end{macrocode}
% \begin{macro}{\PushFootnoteMark}
%   This gets one argument, the name of the footnote stack.  It pushes
%   the current footnote mark name stored in \cmd{\@thefnmark} onto
%   the footnote stack.
%    \begin{macrocode}
\def\PushFootnoteMark#1{{\let\@elt\relax
  \expandafter\unrestored@protected@xdef \csname FN@stack@#1\endcsname
  {\@elt{#1}{\@thefnmark}{\number\inputlineno}\csname
  FN@stack@#1\endcsname}}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\PopFootnoteMark}
%   This gets one argument, the name of the footnote stack.  It pops
%   the value of \cmd{\@thefnmark} from the named footnote stack.
%    \begin{macrocode}
\def\PopFootnoteMark#1{\expandafter
  \ifx\csname FN@stack@#1\endcsname\@empty
    \PackageError{bigfoot}{Empty footnote stack #1}%
    {The specified footnote type has no uncompleted range}%
  \else
  {\let\@elt\FN@firstpop
    \iffalse{\fi\csname FN@stack@#1\endcsname}}\fi}
%    \end{macrocode}
% \end{macro}
%    \begin{macrocode}
\def\FN@firstpop#1#2#3{\protected@xdef\@thefnmark{#2}%
  \let\@elt\relax
  \expandafter\protected@xdef\csname FN@stack@#1\endcsname{%
    \iffalse}\fi}
%    \end{macrocode}
%
% \subsubsection{Continuation marks}
%
% We add a possibility of adding continuation marks.  While the box is
% assembled, immediately before the break, \cmd{\FN@beforebreak} gets
% called, and \cmd{\FN@afterbreak} is called at the top of the
% continuing box.
%    \begin{macrocode}
\ifx\FN@beforebreak\@undefined
  \let\FN@beforebreak\@empty
\fi
\ifx\FN@afterbreak\@undefined
  \let\FN@afterbreak\@empty
\fi
%    \end{macrocode}
%
%
%\subsubsection{The works}
%
% \begin{macro}{\FN@cache}
%   Cacheboxes cache the typeset forms of the insertion boxes for a
%   certain configuration of footnotes.
%    \begin{macrocode}
\def\FN@cache#1{\csname FN@cache\number#1\endcsname}
%    \end{macrocode}
% \end{macro}
% \cmd{\FN@sortlist} takes the current vertical list and sorts the
% contained boxes according to their width (which is supposed to
% contain the sort key).
%
% The algorithm is a pretty straightforward insertion sort with
% $O(n^2)$~steps.  This is the best one can hope for without
% comparisons across non-adjacent list elements.  For presorted lists,
% the performance will be $O(n)$, and that's what we expect to see for
% simple cases (and when there are no sortkeys yet).  Any negative
% width will certainly hang the algorithm.
%
% It also happens that \TeX\ has a hardwired limit for grouping levels
% that hits at 255.  Oops.  We better not have a few hundred footnotes
% in a single block on one page\dots
%    \begin{macrocode}
\def\FN@sortlist{{%
  \setbox\z@\lastbox
  \ifvoid\z@ \else \FN@sortlist\FN@sortlistii \fi}}

\def\FN@sortlistii{%
  \setbox\tw@\lastbox
  \ifvoid\tw@\else
  \ifdim\wd\tw@<\wd\z@ {\FN@sortlistii}%
  \fi\nointerlineskip\box\tw@\fi\nointerlineskip\box\z@}
%    \end{macrocode}
% \begin{macro}{\FN@sortinsert}
%   This function is an \cmd{\@elt} function that will sort the given
%   insertion if it is non-empty and if there is no cache box present
%   (which would imply that the insertion had already been sorted
%   previously).
%    \begin{macrocode}
\def\FN@sortinsert#1#2{\ifvoid\FN@cache#2%
  \ifvoid#2\else\global\setbox#2\vbox{\unvbox#2%
    \FN@sortlist}\fi\fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@maybeinvalidatecache}
%   This is called after pulling in additional material from the
%   page.  If the material added an insertion, the cache is junk and
%   must be regenerated.
%    \begin{macrocode}
\def\FN@maybeinvalidatecache#1#2{%
  \ifvoid#2\else\global\setbox\FN@cache#2=\box\voidb@x\fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@regeneratecache}
%   This unconditionally regenerates one cache box.  The structure of
%   a cache box is basically a list of vertical boxes.  All but the
%   last such box are packed into a single vertical box which is then
%   followed by the last vertical box.
%    \begin{macrocode}
\def\FN@regeneratecache#1#2{%
   \global\setbox\FN@cache#2=%
   \ifvoid#2%
     \box\voidb@x
   \else
     \vbox{\vbox{\unvcopy#2%
         \setbox\z@\lastbox
         \def\FN@masterinsert{#2}%
         \FN@assembleboxes
         \global\setbox\FN@cache#2\box\z@}%
       \nointerlineskip \box\FN@cache#2}%
    \fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@mayberegeneratecache}
%   This regenerates the cache in case the cache box has been voided
%   in order to mark it as invalid.
%    \begin{macrocode}
\def\FN@mayberegeneratecache#1#2{%
  \ifvoid\FN@cache#2%
    \FN@regeneratecache{}#2%
  \fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@cachesize}
%   This calculates the size impact of a cache box on the current page
%   as a term to be added into a \cmd{\glueexpr}-type of expression.
%    \begin{macrocode}
\def\FN@cachesize#1#2{%
  \ifvoid\FN@cache#2%
  \else
    +\skip#2+(\ht\FN@cache#2+\dp\FN@cache#2)*\count#2/\@m
  \fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@clearcache}
%   This just completely voids a cache register.
%    \begin{macrocode}
\def\FN@clearcache#1#2{%
  \global\setbox\FN@cache#2=\box\voidb@x}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@makefnvtext}
%   Ok, this is one of the parts putting together footnotes in para
%   mode.  The footnotes themselves have already been formatted into
%   hboxes (placed there with \cmd{\@preparefnhtext} in order to cater
%   for proper indentation).  \cmd{\@makefnvtext} then formats a
%   single footnote block from horizontal mode pieces (vertical mode
%   pieces are kept as-is).
%   This takes text and typesets it in a single block.  To get correct
%   indentation, it breaks before the first footnote and adjusts the
%   clubpenalties to move them to one line lower effectively.
%   \cmd{\@makefnvtext} is called in vertical mode, and its argument
%   is typeset in horizontal mode right after a break, inside of
%   \cmd{\@makefntext}.
%    \begin{macrocode}
\def\@makefnvtext#1{%
  \FN@specific\FN@masterinsert\@makefntext{%
    \clubpenalties\thr@@\@MM\clubpenalty\z@
    \vadjust{\nobreak\vskip-\baselineskip}\nobreak\hfill\break#1}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\@preparefnhtext}
%   This creates appropriate skips to be put before the horizontal
%   material to make the indentation correct with a breakpoint before
%   the footnote as well as when in run-in text.  This is run once at
%   the start of each horizontal mode footnote when it is first being
%   typeset, in horizontal mode.
%    \begin{macrocode}
\ifx\@preparefnhtext\@undefined
\def\@preparefnhtext{{%
  \setbox\z@\vbox{\FN@specific\FN@masterinsert\@makefntext{%
      \unskip\unpenalty\setbox\z@\lastbox
      \dimen@
        \ifnum\parshape>\z@
          \dimexpr\parshapeindent\tw@-\parshapeindent\@ne\relax
        \else \ifnum\hangafter=\@ne\hangindent \else
          \ifnum\hangafter=\m@ne -\hangindent
          \else \z@ \fi\fi\fi
      \dimen@ii\dimen@
      \ifhbox\z@ \advance\dimen@-\wd\z@
        \setbox\z@\hbox{\unhbox\z@}%
        \advance\dimen@\wd\z@
      \fi
      \xdef\FN@tempinfo{\hskip\the\dimen@
        \vadjust{}\nobreak\hskip-\the\dimen@ii\relax}}}}%
  \FN@tempinfo}
\fi
%    \end{macrocode}
% Now we have in |\FN@tempinfo| the excess width of the label we don't
% want to preserve when doing in-paragraph footnote setting.  A
% sequence of glue before a label now has to consist of stuff that
% vanishes at a breakpoint, followed by stuff that remains.  We have
% to have two behaviors for the contents: behavior one is
% justification at the start of a line, behavior two is justification
% in the line.  When we are at the start of the line, preceding
% interword space disappears swallowed and so the natural criterion
% for distinguishing those cases is this initial line break.  This
% means that we can't avoid articifially adding a line break at the
% start of such a box.  We will back up its height again.  Some
% packages specify a |\hangindent| (I~know of no examples where they
% would actually set |\hangafter| to a value different from its
% default of~1, or set |\hangindent| to a negative value which would
% affect the right margin): due to our artifical line at the top, the
% indent will actually be active for the first line already.  We back
% it out of the actual labels happening at the start of the line.
% Two-line parshapes have the same effect: the first line is not
% actually used, and we put the relevant info for the first line into
% the label.  Different right indentation for the first line is
% something we can't simulate, but again, it should occur rarely.
% When |\parshape| is active, |\hangindent| is ignored.
% \end{macro}
%    \begin{macrocode}
\def\@makefnstartbox{%
  \ifdefined\setspace@singlespace
    \def\baselinestretch{\setspace@singlespace}%
  \fi
  \reset@font\footnotesize
  \hsize\MFL@columnwidth \@parboxrestore
  \interlinepenalty\FN@specific\FN@masterinsert\interfootnotelinepenalty
  \widowpenalty\FN@specific\FN@masterinsert\footnotewidowpenalty
  \clubpenalty\FN@specific\FN@masterinsert\footnoteclubpenalty
  \advance\linepenalty500\relax}

\def\@makefnendbox{%
  \widowpenalty\FN@specific\FN@masterinsert\finalfootnotewidowpenalty}

\newcount\footnotewidowpenalty
\footnotewidowpenalty=250
\newcount\footnoteclubpenalty
\footnoteclubpenalty=250
\newcount\finalfootnotewidowpenalty
\finalfootnotewidowpenalty=4000
%    \end{macrocode}
% \begin{macro}{\@makefnvbox}
%   This is the formatting code for a vertical mode footnote box from
%   already set horizontal material.  It uses \cmd{\@makefnstartbox}
%   for setting up the initial widow/club penalties, and
%   \cmd{\@makefnendbox} for preparing the final end.  It results in a
%   vbox.
%    \begin{macrocode}
\ifx\@makefnvbox\@undefined
  \def\@makefnvbox#1{\vbox{%
      \@makefnstartbox
      \clubpenalties\thr@@\@MM\clubpenalty\z@
      \let\@thefnmark\@empty
      \FN@specific\FN@masterinsert\@makefntext{\rule\z@\footnotesep
        \nobreak
        #1\@finalstrut\strutbox
      \@makefnendbox}}}
\fi
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\hfootfraction}
% \begin{macro}{\vtypefraction}
%   Those parameters govern when a footnote block is going to be set
%   completely in vertical mode.  If a footnote block does not shrink
%   to less than \cmd{\hfootfraction} its size when using in-paragraph
%   notes or has at least \cmd{\vtypefraction} of forcedly vertical
%   footnotes (specified as purely vertical, or vertical because of
%   being large), it is set entirely in vertical mode.
%    \begin{macrocode}
\def\hfootfraction{0.9}
\def\vtypefraction{0.7}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \begin{macro}{\FN@assembleboxes}
%   This will produce the finished product, by generating all boxes
%   and concatenating them except for the last vbox.  It is assumed
%   that have already set |\box\z@| to |\lastbox| before calling this
%   routine (or, more likely, have already assembled and split the
%   last box).  The last, not yet unpacked |\vbox| is left in
%   |\box\z@| on return.  The original id of the last box of a block
%   is properly transferred to it.
%
%   The last box might have come about by joining several horizontal
%   boxes, so splitting it might separate footnotes.  We deal with
%   that problem at a different point of time by checking the
%   respective Ids when breaking a vbox into pieces: if the split
%   piece does not contain the last footnote beginning, we switch to a
%   slow motion decomposal.  \cmd{\FN@assembleboxes} is supposed to be
%   entered and exited in vertical mode.
%    \begin{macrocode}
\def\FN@assembleboxes{%
%<trace> \ifhmode \PackageError{bigfoot}{Unexpected hmode}{}\fi
  \ifhbox\z@
    \dimen@\dp\z@
%<trace> \MFL@checksinglebox\z@\z@{}{}%
    \dimen@ii\z@
    \setbox\tw@\box\voidb@x
    \loop \advance\dimen@ii\dimexpr\ht\z@+\dp\z@\relax
      \setbox\tw@\hbox{\box\z@\unhbox\tw@}%
      \setbox\z@\lastbox
    \ifhbox\z@
    \repeat
    {\FN@assembleboxes\nointerlineskip\unvbox\z@}%
%    \end{macrocode}
% At this point of time, |\box\tw@| contains a plain hbox with nothing
% but the unadorned hboxes in horizontal mode to be joined into one
% footnote block.  All preceding footnote blocks have been emptied
% into the current vertical list.  We put the |\unvbox| operations in
% a group so that the paragraph shapes will not get reset over the
% break.
%    \begin{macrocode}
    \global\setbox\FN@tempbox\copy\tw@
    \setbox\z@\@makefnvbox{%
      {\unhbox\FN@tempbox}%
      \setbox\z@\lastbox\FN@joinhboxes}%
    \ifcase
      \ifdim\FN@vfound>\dimexpr\vtypefraction\p@*\FN@found\relax \@ne\fi
      \ifdim\dimexpr \ht\z@+\dp\z@>\hfootfraction\dimen@ii \@ne\fi \z@
    \or
      \global\setbox\FN@tempbox\box\tw@
      \setbox\z@\@makefnvbox{\let\@makefnbreak\FN@pseudofillbreak
          {\unhbox\FN@tempbox}\setbox\z@\lastbox\FN@joinhboxes}%
    \fi
    \setbox\tw@\box\voidb@x
    \ht\z@\dimexpr \ht\z@+\dp\z@-\dimen@\relax
    \dp\z@\dimen@
%<trace>  \MFL@checksinglebox\z@\z@{}{}%
  \else
    \ifvbox\z@
%<trace>  \MFL@checksinglebox\z@\z@{}{}%
      {\setbox\z@\lastbox
      \FN@assembleboxes\nointerlineskip\unvbox\z@}%
    \fi
  \fi}
%    \end{macrocode}
% \end{macro}
% Ok, now follow a lot of fuzzy calculation routines.  When we are
% considering truth values, |\p@| (1pt) corresponds to a value of
% ``true'', and |\z@| corresponds to ``false''.
% \begin{macro}{\FN@fuzzyeval}
%   This calculates a ratio, something with which you multiply.  The
%   first two arguments of the function define an interval, and the
%   third argument is a value in that interval.  If |#3| is equal to
%   |#1|, the resulting ratio is~0, if the |#3| is equal to |#2|, the
%   resulting ratio is~1.  Values in between are linearly
%   interpolated.  Values outside of the interval are mapped to 0
%   and~1.  If all three values are equal (hardly useful), 1 is
%   returned.
%    \begin{macrocode}
\def\FN@fuzzyeval#1#2#3{%
  \ifdim\dimexpr(#3)<\dimexpr(#2)\relax
    \ifdim\dimexpr(#3)>\dimexpr(#1)\relax
      *(\dimexpr(#3)-(#1))%
      /(\dimexpr(#2)-(#1))%
    \else *\z@
    \fi
  \fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@fuzzyor}
%   This returns probabilistic \textsc{or}:
%   \[(|#1|+|#2|-|#1|\cdot|#2|)\]
%    \begin{macrocode}
\def\FN@fuzzyor#1#2{(\p@-(\p@-(#1))*(\dimexpr\p@-(#2))/\p@)}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@magicclue}
% Ok, so here is the magic glue calculator.  |#1| and~|#2| give the
% range over which the preceding line changes from `short' to `long'.
% |#3| and |#4| give the range over which the current line changes
% from `short' to `long'.  Both are combined with a probabilistic or
% function, and then a penalty is chosen which ranges from |#5|
% to~|#6| for short to long.
%    \begin{macrocode}
\def\FN@magicglue#1#2#3#4#5#6{%
%<trace> \if\foottrace2\traceon\fi
  \dimen@\dimexpr\p@\FN@fuzzyeval{#1}{#2}\FN@lasthsize\relax
  \dimen@ii\dimexpr\p@\FN@fuzzyeval{#3}{#4}{\ht\z@+\dp\z@}\relax
  \dimen@\dimexpr\FN@fuzzyor\dimen@\dimen@ii
  \count@\numexpr((#6)-(#5))*\dimen@/\p@+(#5)\relax
  \xdef\FN@vfound{\the\dimexpr\FN@vfound+\dimen@}%
  \ifnum\count@>-\@M
    \penalty\count@
    \hskip\glueexpr -\parfillskip+1em minus 0.5em\relax
  \else
    \FN@pseudobreak
  \fi
  \xdef\FN@found{\number\numexpr\FN@found+\@ne}%
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@pseudobreak}
%   This ends a line, but without introducing parskip and similar.  It
%   also `breaks in' the next line to get proper indentation.  The
%   main difference with regard to \cmd{\break} is that this restarts
%   the reckoning of line numbers for the sake of \cmd{\clubpenalty}
%   calculation.
%    \begin{macrocode}
\def\FN@pseudobreak{%
  {\parskip\z@skip\parfillskip\z@skip\parindent\z@\vadjust{}\par\noindent
    \vadjust{\nobreak\vskip-\baselineskip}\nobreak\hfill\break}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@pseudofillbreak}
%   This is basically just for separating paragraphs by force.
%    \begin{macrocode}
\def\FN@pseudofillbreak{\nobreak\hskip\parfillskip\FN@pseudobreak}
%    \end{macrocode}
%
% \end{macro}
% \begin{macro}{\@makefnbreak}
%   This calculates the glue for the standard horizontal footnotes.
%    \begin{macrocode}
\def\@makefnbreak{\FN@magicglue {\footnotesep+\dp\strutbox}%
  {\footnotesep+\dp\strutbox+\baselineskip}%
  {\footnotesep+\dp\strutbox+0.5\baselineskip}%
  {\footnotesep+\dp\strutbox+2\baselineskip}{-200}{-12000}}
%    \end{macrocode}
% \end{macro}
% \cmd{\FN@joinhboxes} is called with box~0 set to the next box to be
% appended to the current list (all preceding hboxes on the current
% vertical list will have to go in front).  \cmd{\FN@joinhboxes} is
% entered in vertical mode, and will be exited in horizontal mode.
%    \begin{macrocode}
\def\FN@joinhboxes{%
%<trace> \ifvmode \errmessage{Unexpected vertical mode.}\fi
  \begingroup\setbox\z@\lastbox
    \ifhbox\z@ \FN@joinhboxes
%<trace> \ifvmode \errmessage{Unexpected vertical mode.}\fi
      \endgroup
      \nobreak\hskip\parfillskip
      \@makefnbreak
    \else
%<trace> \ifvbox\z@ \errmessage{Unexpected vbox.}\fi
      \endgroup
      \vadjust{\nobreak\vskip-\baselineskip}\nobreak\hfill\break
      \xdef\FN@vfound{\z@}%
      \xdef\FN@found{\z@}%
    \fi
  \xdef\FN@lasthsize{\the\dimexpr \ht\z@ +\dp\z@}%
  \unhbox\z@}
%    \end{macrocode}
% \begin{macro}{\FN@par}
% \begin{macro}{\FN@noindent}
% \begin{macro}{\FN@indent}
%   In-paragraph footnotes are collected in horizontal mode.  So
%   |\par|, \cmd{\noindent} and \cmd{\indent} simply don't work.  We
%   replace them with something having the same effect when the boxes
%   get unhboxed.  Note that this does not admit the tracking of
%   club/widow penalties: in a later version, it should get replaced
%   by something that actually allows for separate paragraphs.  One
%   possibility would be to replace the current single hbox for an
%   in-paragraph footnote by an hbox of hboxes and unbox all of them
%   in separate paragraphs.  But that glosses over the fact that a
%   multi-paragraph footnote does not make sense in anything but
%   vertical mode.  So a saner way would probably be to close off the
%   hbox altogether and reinsert it into a vbox, restarting the whole
%   footnote in vertical mode.  Both of those approaches would require
%   that no groups have been opened since the start of the footnote by
%   the time |\par| gets called.  The below pseudosolution at least
%   has the advantage of not depending on the grouping structure at
%   all.
%    \begin{macrocode}
\def\FN@par{\unskip\nobreak\hskip\parfillskip
  \vadjust{\vskip\parskip}\break\null\kern\parindent\ignorespaces}
\def\FN@noindent{\unkern}
\def\FN@indent{\unkern{\setbox\z@\null\wd\z@\parindent\box\z@}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \begin{macro}{\MFL@fnoteplain}
% \begin{macro}{\MFL@fnotepara}
%   We redefine |manyfoot|'s basic footnote calls to use our own,
%   versatile variant.
%    \begin{macrocode}
\def\MFL@fnoteplain{\FN@fnotenested{plain}}
\def\MFL@fnotepara{\FN@fnotenested{para}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \begin{macro}{\FN@fnotenested}
%   This is somewhat contorted: we want |\footnote+| to be in |plain|
%   style and |\footnote-| in |para| style regardless of the current
%   footnote style.  Adding a second |+| or |-| after the first will
%   actually restyle all footnotes coming afterwards appropriately.
%   This should work for all footnote commands getting footnote text.
%    \begin{macrocode}
\def\FN@fnotenested#1#2#3{%
  \edef\reserved@d{#1}%
  \FN@checkvariant{\edef\reserved@d}{%
    \FN@checkvariant{\FN@restylefootnote{#2}}%
    {\csname FN@fnote\reserved@d\endcsname{#2}{#3}}}}

\def\FN@checkvariant#1#2{\def\reserved@a{#1}%
  \def\reserved@b{#2}%
  \futurelet\reserved@c\FN@checkvariantii}

\def\FN@checkvariantii{%
  \ifx\reserved@c+%
    \reserved@a{plain}\expandafter\@firstoftwo
  \else\ifx\reserved@c-%
    \reserved@a{para}\expandafter\expandafter\expandafter
    \@firstoftwo
  \fi\fi
  \reserved@b}
%    \end{macrocode}
% \end{macro}
% In order to be able to sort footnotes according to the order of
% their reference points, we use a sorted counter.
%    \begin{macrocode}
\newcounter{FN@totalid}
\MakeSorted{FN@totalid}
%    \end{macrocode}
% \begin{macro}{\FN@fnoteplain}
% \begin{macro}{\FN@fnotepara}
%   The actual commands are easy enough:
%    \begin{macrocode}
\def\FN@fnoteplain{\FN@fnotecommon\vbox}
\def\FN@fnotepara{\FN@fnotecommon\hbox}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \begin{macro}{\FN@masterinsert}
%   This contains the insert number of the insert where the footnote
%   mark appears.  If it appears in the main text, 255~will be used.
%    \begin{macrocode}
\def\FN@masterinsert{\@cclv}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@id}
% \begin{macro}{\FN@master}
% \begin{macro}{\FN@slave}
%   Here is the deal with master and slave ids: each footnote has a
%   unique master id.  This master id is larger by one than the last
%   id of its subordinate footnotes.  It is recorded in the mark
%   \cmd{\FN@master} in the footnote box at the start itself, although
%   with an indirection through the \cmd{\FN@newslot} mechanism since
%   the actual id can only become known after all subfootnotes have
%   been typeset.  The same id is recorded in \cmd{\FN@slave} at the
%   ultimate end of the footnote.
%
%   At the point where a \cmd{\FN@master} mark is placed, a default
%   \cmd{\FN@slave} mark is placed also with an id that is one less
%   than the smallest id generated from a footnote that is a
%   `descendent' of the current one.  This makes it possible to
%   distinguish any split off subordinate footnotes.  It must be noted
%   that this sentinel slave id will be the valid id of a completely
%   unrelated footnote!  Since the value is only used for determining
%   one end of an \emph{open} interval of excluded ids, this is no
%   problem.  All subordinate footnotes are numbered sequentially in
%   the order of \emph{completion}, so that any subordinate footnotes
%   have lower ids than their master.
%    \begin{macrocode}
\newcount\FN@id
\FN@id\@ne
\newmarks\FN@master
\newmarks\FN@slave
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \begin{macro}{\FN@errorstack}
%   This records the history of nested footnotes in order to deliver
%   more useful error messages.
%    \begin{macrocode}
\let\FN@errorstack\@empty
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@fnotecommon}
%   Well, this is the work horse if the footnote macro.  Really bad
%   thing.  We start off by stepping our absolute counter and making a
%   mark.  \cmd{\leavevmode} is required so that the action of
%   |perpage.sty| is done smoothly.
%    \begin{macrocode}
\def\FN@fnotecommon#1#2#3{%
  \leavevmode
  \stepcounter{FN@totalid}%
  \NCC@makemark{#3}%
%    \end{macrocode}
%   It is an error if the footnote insert number of the current
%   footnote does not correspond to a block below the current
%   insertion level.
%    \begin{macrocode}
  \ifnum#2<\FN@masterinsert
    \FN@colorstackbgroup\FN@divert
    \FN@newslot\FN@masterslot
    \count@\FN@id
%    \end{macrocode}
%   \cmd{\dimen@} is here set to a sorting criterion.  This is
%   designed to make the conversion of footnote blocks as reliable as
%   possible.  If we could guarantee convergence, just using
%   \cmd{\c@FN@totalid} would be sufficient for sorting.  It turns out
%   that this is too sensitive to footnotes of different blocks
%   changing pages, so the number of the superior footnote block is
%   allowed to take precedence by multiplying it with 4194304 which is
%   unlikely to get exceeded by \cmd{\c@FN@totalid}.
%    \begin{macrocode}
    \dimen@=\dimexpr64\p@*\FN@masterinsert-\c@FN@totalid sp\relax
    \def\FN@masterinsert{#2}%
    \edef\FN@errorstack{\FN@errorstack^^J%
\FN@masterinsert\space entered in line \number\inputlineno}%
    \let\FN@boxtype=#1%
    \setbox\z@#1\bgroup
%    \end{macrocode}
%   The following is for the likes of PDF\TeX\ which has its own idea
%   about how to restore a color stack.
%    \begin{macrocode}
      \let\current@color\default@color
      \FN@@color@begingroup
      \let\MFL@minipage\relax
      \let\MFL@endminipage\relax
      \@makefnstartbox
%    \end{macrocode}
%   We reset the list parameters in footnotes.  Strictly speaking,
%   this is interfering with \LaTeX's standard operation, but the
%   standard operation does not make sense.
%    \begin{macrocode}
      \let\@listdepth\@mplistdepth \@mplistdepth\z@
      \@itemdepth\z@ \@enumdepth\z@
      \protected@edef\@currentlabel{\csname p@footnote%
         \expandafter\FN@stripfootins\string#2\endcsname\@thefnmark}%
      \ifx\FN@boxtype\vbox \normalcolor\nobreak
      \else \FN@specific{#2}\@preparefnhtext \normalcolor
      \fi
%    \end{macrocode}
%   Ok, now we do the call to \cmd{\@makefntext} which may occur in
%   one of several ways, depending on whether the `robust' or the
%   `fragile' package option got used.
%    \begin{macrocode}
      \expandafter \FN@makefncall
  \else
%    \end{macrocode}
%   We still needed to cater for the error of badly anchored footnotes:
%    \begin{macrocode}
    \PackageError{bigfoot}{#2 forbidden in \FN@masterinsert.}%
    {Higher-placed footnotes can't be anchored in inferior ones.^^J%
    I am not putting this text in a footnote.  History:%
\FN@errorstack}%
    \rule{1em}{\ht\strutbox}%
\fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@makefnstart}
% This is called in the start of \cmd{\@makefntext}.
%    \begin{macrocode}
\providecommand{\FN@seitenobreak}{\nobreak}
\def\FN@makefnstart{%
%    \end{macrocode}
%   Record the footnote specific dimensions.  It is assumed that they
%   don't change in the document, at least not before the footnote
%   gets actually placed.
%    \begin{macrocode}
  \expandafter\xdef\csname FN@ht\number\FN@masterinsert\endcsname
    {\the\footnotesep}%
  \expandafter\xdef\csname FN@dp\number\FN@masterinsert\endcsname
    {\the\dp\strutbox}%
  \expandafter\xdef\csname FN@wd\number\FN@masterinsert\endcsname
    {\the\hsize}%
%    \end{macrocode}
%   The footnote gets markers for identifying it and its starting block.
%    \begin{macrocode}
  \marks\FN@master{\FN@masterslot}%
  \marks\FN@slave{\number\FN@id}%
  \nobreak
%    \end{macrocode}
% \cmd{\FN@commonending} will intervene before any tokens that are
% shifted in due to switching back the color stack.  Those will only
% be executed once we completely relinquish control.
%    \begin{macrocode}
  \ifx\FN@boxtype\vbox
    \rule\z@\footnotesep
  \else
    \ifx\FN@par\par\else
      \let\FN@@par\par
      \let\FN@@noindent\noindent
      \let\FN@@indent\indent
    \fi
     \everyvbox\expandafter{\expandafter\everyvbox
       \expandafter{\the\everyvbox}%
       \let\par\FN@@par
       \let\noindent\FN@@noindent
       \let\indent\FN@@indent
       \the\everyvbox}%
     \let\par\FN@par
     \let\noindent\FN@noindent
     \let\indent\FN@indent
  \fi
  \FN@seitenobreak
  \afterassignment\ignorespaces}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@makefnrobust}
%   After preparation, we now do the big bad trick for making
%   footnotes cooperate with \cmd{\verb} and other catcode changing
%   things: we call \cmd{\@makefntext} with an argument of
%   |\iffalse|.  This kills off its expansion right at the point
%   where it would choose to place its argument.
%
%   Furthermore, this swallows the opening brace of the footnote text
%   and then lets the footnote text progress.  The closing group will
%   then trigger the processing via \cmd{\aftergroup}.
%    \begin{macrocode}
\def\FN@makefnrobust#{%
  \FN@specific\FN@masterinsert\@makefntext
  \iffalse\fi
  \bgroup
    \aftergroup\FN@robustending
    \FN@makefnstart
    \let\next}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@robustending}
%   Here we put in the missing part of \cmd{\@makefntext}.
%    \begin{macrocode}
\def\FN@robustending{%
  \expandafter\expandafter\expandafter
  \expandafter\expandafter\expandafter\expandafter
  \iffalse  \FN@specific\FN@masterinsert\@makefntext\fi
  \FN@commonending}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@makefnfragile}
%   This is the escape route when the robust variant does not work.
%   In that case, |\verb| and similar won't work in footnotes.
%    \begin{macrocode}
\long\def\FN@makefnfragile#1{%
  \FN@specific\FN@masterinsert\@makefntext
  {\FN@makefnstart#1\FN@commonending}}
%    \end{macrocode}
%
% \end{macro}
%
% Ok, color handling is a nuisance, to say the least.  Split
% footnotes need to close their color stack on the old page, and reopen
% it on the new one.  So we record the color stack state at each time
% it changes in a marks register.
%    \begin{macrocode}
\newmarks\FN@color
\def\FN@colorstackbgroup{\let\FN@savecolorstack\FN@colorstack
  \global\let\FN@colorstack\@empty
  \bgroup
  \ifdefined\FN@savecolorstack\else
    \let\FN@@set@color\set@color
    \let\FN@@reset@color\reset@color
    \let\FN@@color@begingroup\color@begingroup
  \fi
  \let\set@color\FN@set@color
  \let\reset@color\FN@reset@color
  \let\color@begingroup\FN@color@begingroup}

\def\FN@colorstackegroup{\egroup
  \global\let\FN@colorstack\FN@savecolorstack}

\def\FN@colorstackfinish{\def\@elt##1##2{\FN@@reset@color##2}%
  \FN@colorstack
  \def\@elt##1##2{\noexpand\@elt{}{##2}}%
  \xdef\FN@colorstack{\FN@colorstack}%
  \let\@elt\relax
  \marks\FN@color{}}

\def\FN@reset@color{%
  \bgroup\def\@elt##1##2{\def\FN@next{##1}{\gdef\FN@colorstack{##2}}}%
    \let\FN@next\@empty
    \FN@colorstack
    \ifx\FN@next\@empty
      \FN@colorstackegroup
    \else \egroup
      \FN@@reset@color
      \marks\FN@color{\FN@colorstack}%
  \fi}

\def\FN@color@begingroup{%
  \let\reset@color\FN@@reset@color
  \let\color@begingroup\FN@@color@begingroup
  \let\set@color\FN@@set@color
  \color@begingroup}

\def\FN@set@color{\FN@@set@color
  \xdef\FN@colorstack{\@elt{\current@color}{\FN@colorstack}}%
  \marks\FN@color{\FN@colorstack}}

\def\FN@coloraftersplit#1{%
  \def\@elt##1##2{##2\def\current@color{##1}\set@color}%
  #1%
  \let\@elt\relax}
%    \end{macrocode}
% \begin{macro}{\FN@commonending}
%   We'll eventually arrive here at the end of the footnote.  Now we
%   again call \cmd{\@makefntext}, but this time pass it |\fi| as
%   its argument, and place |\iffalse| before its expansion.  This
%   cuts away the start of the macro.  If this start changes the tail
%   of the macro when executed, the whole trickery will not work.  It
%   turns out that a large sampling of document classes (including the
%   standard ones) happens to work.
%    \begin{macrocode}
\def\FN@commonending{%
  \@makefnendbox
  \ifx\FN@boxtype\vbox\@finalstrut\strutbox \else \unskip \fi
  \FN@colorstackfinish
  \color@endgroup
  \egroup
  \global\advance\FN@id\@ne
  \FN@slotxdef\FN@masterslot{\number\FN@id}%
%    \end{macrocode}
%   Now we want to get an upper estimate of the size.  In case of a
%   horizontal box, we do this by creating a vertical box of it all
%   alone, and measuring that.  Measuring the hbox itself is plain
%   out: \TeX's maximal dimension of something like 5\,m is already
%   busted with about two pages of material.  We put the master slot
%   identification into the depth of the box, and arrange for the
%   total of depth and height of the box to still give the total depth
%   and height of its size on the page.
%    \begin{macrocode}
  \ifhbox\z@
    \global\setbox\FN@tempbox\copy\z@
    \setbox\tw@\@makefnvbox{\unhbox\FN@tempbox}%
    \ht\z@\dimexpr\ht\tw@+\dp\tw@-\FN@masterslot sp\relax
  \else
    \ht\z@\dimexpr\ht\z@+\dp\z@-\FN@masterslot sp\relax
  \fi
%    \end{macrocode}
%   Now we put the sorting criterion into the width of the box, and
%   then put the masterslot id into the depth.
%    \begin{macrocode}
  \wd\z@\dimen@
  \dp\z@\FN@masterslot sp\relax
%<trace>      \ifnum\z@<0\FN@slotget{\FN@masterslot} %
%<trace>      \else \errmessage{Inconsistent
%<trace>        \string\FN@masterslot=\FN@masterslot}\fi
%    \end{macrocode}
%   Now we just need to place the stuff into an insertion and record
%   the possibly changed slave id in order to know what subordinate
%   footnotes belong to this one.
%    \begin{macrocode}
  \MFL@insert\FN@masterinsert{\nointerlineskip\box\z@}%
  \ifdim\lastkern=\z@ \let\FN@next\@empty\else
    \edef\FN@next{\kern\the\lastkern\relax}\unkern
  \fi
  \marks\FN@slave{\number\FN@id}%
  \expandafter\FN@enddivert\expandafter\FN@colorstackegroup
  \FN@next
}
%    \end{macrocode}
% \end{macro}
% A lot of stuff follows.  This should really be cleaned up and
%   documented.
%    \begin{macrocode}
\dimen\footins\maxdimen
\gdef\FN@nestlist{}

\newdimen\FN@outervsize
\newskip\FN@vsize

\newbox\FN@insertions

%<trace>\def\MFL@showone#1#2{\message{Box #2:}\showbox#2%
%<trace>  \MFL@checkconsistency{#2}%
%<trace>  \message{Cachebox #2:}\showbox\FN@cache#2}
%<trace>
%<trace>\def\MFL@checkconsistency#1{{%
%<trace>  \setbox\z@\vbox{\unvcopy#1%
%<trace>    \MFL@checkconsistencyi{#1}}}}
%    \end{macrocode}
% \begin{macro}{\MFL@checksinglebox}
%   Check box~|#1| for consistency.  If it is bad, output box~|#2|.
%   Execute |#3| if it was good, |#4| if it was bad.
%    \begin{macrocode}
%<trace>\def\MFL@checksinglebox#1#2#3#4{%
%<trace>    \ifvoid#1\else
%<trace>      \ifnum\z@<0\FN@slotget{\number\dp#1} %
%<trace>        #3%
%<trace>      \else \errmessage{Inconsistent box #2}%
%<trace>         \showboxdepth4\showboxbreadth100
%<trace>         \showbox#2\relax
%<trace>         #4%
%<trace>      \fi\fi}
%    \end{macrocode}
% \end{macro}
%    \begin{macrocode}
%<trace>\def\MFL@checkconsistencyi#1{%
%<trace>    \unpenalty\unskip\unkern
%<trace>    \setbox\z@\lastbox
%<trace>    \MFL@checksinglebox\z@{#1}{{\MFL@checkconsistencyi{#1}}}{}}
%<trace>
%<trace>\def\MFL@showall{{%
%<trace>    \showboxbreadth=\maxdimen
%<trace>    \showboxdepth=4
%<trace>    \tracingonline=\@ne
%<trace>    \FN@nest@iterate\MFL@showone}}
%    \end{macrocode}
% \begin{macro}{\FN@retaindelayed}
%   This is a complex macro that removes all boxes from the current
%   list that are not to be kept for the next page.  It works on the
%   material from the original insertions, not the cache boxes.
%   The slot specified by \cmd{\count@} is not freed when encountered,
%   all others are freed upon removing the box.  The last box is
%   returned in box~0 if any is retained.  The vertical list might
%   have an unchecked part locked off in front by placing a
%   \cmd{\nobreak} penalty there.  This penalty is removed, and the
%   list before it not touched.
%    \begin{macrocode}
\def\FN@retaindelayed{%
  \setbox\z@\lastbox
  \ifcase
    \ifvoid\z@\m@ne\fi \FN@config\z@
%<trace>  \if\foottrace8\message{^^J\string\FN@retaindelayed:
%<trace>     dropping Id \FN@slotget{\number\dp\z@}}\fi
%<trace>  \if\foottrace{16}{\showboxdepth4 \showboxbreadth400
%<trace>     \tracingonline=\@ne\showbox\z@}\fi
    \ifnum\dp\z@=\count@\else \FN@freeslot{\number\dp\z@}\fi
%<trace> \ifnum\dp\z@<\@ne \errmessage{Unidentified box}\fi
    \expandafter\FN@retaindelayed
  \or
%<trace> \if\foottrace8\message{^^J\string\FN@retaindelayed:
%<trace>    retaining Id \FN@slotget{\number\dp\z@}}\fi
%<trace>  \if\foottrace{16}{\showboxdepth4 \showboxbreadth400
%<trace>     \tracingonline=\@ne\showbox\z@}\fi
    {\FN@retaindelayed \nointerlineskip \box\z@}%
  \else \unpenalty \setbox\z@\lastbox
%<trace>  \ifnum\lastnodetype>\m@ne
%<trace>    \errmessage{Unexpected node \number\lastnodetype}\fi
%<trace>  \ifvoid\z@ \else
%<trace>     \if\foottrace8\message{^^J\string\FN@retaindelayed:
%<trace>        carrying split box \FN@slotget{\number\dp\z@}}\fi
%<trace>     \if\foottrace{16}{\showboxdepth4 \showboxbreadth400
%<trace>        \tracingonline=\@ne\showbox\z@}\fi\fi
  \fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\MFL@processplain}
%   This gets called for actually inserting the processed material
%   into the footnote box.  The current state of affairs is that
%   \cmd{\FN@config} contains all footnotes that should get
%   transferred to the next page completely.  The cache boxes contain
%   the collected and typeset footnotes for typesetting on the current
%   page.
%
%   The structure of a cachebox is currently as follows: it is filled
%   with vboxes containing the arranged material, optionally followed
%   by another box to be carried over to the next page flagged with a
%   \cmd{\nobreak} penalty.
%    \begin{macrocode}
\def\MFL@processplain#1{%
%<trace> \MFL@checkconsistency#1%
   \ifvoid\FN@cache#1%
%    \end{macrocode}
% Now if the cache box is void, nothing gets typeset on the current
% page.  What we do, however, is to collect all boxes from the
% original insertion that did not make it on this page and reinsert
% them.  \cmd{\count@} is cleared to zero to retain nothing special.
%    \begin{macrocode}
     \global\setbox\FN@tempbox\vbox\bgroup
       \unvbox#1%
       \count@\z@
       \let\@elt\FN@removecheck \FN@retaindelayed
       \ifvoid\z@ \egroup
       \else \nointerlineskip \box\z@ \egroup
         \MFL@realinsert{#1}{\unvbox\FN@tempbox}%
       \fi
%    \end{macrocode}
% The following stops in the insertion process within the |manyfoot|
% package.
%    \begin{macrocode}
     \expandafter\expandafter
   \fi\iffalse\fi
%    \end{macrocode}
% Ok, this is the case when we have a nonvoid cache box.
%    \begin{macrocode}
   \global\setbox#1\vbox\bgroup%
     \unvbox\FN@cache#1%
     \ifnum\lastpenalty>\z@
       \unpenalty
       \setbox\z@\lastbox
     \else
       \setbox\z@\box\voidb@x
     \fi
%    \end{macrocode}
% Ok, now box zero contains carryover material (if any).  We
% initialize \cmd{\count@} to this so that we will keep this carryover
% material just once.
%    \begin{macrocode}
     \count@\dp\z@
     \global\setbox\FN@tempbox\vbox\bgroup
       \box\z@
       \nobreak
       \unvbox#1%
       \let\@elt\FN@removecheck \FN@retaindelayed
       \ifvoid\z@ \egroup \MFL@removevboxes\egroup
       \else \nointerlineskip \box\z@ \egroup
         \MFL@removevboxes \egroup
         \MFL@realinsert{#1}{\unvbox\FN@tempbox}%
       \fi}

\let\MFL@processpara\MFL@processplain
%    \end{macrocode}
% \end{macro}
% Ok, here is the bit about the caches: whenever we encounter a new
% configuration, we have to first update the caches since we don't
% know the sizes we are dealing with regarding the new configuration
% until we do so.  The caches are kept up to date globally.  When we
% are working at several levels in the recursion, we have a bottom
% active level where we may are looking for a way to find a best break
% and configuration.  We will return at most one configuration once we
% are finished.  While we are working with a returned configuration,
% adding more material on the current list will not require another
% recursion as long as the totals stay underfull: the penalty
% difference between underfull configurations becomes smaller while
% the underfullness decreases, which means that smaller breaks that
% have not been chosen before might become eligible if the penalties
% allow for that.  Only when the badness of underfullness remains
% infinite can't we have any improvement.
%
% Ok, after we recurse for removing an underfull condition, the
% resulting configuration can't actually be used further for breaks
% with less remaining space.  It is, however, clear that if less space
% remains, there is no better break with the same configuration
% leaving \emph{more} space: if there were, it would already have been
% taken.  That means that our goal height for the next break will be
% chosen in order to reach the exact size met on the last recursion.
% No break before that can be chosen on the next try, but a break
% after it might then be taken.
%
% available, or an overfull one.  If a deeper level at any point of
% time returns an overfull configuration, we are finished.  The best
% configuration to be returned is the least underfull.  If there is
% none, the least overfull.  The case of no underfull at all can only
% happen if even splitting this and every subordinate level to minimal
% height and recursing does not yield an underfull.  At every level,
% we need to maintain just a current split, and the previous best
% split at most.
%
% When we change a configuration on recursing, we have to remember the
% configurations for the previous best split.  We can manage that by
% sweeping the current cache values into a local box register
% before recursing with a different configuration: we have to rebuild
% the box registers for a different configuration, anyway.  We don't
% save the configuration from an overfull setting: when we rework the
% list in slow motion mode, we can't help stopping the recursion by
% reaching an overfull setting that is at least as good as the
% initial one.
%
% When we return to a caller, we leave the cache in the configuration
% of the best choice up to now: either we are returning an overfull
% configuration and if it is not the best so far, the caller can
% restore his better choice from his copy, or we are returning an
% underfull configuration in which case the caller might still want to
% improve upon it before returning to its caller in turn.  New: If we
% return an underfull configuration, we also return an ``optimal
% penalty estimate'' that gives the best break point penalty under the
% assumption that additional stretchability is present on the page.
%
% The purpose of this is to offer the possibility of avoiding widows
% and similar by moving more material in some footnotes to the next
% page in exchange for other material.
%
% At the current grouping level we empty out our current cache and
% keep it for working purposes on the vertical list until we return
% (nobody references it while we are working on it).  We always enter
% with an overfull configuration, meaning that \cmd{\FN@vsize} is
% negative.  It is calculated with the current cache\slash config
% setting.
%
% There is a danger of overflow involved with that: if we keep a swept
% complete configuration at each level of recursion, we need $O(n^2)$
% of space here.  The alternative would be to keep the history of how
% the configuration came about.  Since that might involve some
% slow-motion splitting, this is also a speed issue.  Since deep
% recursion with pending best data at each level is not really
% likely, and since we are not going to have that many footnote
% levels to go around, anyway, we just rely on \LaTeX\ having been
% started with sufficient memory.
%
% A workable compromise would be to just store the split boxes
% from a configuration together with the configuration data for
% reconstructing the rest.  After all, we don't need to reconsider
% such a configuration before actually typesetting anything.  And
% whenever we find an acceptable fit (neither underfull\slash
% overfull), we could cut through all the hierarchy without having to
% restore anything.  This has not been implemented yet: at the moment
% we go for the less complicated variation.
%
%
% The algorithm we use here is a bit complicated.  Whenever we
% recurse, we have one of the following situations:
% \begin{enumerate}
% \item An overfull/underfull dilemma: including a minimal amount of
%       material at the current level will cause the page to become
%       overfull.  This can be the case in connection with zero (in
%       case of interline penalties for larger blocks), one or more
%       subordinate footnotes and related footnotes.
% \item A pure overfull dilemma: the page was overfull to start with,
%       we need to reduce it.
% \item an underfull dilemma: some operation in the next level made
%       the page become underfull, only too much so.  We can't make it
%       fuller on the current level, but we can make it even emptier,
%       and let the next level fill it up again.
% \end{enumerate}
%
% In the current implementation, we just ignore the slight probability
% that the optimum choice might lie with case~3.  We don't
% recurse for making the page fuller again.  If we have an
% overfull/underfull dilemma, the recursion will either give us a
% less awful overfull box, or an underfull one.  An overfull box that
% occurs at the highest level of recursion can't be improved on any
% lower level.  So we never need to locally return an overfull box: we
% can compare it to the best overfull box seen before, and if we turn
% out better than that, we overwrite the global best overfull value
% and return the best local underfull if there is such a one.  The
% best local underfull will then be refilled as much as possible on
% the next level without changing the configuration.  Actually, if we
% need to change the configuration, this would also be fine as long as
% we arrive at a better underfull eventually.  But since a change of
% configuration renders our previous split completely useless, as the
% broken paragraph could look disastrously different under a changed
% configuration, we would need to recurse again.  We repeat this
% recursing operation until we don't get an underfull solution
% returned anymore.  We then return the best underfull, if any.  The
% best overfull is stored globally, as mention before.
%
% Does this sound complicated?  Unfortunately, it does.  It also
% sounds somewhat slow.  For that reason, we do a few assumptions that
% will facilitate a good average-case behavior.  The first assumption
% is that we will usually do fine by just splitting in the current
% level (if at all) and not at all in subordinate levels.
%
% We do this assumption on the first pass used for gathering the size
% information and collect the corresponding boxes in nested lists.
% When the recursion tops out, it does so either with an overfull
% page, or an underfull page.  If it does with an underfull page, we
% cache the current configuration for the next pass through the output
% routine, so that we won't need to retypeset and measure assembled
% boxes that have not gathered any new material.  If we top out with an
% overfull page, the previous underfull configuration is still worth
% keeping as well, as it might become the material actually chosen to
% be typeset.
%
% Ok, the current best configuration of the next recursion level is
% gathered on the current vertical list, in a separate box.  We use
% box~2 for this purpose.  A saved configuration consists of the
% complete contents for the current cache box without the trailing
% penalty indicating material from a single split box carried over to
% the next page (boxes that are carried over completely to the next
% page are not maintained here but rather reinserted by
% \cmd{\MFL@processnested}).  This penalty is added in case the box
% is actually disassembled and returned: there is no possibility for
% confusion since we only save such a configuration if indeed there is
% a split present.
%    \begin{macrocode}
\newtoks\FN@output
\FN@output\output

\newbox\FN@tempbox
\newinsert\FN@savebox
\count\FN@savebox\@m
\dimen\FN@savebox\maxdimen
\skip\FN@savebox\z@skip
\global\setbox\FN@savebox\box\voidb@x

\expandafter\expandafter\expandafter\let\FN@cache\FN@savebox=\@cclv

\expandafter\def\csname FN@ht\number\FN@savebox\endcsname{\z@skip}%
\expandafter\def\csname FN@dp\number\FN@savebox\endcsname{\maxdepth}
\expandafter\def\csname FN@wd\number\FN@savebox\endcsname{\columnwidth}

\def\FN@list{\MFL@list\@elt{}\footins}

\def\FN@sweepbox#1#2{\ifvoid#2\else
  \nointerlineskip\box#2\penalty#2\fi}

\def\FN@sweepcachebox#1#2{\nointerlineskip
  \box\FN@cache#2%
  \penalty\FN@cache#2}

\def\FN@copycachebox#1#2{\nointerlineskip
  \copy\FN@cache#2%
  \penalty\FN@cache#2}

\def\FN@restoreboxes{\count@\lastpenalty \unpenalty
  \ifnum\count@>\z@
    \global\setbox\count@\lastbox
    \expandafter\FN@restoreboxes
  \fi}
%    \end{macrocode}
% \begin{macro}{\FN@removecheck}
%   This returns |\@ne| if and only if the current slot master is strictly
%   inside of the specified open interval.  In this case it is not to
%   appear on the current page.
%    \begin{macrocode}
\def\FN@removecheck#1#2{%
  \ifnum#1<\FN@slotget{\number\dp\z@} %
  \ifnum#2>\FN@slotget{\number\dp\z@} %
    \@ne\fi\fi}
%    \end{macrocode}
% \end{macro}
% Parameter recording merely records the relevant value of the
% skip register and sets it to zero.  The purpose is to avoid changes
% of the reserved page space when we collect additional material from
% a page where an insertion of the appropriate kind had already been
% encountered.  This is used for filling up underfull pages.
%    \begin{macrocode}
\def\FN@recordinsertparam#1#2{\ifvoid#2\else
  \global\skip\number#2=\the\skip#2\relax\fi}

\def\FN@clearinsertparam#1#2{\ifvoid#2\else
  \global\skip#2=\z@skip\fi}
%    \end{macrocode}
% \cmd{\FN@insertouterspace} will sum the size of the inserts manually.
%    \begin{macrocode}
\def\FN@insertouterspace#1#2{\ifvoid#2\else
    +\skip#2+(\ht#2+\dp#2)*\count#2/\@m\fi}

\def\FN@list@iterate#1{\let\FN@eltsave\@elt
  \let\@elt#1%
  \FN@list
  \let\@elt\FN@eltsave}

\def\FN@nest@iterate#1{\let\FN@eltsave\@elt
  \let\@elt#1%
  \FN@nestlist
  \let\@elt\FN@eltsave}
%    \end{macrocode}
%
% \subsection{The output routine stuff}
%
% \paragraph{Marks}
% This is used for sweeping all marks up for reinsertion.
% \begin{macro}{\FN@allmarks}
%    \begin{macrocode}
\def\FN@allmarks#1{\@elt{#1}%
  \ifnum#1<\count266
    \expandafter\FN@allmarks\expandafter{\number\numexpr#1+\@ne}%
  \fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@sweeptopmarks}
% \begin{macro}{\FN@topmarkbox}
%   This sweeps the current topmarks and places them into the global box
%   \cmd{\FN@topmarkbox}.
%    \begin{macrocode}
\def\FN@sweeptopmarks{\global\setbox\FN@topmarkbox\vbox{%
    \def\@elt##1{\marks##1{\unexpanded\expandafter{\topmarks##1}}}%
    \FN@allmarks0}}
\newbox\FN@topmarkbox
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \begin{macro}{\FN@establishmarks}
%   This sets marks from a marks sweep.  The first argument is the
%   mark number, the second is from the first mark on the first scan,
%   the third argument from the bottom mark on the first scan, and the
%   fourth argument from the bottom mark on the second scan (with
%   additional mark entries).  If second and third arguments don't
%   match, no mark gets placed.
%    \begin{macrocode}
\long\def\FN@establishmarks#1#2{\edef\reserved@a{\unexpanded{#2}}%
  \edef\reserved@b{\unexpanded\expandafter{\splitbotmarks#1}}%
  \ifx\reserved@a\reserved@b
    \marks#1{\unexpanded\expandafter{\splitfirstmarks#1}}%
    \marks#1{\unexpanded\expandafter{\reserved@b}}%
  \fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@markspassone}
%   This constitutes the first pass for mark collection.  We do this
%   just to check whether there are any marks in the list.
%    \begin{macrocode}
\def\FN@markspassone#1{\noexpand\FN@establishmarks{#1}%
  {\unexpanded\expandafter{\splitbotmarks#1}}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@insertmarks}
%   This routine transfers first and bottom marks from the current
%   |\box255| to the vertical list in order to get the marks right.
%   This is quite a bother, since we must detect the special case
%   where there are no marks at all in the list, and since we might
%   require the use of several \cmd{\vsplit} commands in a row, since
%   infinite stretch might make the optimal breakpoint lie before the
%   end of the box in spite of its large size.
%
%   So we need to do the splitting in a loop, and do it twice, once
%   with artificial marks at the start.  If those artificial marks
%   make it to \cmd{\splitbotmarks}, we don't place any actual marks.
%    \begin{macrocode}
\def\FN@pseudomarks#1{\marks#1{X}}
\def\FN@insertmarks{%
  {\setbox\z@\copy\@cclv
    \splittopskip-\maxdimen\relax
    \vbadness=\@M
    \vfuzz=\maxdimen
    \loop
    \ifvoid\z@\else
      {\let\@elt\FN@pseudomarks
        \setbox\z@\vbox{\FN@allmarks0\nobreak\unvcopy\z@}%
        \setbox\z@\vsplit\z@ to\maxdimen}%
      \let\@elt\FN@markspassone
      \edef\next{\FN@allmarks0}%
      \setbox\z@\vbox{\nobreak\unvbox\z@}%
      {\setbox\z@\vsplit\z@ to\maxdimen}%
      \next
    \repeat}}
%    \end{macrocode}
% \end{macro}
% \paragraph{Some stuff}
%
% \begin{macro}{\FootnoteMainMinimum}
%   This specifies the minimum amount of main text.  You can make this
%   a complicated expression if you want to, for example by checking
%   the presence of particular footnotes.
%    \begin{macrocode}
\def\FootnoteMinimum{1sp}
\def\FootnoteMainMinimum{0pt}
\expandafter\def\csname\string\FootnoteMinimum\number\FN@savebox
\endcsname{\FootnoteMainMinimum}
%    \end{macrocode}
% \end{macro}
%
%\paragraph{The output routine itself}
%
% This is our own output routine that does all the balancing stuff.
% If we receive a forced penalty here, we must not do any of our
% output processing on our own unless this is the choice of the
% underlying output routine.  We do want to have the `real' output
% routine to have a correct idea about the size that the insertions
% will take up.  So the steps that we \emph{will} actually perform in
% any case are sorting the insertions and calculating their real
% size.  If we have not had a forced penalty, we are free to exit the
% output routine for gathering further material as there are no
% expections of the underlying output routine when it should get
% called.  If we encountered a forced penalty, things are getting more
% complicated.  If the current page happens to be overfull after
% adding the current material, we first need to ship out the material
% for a regular page (after splitting off the necessary material for
% the next page).  We then reinsert the remaining split insertions,
% any possibly split off page material and the penalty.
%
% \TeX\ is rather monotonous in its page break processing.  Increase
% the available page size, and the available page material will also
% increase.  There is a singular exception to that rule, and that are
% split and floating insertions.  However, we notice their presence by
% a non-zero setting of \cmd{\insertpenalties}, and we can just
% measure the material that they have taken up in a forced pass of the
% output routine, adding that much to our request size.  However, this
% operation will change the penalties associated with the page breaks.
%
% Unfortunately, this is not sufficient: the penalty might have been
% inserted with a box immediately preceding it.  In that case the
% penalty would have been guaranteed to eventually turn up in the
% output routine.  If we now reinsert merely all of the above stuff,
% the penalty will just disappear.  If we protect the penalty by
% placing an empty box before it when none of it had been before it
% before, we will get an empty page.  Since we don't know whether the
% penalty was supposed to disappear at the start of an empty page or
% not, we will do the following: if the rest of |\box255| is nonvoid,
% we just reinsert the split insertions followed by the rest of
% \box255 and the penalty and return.  If it is void, we call the
% regular output routine, capturing its output in a |\vbox| of its
% own.  If the regular output routine failed to ship out the prepared
% insertions, we just keep the original data either in their boxes or
% in a reinserted insertion.
%
% It hides the relevant information from the `real' output routine
% until such a time that we have enough material gathered to produce a
% full page.  The exception to this is when we have a special penalty
% that gets passed through to the regular output routine.
%
% If we are on a material collecting spree, \cmd{\FN@savebox} contains
% all boxes from the last output call time.  At the point where we
% enter the output routine, \cmd{\FN@vsize} contains the amount of
% space available for mounting footnotes, after subtracting all
% insertions of footnote variety.  At most times in our output
% routine, the variable will contain the amount of space left after
% everything is put to the page including footnotes.
%    \begin{macrocode}
\savingvdiscards=\@ne
%    \end{macrocode}
% We have the following situations that can cause us to enter the
% output routine:
% \begin{enumerate}
% \item The page has just filled up.
% \item A magic output penalty has been encountered.
% \item We are filling up a previously underfull page.
% \item We are looking for missing insertions that may have floated.
% \end{enumerate}
%
% We are trying to do bookkeeping on the effects of page size for
% insertions that fall into the footnote class.  While we do basic
% bookkeeping for other insertions as well, this can only be
% incomplete since we don't reinsert material.  In consequence,
% multiple material ending up in the same insertion might cause the
% corresponding skip register to be accounted for several times.
% \LaTeX\ does not really reuse insertions in that manner except for
% footnotes, so we are mostly ok here.
%
% |bigfoot| usually does some lookahead in the main list in order to
% obtain optimal breakpoints.  It explicitly undoes the effect this
% has on marks, but insertions are a different matter here.  So floats
% may appear on an earlier page than expected.
%
% If the output routine is invoked with a penalty of $-13750$, then
% the page content is merely used for setting the \cmd{\topmarks}
% array.  In that case, we just clear out the output box and resume.
% We don't fiddle with \cmd{\deadcycles} in order to catch foulups.
%
% Also we don't touch insertion boxes.  There is a particular
% situation where there \emph{are} insertions, namely if we are
% collecting insertions after the last output routine has ended up
% with a non-zero value of \cmd{\insertpenalties}.  In this case, all
% insertions we \emph{do} get are floating insertions, meaning that
% they had a preceding insertion of the same class already on the last
% page, and thus we have zeroed its skip register already.  We are
% assuming that a single pass with such a large \cmd{\vsize} is
% sufficient for pulling all insertions.  If that happens to be
% incorrect, insertions need to get pulled in piecewise, but then we
% are probably in big dodo with regard to page size accounting,
% anyway.
%    \begin{macrocode}
\newcount\FN@outputflag
\FN@outputflag=3158345
\output{%
  \let\@elt\relax
  \ifvoid\@cclv \PackageError{bigfoot}{Empty box 255 in \output}\fi
%<trace> \if\foottrace8%
%<trace>   \message{entering output with
%<trace>      \outputpenalty=\the\outputpenalty:}%
%<trace>   {\showboxdepth4\showboxbreadth\maxdimen\showbox\@cclv}\fi
  \ifnum\outputpenalty=-13750
%<trace>  \if\foottrace8%
%<trace>    \message{Discarding box 255.}%
%<trace>  \fi
    \ifnum\insertpenalties>\z@
      \PackageError{bigfoot}{Too much insertion material}{%
        This error means that the output routine was not able to^^J%
        gather all floating insertions in a single pass.^^J%
        Complain to the author if you consider this a bug}%
    \fi
    \global\advance\FN@outervsize\dimexpr\ht\@cclv-\vsize
    \global\setbox\@cclv\box\voidb@x
  \else
%    \end{macrocode}
% Note that a potential \cmd{\FN@vsadjustlist} will restore the
% previous value of \cmd{\outputpenalty}.  So we need to save it.
%    \begin{macrocode}
  \edef\FN@outputpenalty{\number\outputpenalty}%
  \ifvoid\FN@savebox
    \ifvoid\@holdpg
      \FN@sweeptopmarks
    \fi
    \FN@nest@iterate{\FN@insertouterspace\global\FN@outervsize
      \dimexpr\z@}%
    \global\advance\FN@outervsize\ht\@cclv
    \global\setbox\@cclv\vbox{\unvbox\@cclv\boxmaxdepth\maxdepth}%
    \global\let\FN@vsadjustlist\@empty
%    \end{macrocode}
% \cmd{\FN@outervsize} now contains the value of \cmd{\pagegoal} at
% the time of output.  It should be \cmd{\vsize} adjusted by the
% natural size of insertions.  Note that \cmd{\FN@normaloutput} is not
% required to return with a sensible value of \cmd{\outputpenalty}.
%    \begin{macrocode}
    \FN@normaloutput
  \else
%    \end{macrocode}
% We now are in the situation that we already have collected material
% previously.  We can't be sure that adding a special penalty does not
% take more than one output routine call before delivery.  For that
% reason, we don't rely on special outputs being special and always
% subtract any additionally demanded \cmd{\vspace} from
% \cmd{\FN@outervsize} before calling a special output, so that we can
% afterwards compensate for it.
%    \begin{macrocode}
    \FN@nest@iterate{\FN@insertouterspace\global\advance\FN@outervsize
      \dimexpr\ht\@cclv}%
    \global\setbox\@cclv\vbox{\unvbox\@cclv\boxmaxdepth\maxdepth}%
%    \end{macrocode}
% Now we invalidate the cache boxes for all insertions that had
% changed due to the recent additions to the page (this does
% \emph{not} affect \cmd{\FN@vsize}).
%    \begin{macrocode}
    \FN@nest@iterate\FN@maybeinvalidatecache
%    \end{macrocode}
% We now update all boxes by inserting the previously collected
% material in front of the boxes.
%    \begin{macrocode}
    \vskip\z@skip
    \unvbox\FN@savebox
    \loop
      \count@\lastpenalty
    \ifnum\count@>\z@
      \unpenalty
      \setbox\z@\lastbox
      \global\setbox\count@\vbox{\unvbox\z@\unvbox\count@}%
    \repeat
    \ifcase
      \ifnum\FN@outputpenalty=-13749 \@ne\fi
      \ifnum\FN@outputpenalty=-13751 \@ne\fi \tw@
    \or
%    \end{macrocode}
% \cmd{\outputpenalty} is restored to the original value before the
% total page is glued together.
%    \begin{macrocode}
      \FN@vsadjustlist
%<trace> \if\foottrace8\message{receiving special penalty
%<trace>    \FN@outputpenalty, dissing box 255:}%
%<trace>      {\showboxdepth4 \showboxbreadth400
%<trace>       \tracingonline=\@ne\showbox\@cclv}\fi
%    \end{macrocode}
% This special penalty means that we have been collecting floated
% insertions right now.  So |\box255| is actually empty except for
% filler material.  We restore the old box into it.
%    \begin{macrocode}
      \global\setbox\@cclv\lastbox
      \unskip
%<trace>  \ifnum\lastnodetype>\m@ne
%<trace>    \errmessage{Unexpected node \number\lastnodetype}\fi
      \ifnum\FN@outputpenalty=-13749
        \FN@normaloutput
      \else
        \the\FN@output
        \@pageht-\vsize
        \let\@currbox\footins
        \@reinserts
        \global\vsize-\@pageht
      \fi
    \else
      \dimen@\topskip
      \FN@vsadjustlist
      \setbox\z@\lastbox
      \unskip
%<trace>  \ifnum\lastnodetype>\m@ne
%<trace>    \errmessage{Unexpected node \number\lastnodetype}\fi
%    \end{macrocode}
% Ok, now we reconstruct the box from its parts.  We add the material
% together, taking the previous output penalty and the current page
% discards (if it belongs between those boxes, otherwise we leave it
% on the list) for glueing the stuff together.  The previous output
% penalty then is irrelevant for further purposes and we replace it
% again.  \cmd{\FN@outervsize} has been
% adjusted by the accumulated contributions of insertions to the page
% size.  Fiddling with it would not appear necessary or even prudent.
%    \begin{macrocode}
%<trace>\if\foottrace8
%<trace>   \message{Box 255 before reglue
%<trace>     (outputpenalty=\the\outputpenalty):}%
%<trace>   {\showboxdepth4\showboxbreadth100\showbox\@cclv}\fi
      \global\setbox\@cclv\vbox{%
%    \end{macrocode}
% Now we might have had a \cmd{\topskip} value designed for requesting
% a given number of lines.  We need to remove anything of that kind.
% Splitting again achieves that.  If the current page was empty except
% for insertions, this means that we gain a new breakpoint.  But
% insertions with discardable material before them would be unusual.
%
% The only exception to this may happen if the current page contained
% only insertions: in this case \TeX\ has made a page break before the
% actually inserted \cmd{\topskip} glue (which will then arrive one
% page later).
%
% Note that the pagediscards contain material corresponding to the
% last breakpoint chosen, so they will either start with a penalty
% of~10000 (which is what an actual outputpenalty gets replaced with)
% or will start with discardable material.  We clean it for that
% reason.
%    \begin{macrocode}
        \unvbox\z@
        \global\setbox\@cclv\vbox{\break\unvbox\@cclv}%
        {\splittopskip-\maxdimen \setbox\z@\vsplit\@cclv to\z@}%
        \ifnum\outputpenalty=\@M
          \setbox\z@\vbox{\pagediscards
            \FN@cleanpagepenalty}%
          \unvbox\z@
        \else
          \penalty\outputpenalty
          \pagediscards
        \fi
        \unvbox\@cclv
        \boxmaxdepth\maxdepth}%
%<trace>\if\foottrace8
%<trace>   \message{Box 255 reglued (outputpenalty=\FN@outputpenalty):}%
%<trace>   {\showboxdepth4\showboxbreadth100\showbox\@cclv}\fi
      \global\outputpenalty\FN@outputpenalty\relax
%    \end{macrocode}
% Ok, now if \cmd{\topskip} is actually \emph{positive}, we have been
% collecting material tentatively without having proper marks.  We
% then need to fill in the marks into the list and try again.  Note
% that we are not reinserting anything in order to compensate for
% \cmd{\outputpenalty} being replaced by a nobreak: this is the job of
% \cmd{\FN@normaloutput} when it decides to place material back on the
% page.  That is: when code is written that will make use of
% pagediscards, it has to cater for their proper structure.
%    \begin{macrocode}
      \ifdim\dimen@>\z@
%<trace>  \if\foottrace8
%<trace>    \message{recycling special penalty}
%<trace>  \fi
        \hrule\@height\z@\@depth\z@
        \unvcopy\FN@topmarkbox
        \penalty-13750
        \penalty\FN@outputflag
        \hrule\@height\z@\@depth\z@
        \FN@insertmarks
        \penalty-13749
        \penalty\FN@outputflag
        \FN@prepareoutput
        \global\topskip-\maxdimen
        \global\vsize0.5\maxdimen
        \global\advance\FN@outervsize-\vsize
      \else
        \FN@normaloutput
      \fi
   \fi
  \fi
  \fi}
%    \end{macrocode}
% \begin{macro}{\FN@normaloutput}
%   This is the normal output routine we use.
%   Now we have recovered a sensible state and glued everything together
%   that has been necessary.  All insertion parameters are at their
%   standard values, and any insertions have been collected in the
%   respective boxes.
%    \begin{macrocode}
\def\FN@normaloutput{%
%<trace> \if\foottrace8\message{^^JEntering \string\FN@normaloutput:^^J}\fi
%    \end{macrocode}
% \cmd{\FN@vsize} is now being set to the vertical size taken up by
% the insertions, according to \TeX.  Note that this does not include
% flexibility.  This much amount of space gets available on the
% current page if we remove all insertions.  This figures into
% \cmd{\FN@vsize} as a \emph{positive} quantity since the insertion
% size was taken from \cmd{\pagegoal}, and we reconstitute it in this
% manner.
%    \begin{macrocode}
  \global\FN@vsize\FN@outervsize
  \global\advance\FN@vsize-\ht\@cclv\relax\relax
%    \end{macrocode}
% Now we sort the inserts and regenerate the cache.
%    \begin{macrocode}
  \FN@nest@iterate\FN@sortinsert
  \FN@nest@iterate\FN@clearcache
  \xdef\FN@config{\@elt{\number0\botmarks\FN@slave}%
    {\number\maxdimen}}%
%<trace> \if\foottrace8%
%<trace>    \message{\noexpand\FN@normaloutput start config: \FN@config^^J}%
%<trace> \fi
  \FN@nest@iterate\FN@reconfig
%    \end{macrocode}
% Note that \cmd{\FN@reconfig} subtracts the \emph{actual} size of all
% insertions (after paragraphs have been combined and too early
% insertions moved to the next page) and also subtracts the flexible
% glues associated with the insertions' skip registers, so this
% flexibility is typically negative.  Since the cache registers have
% been explicitly cleared, \cmd{\FN@reconfig} starts from the state
% where indeed no insertions are present.
%    \begin{macrocode}
  \ifcase
    \ifnum\insertpenalties>\z@ \@ne\fi
%    \end{macrocode}
% If we have floating insertions, we need to catch up with them.  This
% is done in case~1 which just places an immediate penalty and
% recurses.
%
% Now here are a few cases that are only checked when we don't have a
% special penalty:
%    \begin{macrocode}
    \ifnum\outputpenalty>-\@M
%    \end{macrocode}
% The first case is if the page is underfull.  We need more material then.
%    \begin{macrocode}
      \ifdim\FN@vsize>-\gluestretch\FN@vsize \tw@ \fi
%    \end{macrocode}
% Second case is when there is not enough vertical minimum material.
%    \begin{macrocode}
      \ifdim\FootnoteMainMinimum>\ht\@cclv \tw@ \fi
    \fi
%    \end{macrocode}
% Case 3 means page is overfull.  If there are no missing insertions,
% try to split.
%    \begin{macrocode}
    \ifdim\FN@vsize<\glueshrink\FN@vsize \thr@@ \fi
%    \end{macrocode}
% page has appropriate size or we have special penalty.  If we have
% come here not the first time, we might have arrived at a non-optimal
% break.  So we attempt a split.
%    \begin{macrocode}
    \ifx\FN@vsadjustlist\@empty \else \thr@@\fi\z@
%    \end{macrocode}
% Ok, now we get the default case in our big routine: case~0.  We just
% pass the result onto the output routine.
%    \begin{macrocode}
    {\vbadness\@M
      \vfuzz\maxdimen
      \global\setbox\@cclv\vbox
      spread\FN@vsize{\unvbox\@cclv\boxmaxdepth\maxdepth}}%
    \the\FN@output
    \let\@currbox\footins
    \@pageht-\vsize
    \@reinserts
    \global\vsize-\@pageht
    \FN@nest@iterate\FN@clearcache
  \or
%    \end{macrocode}
% Case 1: We just pull in remaining insertions and are done.  Note
% that the special penalty here will get turned into an explicit
% nobreak.  So if we have no record of an actual outputpenalty, we
% need to insert an artificial penalty of 0 here.
%    \begin{macrocode}
    \FN@restartoutput
    \penalty -13749
    \penalty \FN@outputflag
  \or
%    \end{macrocode}
% Case 2: Now we want to gather additional material.  This is somewhat
% weird.  We first gather our material with a `normal' setting of
% topskip, and then we'll have another go at the material using proper
% marks.  We can't actually insert anything right now in order not to
% introduce a premature breakpoint.
%    \begin{macrocode}
    \dimen@=\dimexpr\FN@vsize-\glueshrink\FN@vsize\relax
    \FN@prepareoutput
    \global\topskip \normalbaselineskip
    \global\vsize \dimen@
    \global\advance\FN@outervsize-\vsize
    \global\deadcycles\z@
  \else
%    \end{macrocode}
% This is case 3: Fake our output box into something looking like a
% cache box and do the optimal split routine.  The output cache box
% has a few deficiencies: its inner box is \emph{not} depth-extended
% to some default measurement.  That means that where page size
% calculations are involved, one needs to \emph{disregard} its actual
% depth and instead use \cmd{\maxdepth}.  This is somewhat awkward and
% prone to problems.  One alternative might be to mark the box as
% split, extend its depth in the split part and let it be followed by
% nothing as lower part of the split.  But we still would need to
% account for the missing depth at the end.
%    \begin{macrocode}
    \edef\FN@masterid{\number\maxdimen}%
    \def\FN@masterslot{-1}%
    \global\setbox\@cclv\vbox{\box\@cclv}%
    \xdef\FN@config{\noexpand\@elt{\number0\botmarks\FN@slave}%
      {\number\maxdimen}}%
%<trace> \ifvoid\FN@savebox \else \PackageError{bigfoot}{\FN@savebox
%<trace>   \space should be void!}{}\fi
    \global\setbox\FN@savebox\vbox{}%
    \gdef\FN@penalties{0}%
    \edef\FN@defaultpenalty{\ifnum\outputpenalty<\@M
        \number\outputpenalty
      \else
        0\fi}%
    \let\@elt\FN@newlevel
    \@elt{}\FN@savebox\FN@nestlist\FN@mainsplitreturn
    \let\@elt\relax
%<trace> \if\foottrace8{\showboxdepth4\showboxbreadth100\showbox\@cclv}\fi
    \global\setbox\FN@savebox\box\voidb@x
    {%
      \vbadness\@M
      \vfuzz\maxdimen
      \global\setbox\@cclv\vbox spread\FN@vsize{%
        \unvbox\@cclv
        \ifnum\lastpenalty>\z@
          \unpenalty
          \global\setbox\FN@tempbox\lastbox
        \else
          \global\setbox\FN@tempbox\box\voidb@x
        \fi
        \setbox\z@\lastbox
%    \end{macrocode}
% Now if a split has been done, |\box\FN@tempbox| contains the lower
% part of the split.  In either case, |\box\z@| contains the upper
% part of the split (in a prepared form with the splitdiscards in a
% box of their own).  This may be void if there is no main text but
% only footnotes.  If we have carryover material, we add the current
% outputpenalty there and set outputpenalty to a value indicating that
% we have no outputpenalty to add at the end of the current list.
%    \begin{macrocode}
        \ifvoid\z@
          \ifvbox\FN@tempbox
            \ifnum\outputpenalty<\@M
% The output penalty originally from below the split box gets appended
% to the end of the split box.
              \global\setbox\FN@tempbox{\unvbox\FN@tempbox
                \penalty\outputpenalty}%
            \fi
            \global\outputpenalty=\@M
          \fi
        \else
%    \end{macrocode}
% Ok, we have material to go to the next page.  We unpack it and fish
% out the break penalty from the last box.  After checking it, put it in
% box~0.  A prospective current break penalty gets appended to the
% carryover material.  The fished-out break penalty becomes the new
% value of outputpenalty.
%    \begin{macrocode}
          \MFL@removevboxes
          \unvbox\z@
          \edef\FN@defaultpenalty{\number\@M}%
          \FN@getbreakpenalty
          \setbox\z@\lastbox
          \global\setbox\FN@tempbox\vbox\bgroup\unvbox\z@
            \unvbox\FN@tempbox
            \ifnum\lastnodetype<\z@
            \egroup\global\setbox\FN@tempbox\box\voidb@x
            \else
              \ifnum\outputpenalty<\@M
                \penalty\outputpenalty
              \fi
            \egroup
            \global\outputpenalty\FN@breakpenalty
          \fi
        \fi
        \boxmaxdepth\maxdepth}%
    }%
    \setbox\z@\box\FN@tempbox
    \let\@elt\relax
%    \end{macrocode}
% Ok, now we have in box~255 the split off stuff for the current
% output routine, and in box~0 stuff that is going to follow
% afterwards.  If box~0 is not void, we were not able to make use of
% all of box~255.  There is a slight probability that by taking even
% \emph{more} material from the main list, we might get a better
% result (by being able to move footnote material to the next page
% instead), but we don't make use of this possibility here.  In
% general, we assume that if box~0 is nonvoid, we take the resulting
% split.  Otherwise, if the page appears underfull, we pull in more
% material.  If the page is not underfull, we can pass it to the
% output routine.  If box~0 is void, the break was chosen at the
% ultimate end of the vertical list.  If it was not a forced break,
% and if it is not an overfull case already, we pull in more material
% in order to avoid widows in the main text.
%    \begin{macrocode}
    \dimen@=\dimexpr\FN@vsize-\glueshrink\FN@vsize\relax
    \ifcase
      \ifvoid\z@ \ifnum\outputpenalty>-\@M
                    \ifdim\dimen@<\z@ \else \@ne \fi
                 \fi
      \else \thr@@
      \fi
      \ifdim\ht\@cclv<\normalbaselineskip \@ne\fi
      \ifdim\dimen@<\normalbaselineskip \tw@\fi \@ne
    \or
      \FN@prepareoutput
      \global\topskip \normalbaselineskip
      \ifdim\dimen@<\normalbaselineskip \dimen@=2\baselineskip\fi
      \global\vsize \dimen@
      \global\advance\FN@outervsize-\vsize
      \global\deadcycles\z@
    \or
%<trace> \if\foottrace8%
%<trace>   \message{^^JOutput: config is \FN@config...}\fi
      \setbox\tw@\vbox{%
        \the\FN@output
%<trace> \if\foottrace8%
%<trace>   \ifnum\lastnodetype=\m@ne
%<trace>     \message{^^JOutput: end without carryover^^J}%
%<trace>   \else
%<trace>     \message{^^JOutput: end with carryover}}%
%<trace>      {\showboxdepth5 \showboxbreadth400
%<trace>      \tracingonline=\@ne\showbox\tw@
%<trace>   \fi
%<trace> \fi
      }%
      \unvbox\tw@
      \unvbox\z@
      \let\@currbox\footins
      \@pageht-\vsize
      \@reinserts
      \global\vsize-\@pageht
      \FN@nest@iterate\FN@clearcache
    \or
      \FN@restartoutput
      \penalty -13751
      \penalty\FN@outputflag
      \unvbox\z@
      \ifnum\outputpenalty>\@M
      \else \penalty
            \ifnum\outputpenalty=\@M \z@ \else\outputpenalty\fi
      \fi
    \fi
  \fi
%<trace> \if\foottrace8\message{^^JExiting \string\FN@normaloutput^^J}\fi
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@prepareoutput}
%   This is a preparation for gathering more material.  First sweep up
%   all the information about \cmd{\vsize}, \cmd{\topskip} and
%   \cmd{\outputpenalty}.  After that, record the insertion skip
%   parameter of all insertions that have already been started, and
%   reset them to zero so that no additional space gets reserved for
%   them in case more material accumulates.  We don't reset
%   \cmd{\topskip} here since the amount of newly requested material
%   will typically be in total lines, and \cmd{\topskip} might be the
%   only way to figure out the proper request size.  If the current
%   depth and following height would make for a non-standard line
%   distance, we might have a problem here.  There is no obvious way
%   to avoid it, though.
%    \begin{macrocode}
\def\FN@prepareoutput{%
  {\let\@elt\FN@recordinsertparam
   \xdef\FN@vsadjustlist{%
     \global\vsize=\the\vsize
     \global\topskip=\the\topskip
     \global\outputpenalty=\the\outputpenalty\relax
     \FN@list}%
   \let\@elt\FN@clearinsertparam
   \FN@list}%
%    \end{macrocode}
%   Now we collect all boxes in the save box.
%    \begin{macrocode}
%<trace> \ifvoid\FN@savebox \else \PackageError{bigfoot}{\FN@savebox
%<trace>   \space should be void in \string\FN@prepareoutput}{}\fi
  \global\setbox\FN@savebox\vbox{%
    \box\@cclv
    \FN@list@iterate\FN@sweepbox}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@restartoutput}
%   This is for the case where we are requesting additional material
%   and have to cater for sizes.
%    \begin{macrocode}
\def\FN@restartoutput{%
%    \end{macrocode}
% Calculate the remaining size on this page:
%    \begin{macrocode}
  \dimen@=\dimexpr\FN@vsize-\glueshrink\FN@vsize\relax
%    \end{macrocode}
% We just pull in remaining insertions and are done.
%    \begin{macrocode}
%<trace> \if\foottrace8\message{sending special penalty}\fi
  \hrule\@height\z@\@depth\z@
  \unvcopy\FN@topmarkbox
  \penalty -13750
  \penalty\FN@outputflag
  \hrule\@height\z@\@depth\z@
  \FN@insertmarks
  \FN@prepareoutput
  \global\topskip-\maxdimen\relax
  \global\vsize 0.5\maxdimen
  \global\advance\FN@outervsize-\vsize
  \global\deadcycles\z@
}
%    \end{macrocode}
% \end{macro}
%
% Ok, here is the deal.  If the \cmd\FN@truevsize is negative, we have
% an overfull vbox at our hand.  We then start the splitting action.
% We take the first non-split lowest footnote block and split it to
% size, removing subordinate footnotes that we would not be able to
% maintain.  We do this recursively starting by the top footnote
% block.  It must be noted that it would be even better to start with
% the highest-numbered footnote (which corresponds to the latest
% finished footnote in \emph{logical} order, that in the source code),
% but then we get the problem that we might have to remove boxes from
% a footnote block that has already been split, and that is
% troublesome (to put it mildly) in case where the footnote block is
% set in paragraph mode.  It's bad enough backtracking in a fixed
% order across footnote blocks, going back and forward would be pretty
% tough.
%
% So our recursion just walks the footnote blocks once top to bottom,
% splitting and removing boxes that are not needed.  When we recurse,
% we have a dichotomy between current overfull and underfull boxes.
% At each recursion level, we enter with an overfull configuration
% that establishes the breakable section for the footnote block in
% question.
%
% Suppose that we have already established a previous best
% configuration.  When we are recursing, we can only increase the
% badness (a non-broken insertion box contributes nothing to the
% overall badness or penalties, breaking the box causes a badness of
% 10000, minus the break penalty, plus the break badness).  So there
% is no point in recursing if entry badness and break penalty are as
% large as the previous best break penalty or more.
%
% Ok, so we construct the footnote block and try splitting it
% to size.  If this
% gives us a \emph{good} underfull version, we return that (and break
% out of recursion altogether).  Otherwise we remember the underfull
% version before the break and recurse on the overfull version.  If
% this returns an overfull version again, we return the underfull
% version before the break.  If it returns an underfull version, we
% fill up the underfull version as much as possible without a change
% of configuration, then select the best of the last underfull and
% this as new local underfull.  We then take the first overfull
% combination (even allowing a change of configuration), throw away
% the previous split in the next recursion level and recurse on the
% now thoroughly overfull combination again.
%
% When recursion tops out, we compare the current overfull with the
% previous one and record the best.  We prefer keeping an older
% overfull, all other things being equal.
%
% Ok, so what are the data structures we maintain when going through
% all this folderol?
%
% We let the insertion boxes themselves remain untouched: that makes
% it only a bit more complicated to maintain and access the relevant
% boxes, but it might come handy at one time when somebody wants to
% implement recursion that is not strictly top-to-bottom.
%
% Instead we return the relevant information in the cache boxes.  The
% total size of the cache boxes may not correspond to their actual
% contents: in case a split box intended for the next page is stored
% within them, its height is deducted from the total height of the
% cache box (and, consequentially, from \cmd{\FN@vsize}).
%
% \cmd{\FN@vsize}, the amount of free space on the current page, is
% only updated when changing levels of recursion.  Instead we maintain
% score of the accumulated size in the current insertion in
% \cmd{\FN@myvsize}.
%
% What about the penalties and badness we collect?  An unsplit
% footnote block carries a penalty of~0 (so we need not take into
% account unsplit footnote blocks at all during our bookkeeping, as
% they are neutral), a split footnote block is prepenalized with a
% penalty of~10000, plus the badness of the split, plus any penalties
% associated with the split (limited to the $[-10000\ldots10000]$
% range).  This means that no operation on other footnote blocks can
% lower an already accumulated score.  This in turn means that we can
% prune any operations leading to a worse score than the preceding
% best score without having to actually recurse.
%
% This strategy will usually buy us a minimum number of split
% footnotes (since the penalty of~10000 is not easy to compensate)
% and corresponds rather closely to \TeX's own idea of footnote
% splitting.
%
% The following routine will analyze the last box where the results
% from \cmd{\splitdiscards} are stored and return the penalty
% associated with the breakpoint in the macro
% \cmd{\FN@breakpenalty}.
% \begin{macro}{\FN@getbreakpenalty}
%    \begin{macrocode}
\def\FN@getbreakpenalty{{\setbox\z@\lastbox
    \nointerlineskip\copy\z@
    \setbox\z@
      \vbox{\unvbox\z@
        \count@\@M
        \FN@getbreakpenaltyii
        \xdef\FN@tempinfo{\edef\noexpand\FN@breakpenalty{%
            \number\ifnum\count@=\@M \FN@defaultpenalty \else \count@\fi
          }}}}%
  \FN@tempinfo}

\def\FN@getbreakpenaltyii{%
  \ifcase
    \ifnum\lastnodetype<\z@ \m@ne\fi
    \ifnum\lastnodetype<11 \@ne\fi
    \ifnum\lastnodetype>13 \@ne\fi
    \numexpr\lastnodetype-9\relax
  \or
    \PackageError{bigfoot}{Illegal node type}{This can't happen}%
  \or
    \count@\z@ \unskip \expandafter\FN@getbreakpenaltyii
  \or
    \count@\z@ \unkern \expandafter\FN@getbreakpenaltyii
  \or
    \count@\lastpenalty
    \unpenalty \expandafter\FN@getbreakpenaltyii
  \fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@cleanpagepenalty}
%   This is used for removing initial infinite penalties from the
%   pagediscards: those are artifacts of the page break routine.
%    \begin{macrocode}
\def\FN@cleanpagepenalty{%
  \ifcase
    \ifnum\lastnodetype<\z@ \m@ne\fi
    \ifnum\lastnodetype<11 \@ne\fi
    \ifnum\lastnodetype>13 \@ne\fi
    \numexpr\lastnodetype-9\relax
  \or
    \PackageError{bigfoot}{Illegal node type}{This can't happen}%
  \or
    \skip@=\lastskip \unskip
    \expandafter \FN@cleanpagepenalty \expandafter\vskip\the
    \expandafter\skip@
  \or
    \dimen@=\lastkern \unkern
    \expandafter \FN@cleanpagepenalty \expandafter\kern\the
    \expandafter\dimen@
  \or
    \count@\lastpenalty \unpenalty
    \ifnum\count@=\FN@outputflag
      \unpenalty\expandafter\expandafter\expandafter\FN@cleanpagepenalty
    \else
      \expandafter\FN@cleanpagepenalty\expandafter
      \penalty\the\expandafter\expandafter\expandafter\count@
    \fi
  \fi
  \relax}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@mainsplitreturn}
%   This is merely an argument delimiting control sequence to make it
%   possible to figure out which recursion levels still need visiting.
%    \begin{macrocode}
\def\FN@mainsplitreturn{}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@myvsize}
%   This is the size currently taken by this insertion.
%    \begin{macrocode}
\newdimen\FN@myvsize
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\bigfoottolerance}
%   This specifies what footnote arrangement penalty will be accepted
%   without looking for a better solution.
%    \begin{macrocode}
\newcount\bigfoottolerance
\bigfoottolerance=100
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@getbadness}
%   This takes a skip value of remaining space and negative
%   stretchability and shrinkability, and then calculates
%   \cmd{\badness} depending on how good the stretching accommodates
%   the remaining space.
%    \begin{macrocode}
\def\FN@getbadness#1{%
  {\hfuzz\maxdimen\hbadness\@M\setbox\z@\hbox to\z@{\hskip-#1}}}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@newlevel}
%   This is the main workhorse of |bigfoot|.  It splits a particular
%   footnote level, recursing if necessary.  The level list is
%   delimited with \cmd{\FN@mainsplitreturn}.  The whole thing is
%   looped through while the splits are being optimized.  While
%   recursing, \cmd{\FN@penalties} contains the accumulated penalities
%   of the current split configuration: a penalty of $10000$ for any
%   split (except the main list), plus the penalty at the split points
%   plus a `hangover' badness for the percentage of material carried
%   over to the following pages.  If nothing is carried over, this
%   is~0, if more is carried over, we get a penalty according to the
%   proportion of carryover material, raised to the third power.
% \begin{macro}{\footnotecarryratio}
%   The fractional variable \cmd{\footnotecarryratio} is used for
%   scaling the leftover material dimensions.  After scaling with
%   \cmd{\footnotecarryratio}, the carried material is treated like
%   missing material in a glue calculation, while the stretchability
%   for this calculation is given by the total size of material before
%   breaking.  So with a setting of~1, there should always be enough
%   stretchability, causing at most a penalty of~100.  That's not very
%   effective, so we scale this up.
%
%   The default value of~2 seems to provide a reasonable penalty for
%   leftover material.  The actual purpose for this component of the
%   scoring is to penalize footnote blocks that seem to carry over
%   disproportionally much material to later pages.
%    \begin{macrocode}
\providecommand\footnotecarryratio{2}
%    \end{macrocode}
% \end{macro}
%   \cmd{\FN@ebadness} is an augmented value, but also counting in the
%   stretch badness for one particular configuration.  Ebadness does
%   not make sense to evaluate more than temporarily: it is not passed
%   through the levels.  Since \cmd{\FN@penalties} is globally
%   tampered with, its value at entry is saved in
%   \cmd{\FN@entrypenalties}.  Whenever we recurse or return,
%   \cmd{\FN@vsize} contains the full information about the available
%   space on the page, even though locally we use \cmd{\FN@myvsize}, a
%   local value, to keep track of the locally reserved space.  The
%   only time when we need to save \cmd{\FN@myvsize} should be when we
%   temporarily leave boxes in order to save the current
%   configuration.
%    \begin{macrocode}
\def\FN@newlevel#1#2#3\FN@mainsplitreturn{%
  \count@\FN@cache#2%
  \ifvoid\count@
%<trace> \if\foottrace1\message{Page=\thepage #2 is empty, recursing with
%<trace>   \the\FN@vsize^^J}%
%<trace>   \message{Config=\unexpanded\expandafter{\FN@config}^^J}\fi
      #3\FN@mainsplitreturn
%<trace> \if\foottrace1%
%<trace>   \message{Page=\thepage #2 was empty,
%<trace>     returning with \the\FN@vsize^^J}%
%<trace>   \message{Config=\unexpanded\expandafter{\FN@config}^^J}\fi
  \else
%<trace> \if\foottrace1\message{Entering #2 with \FN@penalties,
%<trace>   \FN@vsize=\the\FN@vsize,^^J%
%<trace>   Config=\unexpanded\expandafter{\FN@config}^^J}\fi
    {\def\FN@currentinsertion{#2}%
     \def\FN@currentrecursion{#3}%
     \let\FN@entryconfig\FN@config
     \let\FN@entrypenalties\FN@penalties
     \splittopskip\csname FN@ht\number#2\endcsname\relax
     \splitmaxdepth\csname FN@dp\number#2\endcsname\relax
     \hsize\csname FN@wd\number#2\endcsname\relax
     \vbadness=\@M
     \vfuzz\maxdimen
     \let\@elt\relax
     \expandafter\FN@newleveli\expandafter}%
%<trace> \if\foottrace1\message{Exiting #2 with \FN@penalties,
%<trace>   \FN@vsize=\the\FN@vsize,^^J%
%<trace>   Config=\unexpanded\expandafter{\FN@config}^^J}\fi
  \fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@newleveli}
%    \begin{macrocode}
\def\FN@newleveli{%
%    \end{macrocode}
% \cmd{\FN@vsize} already includes the size of the complete unsplit
% insertion.  When we recurse, it has to reflect the correct size at
% the time of recursion.  Rounding error problems don't permit us to
% accumulate any sizes in \cmd{\FN@vsize} from processing our current
% insertion, so we just subtract the whole insertion-related
% content.  We'll add stuff into it when recursing.
%    \begin{macrocode}
    \dimen@\dimexpr\ht\count@
      \ifnum\FN@currentinsertion=\FN@savebox
        +\maxdepth
      \else
        +\dp\count@
      \fi\relax
    \global\advance\FN@vsize\dimexpr \dimen@
      *\count\FN@currentinsertion/\@m\relax\relax
%    \end{macrocode}
% Ok, now we are typesetting and collecting the best box.  Notice
% that we \emph{don't} exit this \cmd{\setbox} command until we have
% found the best possible split.  What we \cmd{\unvbox} here, stays
% dormant except for the last box.  When we collect configurations
% from cache boxes, we don't collect anything from our current box
% that is being assembled.  So the whole action is confined within the
% current list that will replace the cache box after splitting.  The
% meaning of boxes on the various levels are:\par\noindent
% \begin{tabularx}{\linewidth}{ll@{:\hskip\tabcolsep}X}
%   0&box0&where stuff gets collected as tentative material to be
%   unboxed with \cmd{\FN@removevboxes} once the insertion gets readied
%   for shipout\\
%   0&box2&the previous best split that was found\\\hline
%   1&box0&the material that gets worked off, the tail of the split\\
%   1&box2&where the current split is assigned
% \end{tabularx}
% The structure of 0/box2 is the head of the split, followed by
% |\break| penalty, followed by the tail of the split, followed by
% |\penalty\FN@tempbox|, followed by pairs of cache boxes and
% penalties indicating their box number.  That way, the tail can get
% restored immediately into |\FN@tempbox| when using
% |\FN@restoreboxes|.
%    \begin{macrocode}
    \global\setbox\count@\vbox\bgroup\unvbox\count@
%    \end{macrocode}
% We calculate \cmd{\FN@myvsize} as the total space taken up by this
% insertion.  The size of the last box is excluded since it will be
% split now.
%    \begin{macrocode}
      \ifnum\lastpenalty=\z@
        \setbox\tw@\box\voidb@x
        \setbox\z@\lastbox
        \FN@myvsize=\ifnum\lastnodetype<\z@
          \z@
        \else
          \dimexpr\dimen@-\ht\z@-\dp\z@\relax
        \fi
      \else
%    \end{macrocode}
% Now if the box has been split previously, we glue it back together
% again.  Since the lower part of the split has been \emph{subtracted}
% from the total in \cmd{\dimen@}, we need to put it back into the
% equation here.  \cmd{\dimen@} contains the size of the box after
% padding split material has been added.
%    \begin{macrocode}
%<trace> \if\foottrace1\message{Regluing box 2}\fi
        \unpenalty
        \setbox\tw@\lastbox
        \setbox\z@\lastbox
        \FN@myvsize=\dimexpr\dimen@-\ht\z@-\dp\z@\relax
        \dimen@\dp\z@
        \setbox\z@{\unvbox\z@
          \setbox\z@\lastbox
          \unvbox\z@
          \unvbox\tw@}%
        \ht\z@=\dimexpr\ht\z@+\dp\z@-\dimen@\relax
        \dp\z@\dimen@
      \fi
%    \end{macrocode}
% Ok, size is all accounted for.  Go on with optimization.  Note that
% these definitions here are made in \emph{inner} level, so they can't
% make it outside as the result of the optimization.  If we drop out
% of here without superceding them, something's completely rotten.
% ^^A Fixme: Alpha pruning could be implemented by calling with
% ^^A \FN@bestcost already set at entry to the best badness at
% ^^A the respective level.
%    \begin{macrocode}
      \edef\FN@bestcost{\number\maxdimen}%
      \let\FN@bestbadness\FN@bestcost
      \let\FN@bestconfig\@undefined
      \def\FN@bestvsize{-\maxdimen}%
      \let\FN@splitcolors\@empty
%    \end{macrocode}
% Ok, first attempt.  One interesting feature is that we will never
% have to rewind the boxes from a split: we can always just glue the
% box together again.  And apart from tentative splits which we might
% revert if they cause a configuration change, we will not have to
% bother about contributing too much.  What we put in the box here
% can stay.
%
% First we split to the remaining size.  Since we still have all
% subordinate footnotes considered fully, we need at least this split
% size (in case of a configuration change, we will need more).  After
% having done the initial split, we continue splitting until we get
% the necessary mark of the last footnote into our grasp: we can't
% split before that.
%    \begin{macrocode}
      \ifnum\FN@currentinsertion=\FN@savebox
      \else
        \edef\FN@defaultpenalty{\number-\@M}%
        \edef\FN@masterslot{\number\dp\z@}%
        \edef\FN@masterid{\FN@slotget\FN@masterslot}%
      \fi
%    \end{macrocode}
% Now we are building one tentative candidate for returning in
% |\box\z@|.  It will get discarded in case that a better candidate
% was already found before this box completes.
%    \begin{macrocode}
      \setbox\z@
      \vbox\bgroup
%    \end{macrocode}
% Ok, now stuff gets complicated: for the first, tentatively `optimal'
% split, we want to have all available page stretchability properly
% taken into account.  So we take the box, and add the available page
% stretchability at the top.  Note that the stretchability is
% registered negatively.  If we are on the main vertical list, an
% empty page can be an acceptable option, so we add a penalty of zero
% to account for that.  Note that any prospective true penalties will
% already have disappeared into the page break.
%    \begin{macrocode}
        \let\FN@splitcolors\@empty
        \setbox\z@\vbox{\vskip-\glueexpr(\FN@vsize-\dimexpr\FN@vsize
          \relax\@minus\glueshrink\FN@vsize)%
          *\@m/\count\FN@currentinsertion
          \penalty\z@
          \unvbox\z@
          \ifnum\FN@defaultpenalty>-\@M
            \penalty\FN@defaultpenalty\relax\nointerlineskip
            \vbox to\maxdimen{}%
          \fi}%
%    \end{macrocode}
% Ok, now we have pushed the additional available stretch onto the top
% of box~0.  Now we do the actual split to minimal size.  That means
% that we don't consider any of the shrinkability available on the
% page: it might still be better employed in some recursive level.
%    \begin{macrocode}
        \setbox\tw@\vsplit\z@ to%
          \dimexpr\FN@vsize*\@m/\count\FN@currentinsertion
          -\FN@myvsize-\splitmaxdepth
        \relax
        \ifnum\FN@defaultpenalty>-\@M
          \setbox\z@\vbox\bgroup\unvbox\z@\setbox\z@\lastbox
            \unskip
            \unpenalty
            \ifnum\lastnodetype<\z@
              \egroup \setbox\z@\box\voidb@x
            \else
              \egroup
            \fi
        \fi
%    \end{macrocode}
% Ok, now the top of box~2 contains unwanted additional
% stretchability.  The easiest way to get rid of it is by adding its
% negation.
%    \begin{macrocode}
        \setbox\tw@\vbox{%
          \vskip\glueexpr(\FN@vsize-\dimexpr\FN@vsize
          \relax\@minus\glueshrink\FN@vsize)%
          *\@m/\count\FN@currentinsertion
          \unvbox\tw@\boxmaxdepth\splitmaxdepth}%
%    \end{macrocode}
% Ok, now rinse and repeat if we haven't reached the last footnote
% in the block.
%    \begin{macrocode}
        \ifnum\FN@currentinsertion=\FN@savebox
          \edef\FN@slaveid{\splitbotmarks\FN@slave}%
          \FN@contribute@tw@
        \else
          \ifnum0\splitbotmarks\FN@master=\FN@masterslot \else
            \loop
              \FN@contribute@tw@
              \setbox\tw@\vsplit\z@ to\z@
            \ifnum0\splitbotmarks\FN@master=\FN@masterslot
            \else
            \repeat
          \fi
          \let\FN@splitcolors\@empty
          \edef\FN@slaveid{\splitbotmarks\FN@slave}%
          \FN@contribute@tw@
        \fi
%    \end{macrocode}
% All of the above was necessary to ensure that we actually have the
% beginning of the relevant footnote in our material.  From now on,
% we are dealing with legal splits.
% Ok, now we have to check whether the subordinate configuration has
% changed.
%    \begin{macrocode}
        \ifx\FN@slaveid\@empty
%<trace>  \ifnum\FN@currentinsertion=\FN@savebox\else
%<trace>    \errmessage{Missing slaveid in \FN@currentinsertion}\fi
          \edef\FN@slaveid{\number0\topmarks\FN@slave}%
        \fi
        \ifnum\numexpr\FN@slaveid+\@ne<\FN@masterid
          \let\FN@next\FN@slaveid
        \else
          \let\FN@next\@empty
        \fi
%    \end{macrocode}
% At this point of time, we have \cmd{\FN@masterid} set properly for
% our purposes.  It is to be used for returning any \emph{tail} part
% of a box.  \cmd{\FN@slaveid} is by necessity not empty.  If any
% footnote
% has had its mark broken off, its id must be in the open range
% between \cmd{\FN@slaveid} and \cmd{\FN@masterid}.  So a nonempty
% value of \cmd{\FN@next} at this point of time indicates that we have
% to cater for a different configuration rather than the currently
% cached one.
%    \begin{macrocode}
        \FN@splitfurther}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@vsizerecurse}
% This fixes the vertical size up and recurses once.
%    \begin{macrocode}
\def\FN@vsizerecurse{%
    \global\advance\FN@vsize
      -\dimexpr\FN@myvsize*\count\FN@currentinsertion/\@m \relax\relax
    \let\@elt\FN@newlevel
    \FN@currentrecursion\FN@mainsplitreturn
    \let\@elt\relax
    \global\advance\FN@vsize
      \dimexpr\FN@myvsize*\count\FN@currentinsertion/\@m \relax\relax}
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{Main label for reconsideration}
% When we are here, then there is not yet a split in the next footnote
% blocks scheduled.  We might have to restitch stuff together here,
% though.
% \begin{macro}{\FN@splitfurther}
%    \begin{macrocode}
\def\FN@splitfurther{%
  \ifx\FN@next\@empty \else \let \FN@slaveid\FN@next \fi
%    \end{macrocode}
% Ok, if our configuration now differs from the last one for which we
% have cache boxes set up, we have to reconfigure.  It it doesn't, we
% just stitch the boxes together again in order to have correct size
% info.
%    \begin{macrocode}
  \let\FN@next\FN@config
  \xdef\FN@config{%
    \@elt{\FN@slaveid}%
    {\FN@masterid}%
    \FN@entryconfig}%
  \ifx\FN@next\FN@config
    \let\@elt\FN@rejoin
  \else
    \let\@elt\FN@reconfig
  \fi
  \FN@currentrecursion
  \let\@elt\relax
%    \end{macrocode}
% Ok, now we check whether the current configuration is a match for
% the best previous one.  Also we calculate the badness of the current
% situation.
%    \begin{macrocode}
  \xdef\FN@penalties{\number\FN@entrypenalties}%
  \FN@checkcurrent
%    \end{macrocode}
% No point in recursing if we can't beat the current best one.
% However, if we find a forced break, this is considered perfect as
% long as we are not overfull.  Note that recursion can only increase
% the badness if we are still underfull here, so there is no point in
% using \cmd{\FN@penalties} as the deciding factor of whether there may
% be a point in recursing: the current ebadness (which is never less
% than the badness) already is minimal.
%    \begin{macrocode}
  \ifnum
    \ifdim\skip@>\z@ \FN@ebadness \else \FN@penalties \fi
    >\FN@bestcost\relax
%<trace>    \if\foottrace1%
%<trace>    \message{no recursion: \skip@=\the\skip@,
%<trace>      \noexpand\FN@bestvsize=\FN@bestvsize,
%<trace>      \noexpand\FN@ebadness=\FN@ebadness,
%<trace>      \noexpand\FN@penalties=\FN@penalties,
%<trace>      \noexpand\FN@bestcost=\FN@bestcost.}\fi
  \else
%<trace>    \if\foottrace1%
%<trace>    \message{before recursion: \skip@=\the\skip@,
%<trace>      \noexpand\FN@bestvsize=\FN@bestvsize,
%<trace>      \noexpand\FN@ebadness=\FN@ebadness,
%<trace>      \noexpand\FN@penalties=\FN@penalties,
%<trace>      \noexpand\FN@bestcost=\FN@bestcost.^^J
%<trace>      recurse with \noexpand\FN@penalties=\number\FN@entrypenalties.}\fi
    \xdef\FN@penalties{\number\FN@entrypenalties}%
    \FN@vsizerecurse
    \FN@checkcurrent
%<trace>    \if\foottrace1%
%<trace>    \message{after recursion: \skip@=\the\skip@,
%<trace>      \noexpand\FN@bestvsize=\FN@bestvsize,
%<trace>      \noexpand\FN@ebadness=\FN@ebadness,
%<trace>      \noexpand\FN@penalties=\FN@penalties,
%<trace>      \noexpand\FN@bestcost=\FN@bestcost.}\fi
  \fi
%    \end{macrocode}
% Don't look further if we had a forced break or are overfull or are
% at the end of the list.
%    \begin{macrocode}
  \ifcase
    \ifnum\FN@breakpenalty>-\@M \else \@ne \fi
    \ifvoid\z@ \@ne \fi
    \ifnum\badness<\@MM \else \@ne \fi
    \tw@
  \or
    \expandafter \FN@returnbest
  \else
    \FN@mayberecordbest
    \setbox\tw@\vsplit\z@ to\z@
    \edef\FN@next{\splitbotmarks\FN@slave}%
    \FN@contribute@tw@
    \expandafter \FN@splitfurther
  \fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@checkcurrent}
%   Check out the badness of the current configuration.  The last box
%   on the list is the material constituting the discardable material
%   after a split.
%    \begin{macrocode}
\def\FN@checkcurrent{%
  \FN@getbreakpenalty
  \ifnum\FN@breakpenalty<-\@M
    \edef\FN@breakpenalty{\number-\@M}%
  \fi
  \ifnum\FN@currentinsertion=\FN@savebox
  \else
    \ifdim\FN@specific\FN@currentinsertion\footnotecarryratio\p@>\z@
      \skip@
      \ifdim\FN@specific\FN@currentinsertion\footnotecarryratio\p@>\p@
          \dimexpr\ht\z@+\dp\z@\relax
          \@plus-\dimexpr((\FN@myvsize+\ht\z@+\dp\z@)
                          *\p@/\dimexpr
                          \FN@specific\FN@currentinsertion
                          \footnotecarryratio\p@)\relax
      \else
          \FN@specific\FN@currentinsertion
          \footnotecarryratio
          \dimexpr\ht\z@+\dp\z@\relax
          \@plus-\dimexpr\FN@myvsize+\ht\z@+\dp\z@\relax
      \fi
      \relax
      \FN@getbadness\skip@
      \xdef\FN@penalties{\number\numexpr\FN@penalties+\badness}%
    \fi
  \fi
  \skip@\glueexpr\FN@vsize-\FN@myvsize
   *\count\FN@currentinsertion/\@m\relax
  \FN@getbadness\skip@
  \xdef\FN@penalties{\number\numexpr\FN@penalties+%
    \FN@breakpenalty+\@M}%
  \ifnum\badness>\@M
    \edef\FN@ebadness{\number\numexpr\maxdimen-\@ne}%
  \else
    \ifnum\badness=\@M
      \ifdim\skip@<\vsize
        \edef\FN@ebadness{\number\numexpr\maxdimen-\tw@}%
      \else
        \edef\FN@ebadness{\number\numexpr\maxdimen}%
      \fi
    \else
      \edef\FN@ebadness{\number\numexpr
        \FN@penalties+\badness
        \ifdim\FN@specific\FN@currentinsertion\FootnoteMinimum>\FN@myvsize
          1000000
        \fi
        }%
    \fi
  \fi
  \dimen@\glueexpr\FN@bestvsize\relax
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@checkforbest}
%   This generates 2 if the old stored best is better, 1~if the
%   current variation is better.
%    \begin{macrocode}
\def\FN@checkforbest{%
    \ifnum\FN@breakpenalty>-\@M \else
      \ifnum\badness>\@M \else
         \@ne
      \fi
    \fi
%    \end{macrocode}
% Ok, so the split was not as good as to cause us to return
% immediately, and it also was not the last opportunity for a split
% (which again would make us return immediately).
% So we check if it is at least better than the last one, in which
% case we need to replace the previous best.
%    \begin{macrocode}
    \ifnum\FN@bestcost>\FN@ebadness \@ne\fi
    \ifnum\FN@bestcost<\FN@ebadness \tw@\fi
    \ifdim\skip@<\z@
      \ifdim\dimen@<\skip@ \@ne \fi \tw@
    \fi
    \ifdim\dimen@>\skip@ \@ne\fi \tw@}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@mayberecordbest}
%   This checks whether the current configuration is better than a
%   previously saved one.  If it is, the previous configuration gets
%   replaced.  The cache boxes itself are copied, not voided in the
%   process for efficiency reasons.
%    \begin{macrocode}
\def\FN@mayberecordbest{%
%    \end{macrocode}
% If the current break is forced and the page is not overfull, we take
% the break.
%    \begin{macrocode}
  \ifcase
    \FN@checkforbest
  \or
    \xdef\FN@tempinfo{\def\noexpand\FN@bestvsize{\the\skip@}%
      \def\noexpand\FN@bestcost{\FN@ebadness}%
      \def\noexpand\FN@bestbadness{\number\FN@penalties}%
      \def\noexpand\FN@bestconfig{\FN@config}%
      \def\noexpand\FN@bestslaveid{\FN@slaveid}%
      \def\noexpand\FN@bestsplitcolors{\FN@splitcolors}%
      \def\noexpand\FN@breakpenalty{\FN@breakpenalty}%
      \FN@myvsize=\the\FN@myvsize\relax}%
    \global\setbox\FN@tempbox\box\z@
    \egroup
    \FN@tempinfo
    \let\FN@splitcolors\FN@bestsplitcolors
    \let\FN@slaveid\FN@bestslaveid
%    \end{macrocode}
% Now all relevant info has been retrieved, and we collect the best
% box info in |\box\tw@|.  The structure of the information is as
% follows: it starts with the current box in split form, first the
% tail, then the start of the current split box.
% This is then followed by a zero kern, and then by pairs of boxes and
% penalties indicating the swept box.
%    \begin{macrocode}
    \setbox\tw@\vbox{%
%    \end{macrocode}
% We don't need to place master/slave marks here: the necessary
% information is available outside in the \cmd{\FN@masterslot} and
% \cmd{\FN@slaveid} info and gets attached afterwards.
%    \begin{macrocode}
      \copy\z@\break\nointerlineskip
      \copy\FN@tempbox\penalty\FN@tempbox
      \let\@elt\FN@copycachebox
      \FN@currentrecursion}%
    \setbox\z@
    \vbox\bgroup
      \unvbox\z@
      \setbox\z@\box\FN@tempbox
  \fi}
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\FN@returnbest}
%    \begin{macrocode}
\def\FN@returnbest{%
  \ifcase\FN@checkforbest
  \or
    \xdef\FN@tempinfo{\def\noexpand\FN@bestvsize{\the\skip@}%
      \def\noexpand\FN@bestcost{\FN@ebadness}%
      \def\noexpand\FN@bestbadness{\number\FN@penalties}%
      \def\noexpand\FN@bestconfig{\FN@config}%
      \def\noexpand\FN@bestslaveid{\FN@slaveid}%
      \def\noexpand\FN@bestsplitcolors{\FN@splitcolors}%
      \def\noexpand\FN@breakpenalty{\FN@breakpenalty}%
      \FN@myvsize=\the\FN@myvsize\relax}%
    \global\setbox\FN@tempbox\box\z@
    \egroup
    \FN@tempinfo
    \let\FN@splitcolors\FN@bestsplitcolors
    \let\FN@slaveid\FN@bestslaveid
    \global\FN@vsize\FN@bestvsize\relax
%    \end{macrocode}
% Now all relevant info has been retrieved, and we collect the best
% box info in |\box\tw@|.  The structure of the information is as
% follows: it starts with the current box in split form, first the
% tail, then the start of the current split box.
% This is then followed by a zero kern, and then by pairs of boxes and
% penalties indicating the swept box.
%    \begin{macrocode}
  \or
    \global\let\FN@config\FN@bestconfig
    \global\FN@vsize\FN@bestvsize
    \global\let\FN@penalties\FN@bestbadness
    \egroup
%    \end{macrocode}
% Restore the saved configuration.
%    \begin{macrocode}
    \setbox\z@\vbox{\unvbox\tw@ \FN@restoreboxes}%
    \let\FN@splitcolors\FN@bestsplitcolors
    \let\FN@slaveid\FN@bestslaveid
    \unvbox\z@
    \setbox\z@\lastbox
  \fi
%    \end{macrocode}
%    \begin{macrocode}
  \ifnum\FN@currentinsertion=\FN@savebox
  \else
    \setbox\z@\vbox{%
      \prevdepth\dp\z@
      \unvbox\z@
      \ifvoid\FN@tempbox
      \else
        \global\setbox\FN@tempbox\vbox{%
          \marks\FN@master{\FN@masterslot}%
          \marks\FN@slave{\FN@slaveid}%
          \FN@coloraftersplit\FN@splitcolors
          \FN@specific\FN@currentinsertion\FN@afterbreak
          \nobreak
          \unvbox\FN@tempbox}%
        \FN@specific\FN@currentinsertion\FN@beforebreak
        \ht\FN@tempbox
        \dimexpr\ht\FN@tempbox+\dp\FN@tempbox-\FN@masterslot sp\relax
        \dp\FN@tempbox\FN@masterslot sp\relax
        \wd\FN@tempbox\maxdimen
      \fi
    \ifdim\prevdepth<\splitmaxdepth
       \hrule\@height-\prevdepth \@width\z@
             \@depth \splitmaxdepth \relax \fi}%
    \ht\z@=\dimexpr\ht\z@+\dp\z@-\FN@masterslot sp\relax
    \dp\z@=\FN@masterslot sp
  \fi
  \nointerlineskip \box\z@
%    \end{macrocode}
% If nothing is to be carried over, we just finish our assignment to
% the cache box and return.
%    \begin{macrocode}
  \ifvoid\FN@tempbox \egroup
%    \end{macrocode}
% If not, we add the carried-over box to the list, flag it with a
% \cmd{\nobreak}, and subtract its size from the finished box.  Please
% note that the \cmd{\expandafter} chain will expand just
% |\cmd\dimen@|, but everything following it will be evaluated only
% after \cmd{\egroup}, thus using the new height of the box.
%    \begin{macrocode}
  \else
    \dimen@-\dimexpr\ht\FN@tempbox+\dp\FN@tempbox\relax
    \nointerlineskip\box\FN@tempbox
    \nobreak
    \expandafter\egroup
    \expandafter\ht\expandafter\count@\expandafter\dimexpr
    \the\dimen@+\ht\count@\relax
  \fi
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\FN@contribute@tw@}
%   This will go from the state where we have the previous
%   \cmd{\splitdiscards} struttified on the current list some material
%   split off from box~0 in box~2 to a state where box~2 is
%   contributed to the current list.
%    \begin{macrocode}
\def\FN@contribute@tw@{%
%    \end{macrocode}
% First we change the current colors if we have any in our group.  Not
% sure if this is entirely correct.
%    \begin{macrocode}
  \begingroup\edef\FN@next{\splitbotmarks\FN@color}%
  \ifx\FN@next\@empty \endgroup\else \endgroup
    \edef\FN@splitcolors{\splitbotmarks\FN@color}\fi
%    \end{macrocode}
% If the last box is void, there is no previous split to reconstitute.
%    \begin{macrocode}
  \setbox4\lastbox
  \ifvoid4 \setbox4\vbox{\splitdiscards}%
    \setbox\tw@\vbox{\unvbox\tw@\boxmaxdepth\splitmaxdepth}%
  \else
%    \end{macrocode}
% Now the last box is a strut.  We remove its outer dimensions from
% the total account, and then add back its natural dimensions after
% which we pour it back into the current list.
%    \begin{macrocode}
    \advance\FN@myvsize-\dimexpr\ht4+\dp4\relax
    \setbox4\vbox{\unvbox4}%
    \advance\FN@myvsize\dimexpr\ht4+\dp4\relax
    \unvbox4
%    \end{macrocode}
% We want to contribute box~2 back without any topskip glue, so we
% manually remove any such glue by splitting an empty box off.
%    \begin{macrocode}
    \setbox4\vbox{\splitdiscards}%
    \setbox\tw@\vbox{\break\unvbox\tw@}%
    {\splittopskip-\maxdimen \setbox\tw@\vsplit\tw@ to\z@}%
%    \end{macrocode}
% Notice the effect of \TeX's special box scope rules: box~2 assigned
% just right now will be affected by the split.  The result of the
% split will be an empty box that will temporarily overwrite box~2
% within the group, but will be restored back to the split result on
% exit.  In this manner, any topskip glue will have disappeared.
% After the split, box~2 is set to the natural depth and height of
% its contents.
%
% We now add a sort of strut by putting all the discarded material
% inside of a box that creates the proper size.
% If this split is taken, the box is adjusted to have a full depth of
% \cmd{\splitmaxdepth}, and we take this into account.
%    \begin{macrocode}
  \fi
  \ht4-\dp\tw@
  \dp4\ifdim\dp\tw@<\splitmaxdepth \splitmaxdepth \else \dp\tw@ \fi
  \advance\FN@myvsize\dimexpr \ht\tw@+\dp4\relax
  \unvbox\tw@
  \nointerlineskip
  \box4 }
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@uncontribute@tw@}
%   This is just the opposite: after a split, we revert its effects again.
%    \begin{macrocode}
\def\FN@uncontribute@tw@{%
  \ifvoid\tw@ \else
  \setbox\tw@\vbox{\unvbox\tw@\splitdiscards}%
  \setbox\z@\vbox{\break\unvbox\z@}%
  {\splittopskip-\maxdimen \setbox\z@\vsplit\z@ to\z@}%
  \setbox\z@\vbox{\unvbox\tw@\unvbox\z@}\fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@reconfig}
%   This reconfigures the insertion cache to contain only the boxes
%   that belong to this page.  If the insertion box is empty, we can
%   skip all the folderol.  If it isn't, we empty the cache box (the
%   number of which we place in \cmd{\count@}) and add its size back
%   to \cmd{\FN@vsize}.
%    \begin{macrocode}
\def\FN@reconfig#1#2{\ifvoid#2%
%<trace> \ifvoid\FN@cache#2\else
%<trace>    \errmessage{\FN@cache#2 should be void}\fi
  \else
  \count@\FN@cache#2%
  \ifvoid\count@\else
    \global\advance\FN@vsize
      \glueexpr(\ht\count@+\dp\count@)*\count#2/\@m+\skip#2\relax
    \global\setbox\count@ \box\voidb@x
  \fi
%    \end{macrocode}
%   Ok, now we have emptied the cache and readjusted the size.  We now
%   fill the cache by first copying the insertion into it.
%    \begin{macrocode}
  \global\setbox\count@\vbox\bgroup\vbox\bgroup\unvcopy#2%
    \let\@elt\FN@removecheck
    \FN@retainkept
%    \end{macrocode}
% Now if nothing was retained, we void the cachebox.
%    \begin{macrocode}
    \ifvoid\z@ \egroup\egroup \global\setbox\count@ \box\voidb@x
%    \end{macrocode}
% Otherwise, we combine all the boxes that remain on the page.
%    \begin{macrocode}
    \else \def\FN@masterinsert{#2}%
      \FN@assembleboxes\global\setbox\count@\box\z@\egroup
      \nointerlineskip\box\count@\egroup
%    \end{macrocode}
% Note that now all footnote boxes are collected into a single vbox,
% followed by the last footnote box as another vbox.
% Now we just need to reduce the available size on the page by the
% height of the assembled material:
%    \begin{macrocode}
    \global\advance\FN@vsize
      -\glueexpr(\ht\count@+\dp\count@)*\count#2/\@m+\skip#2\relax
  \fi\fi}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\FN@rejoin}
%   This glues together cache boxes that have been split, without
%   regenerating them.  This saves a lot of time as compared to
%   \cmd{\FN@reconfig}.
%    \begin{macrocode}
\def\FN@rejoin#1#2{{%
%<trace> \if\foottrace1\message{^^JRejoining #2}\fi
  \count@\FN@cache#2%
  \ifvoid\count@\else
    \global\advance\FN@vsize\dimexpr
       (\ht\count@+\dp\count@)*\count#2/\@m\relax
    \global\setbox\count@\vbox{%
      \unvbox\count@
      \ifnum\lastpenalty>\z@
        \unpenalty
        \setbox\tw@\lastbox
        \setbox\z@\lastbox
        \dimen@\dp\z@
        \setbox\z@\vbox{%
          \unvbox\z@
          \setbox\z@\lastbox
          \unvbox\z@
          \unvbox\tw@}%
        \ht\z@=\dimexpr\ht\z@+\dp\z@-\dimen@\relax
        \dp\z@=\dimen@
        \nointerlineskip
        \box\z@
      \fi}%
    \global\advance\FN@vsize-\dimexpr
        (\ht\count@+\dp\count@)*\count#2/\@m\relax
  \fi}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\FN@retainkept}
%  This relies on \cmd{\@elt} being set to \cmd{\FN@removecheck} which
%  expands to \cmd{\@ne} if |\box0| is strictly between the two values
%  from an entry of \cmd{\FN@config}, which means that it is material
%  that should get moved to the next page.  In that case, we recurse
%  while dropping the box in question.  Otherwise we keep it.
%  Recursion bottoms out when there are no boxes left.  The function
%  leaves the last retained box in box~0; if there are no boxes to be
%  retained, this will be void.
%    \begin{macrocode}
\def\FN@retainkept{%
  \setbox\z@\lastbox
  \ifcase
    \ifvoid\z@\m@ne\fi \FN@config\z@
%<trace>  \if\foottrace8\message{^^J\string\FN@retainkept:
%<trace>     retaining Id \FN@slotget{\number\dp\z@}}\fi
%<trace>  \if\foottrace{16}{\showboxdepth4 \showboxbreadth400
%<trace>     \tracingonline=\@ne\showbox\z@}\fi
    {\FN@retainkept \nointerlineskip \box\z@}%
  \or
%<trace>  \if\foottrace8\message{^^J\string\FN@retainkept:
%<trace>     dropping Id \FN@slotget{\number\dp\z@}}\fi
%<trace>  \if\foottrace{16}{\showboxdepth4 \showboxbreadth400
%<trace>     \tracingonline=\@ne\showbox\z@}\fi
    \FN@retainkept
%<trace>  \else
%<trace>  \ifnum\lastnodetype>\m@ne
%<trace>    \errmessage{Unexpected node \number\lastnodetype}\fi
  \fi}
%    \end{macrocode}
% \end{macro}
% Well, as the last measure, we change the output routine to our new
% routine.
%    \begin{macrocode}
\let\output\FN@output
%    \end{macrocode}
% Ok, here is debugging code intercepting all calls of the regular
% output routine and reporting its entry and exit states.
%    \begin{macrocode}
%<trace> \newtoks\FN@tr@output
%<trace> \FN@tr@output\output
%<trace> \output{\if\foottrace8{%
%<trace>   \setbox\z@\vbox{%
%<trace>     \message{Calling regular output with
%<trace>       \outputpenalty=\the\outputpenalty, box255 as}%
%<trace>     \showbox\@cclv
%<trace>     \the\FN@tr@output
%<trace>     \message{Returning from regular output with
%<trace>     \ifnum\lastnodetype<\z@
%<trace>       empty vertical list.\else vlist:}}%
%<trace>   \showbox\z@
%<trace>   \unvbox\z@{{\fi}}}\else\the\FN@tr@output\fi}
%<trace> \let\output\FN@tr@output
%    \end{macrocode}
% If the footnote type ``default'' has not been declared by the time
% the document starts, we do so at the start of the document.
% Unfortunately, by this time the initialization code in |manyfoot|'s
% own \cmd{\AtBeginDocument} hook has already run, so we manually run
% the initialization hook just for the command we inserted ourselves.
%    \begin{macrocode}
\def\FN@maybestart#1#2#3{\ifx#3\relax
  \csname MFL@start#1\endcsname{#2}\fi#3}
\@onlypreamble\FN@maybestart
\AtBeginDocument{\@ifundefined{footinsdefault}%
  {\newfootnote[plain]{default}%
    {\let\@elt\FN@maybestart
      \MFL@list\relax}%
  }{}%
%    \end{macrocode}
% And since LaTeX's macros are inferior to our own (and would probably
% not match too well), we reroot them to the default footnote style.
%    \begin{macrocode}
  \def\@footnotetext{\Footnotetextdefault{}}%
  \def\p@footnotedefault{\p@footnote}%
}
%</style>
%    \end{macrocode}
%
% \section{Various driver files}
% The installer, in case it is missing.  If it is to be used via
% |make|, we don't specify an installation path, since
% \begin{quote}
%   |make install|
% \end{quote}
% is supposed to cater for the installation itself.
%    \begin{macrocode}
%<installer> \input docstrip
%<installer&make> \askforoverwritefalse \nopreamble
%<installer> \generate{
%<installer>    \file{bigfoot.drv}{\from{bigfoot.dtx}{driver}}
%<installer>    \file{perpage.drv}{\from{perpage.dtx}{driver}}
%<installer>    \file{suffix.drv}{\from{suffix.dtx}{driver}}
%<installer&!make>    \usedir{tex/latex/bigfoot}
%<installer>    \file{bigfoot.sty}{\from{bigfoot.dtx}{style}}
%<installer>    \file{perpage.sty}{\from{perpage.dtx}{style}}
%<installer>    \file{suffix.sty}{\from{suffix.dtx}{style}}
%<installer> }
%<installer> \endbatchfile
%    \end{macrocode}
% \Finale
% \endinput
% Local Variables:
% mode: doctex
% TeX-master: "bigfoot.drv"
% End: