summaryrefslogtreecommitdiff
path: root/web/funnelweb/examples/except.tex
blob: cc19c6f5a1822c2d07954be8eea1ffacc50e028c (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

%*******************************************************************************
%*                    START OF AUTOMATICALLY GENERATED TEX FILE                *
%*******************************************************************************
%*                                                                             *
%* This TeX file was automatically generated by the FunnelWeb preprocessor.    *
%* You can typeset this file to produce printed documentation by running it    *
%* through the TeX typesetter using a command such as:                         *
%*    tex thisfilename                                                         *
%* The resultant file thisfilename.dvi can be printed using a command such as: *
%*    lpr -Pcslw -d thisfilename.dvi                                           *
%*                                                                             *
%* FunnelWeb is a preprocessor that allows programmers to weave programs and   *
%* their documentation together in a single document. The FunnelWeb program    *
%* analyses such documents producing both program files and typeset            *
%* documentation such as this TeX file.                                        *
%* FunnelWeb was created by Ross Williams.                                     *
%*                                                                             *
%* For more information on FunnelWeb look in the following FTP archive:        *
%*    Machine  : sirius.itd.adelaide.edu.au [IP=129.127.40.3].                 *
%*    Directory: ~pub/funnelweb/                                               *
%*               (or some other appropriately named directory).                *
%* or email Ross Williams at ross@spam.adelaide.edu.au                         *
%*                                                                             *
%*******************************************************************************


%===================== Start of FunnelWeb TeX Definitions ======================


% Version
% -------
% This is FunnelWeb TeX Macro Library Version 1.0.


% Copyright
% ---------
% This set of FunnelWeb TeX definitions was written by Ross Williams and was
% originally Copyright (C) 1992 Ross N. Williams.  However, I, Ross Williams,
% hereby forego any claim to Copyright in this set of FunnelWeb TeX definitions
% and hereby authorize that the set of TeX definitions pass into the public
% domain. -- Ross N. Williams, 3:41pm 07-May-1992, Adelaide, Australia.


% Modification
% ------------
% Please record all modifications to these TeX definitions here. Unless
% otherwise specified, all modified definitions fall in the public domain too.
%
% Programmers:
%    RNW  Ross N. Williams  ross@spam.adelaide.edu.au
%
% Changes:
%    07-May-1992  RNW  Prepared this work for public domain release.
%


% General Comments
% ----------------
% This set of TeX definitions exists for two reasons:
%
%    1. To shorten and neaten the FunnelWeb TeX output.
%    2. To allow users to fiddle with the output format in their input files
%       (by inserting redefining "\def"s) without having to resort to
%       modifying the FunnelWeb code.
%
% The user is warned that these definitions may be changed from time to time
% (but probably not much). The user should not be too sneaky. In particular,
% users wishing to redefine some of these macros should do so in an explicitly
% defined section at the top of their input file. This will mean that in the
% event of problems, that section can simply be deleted or commented out to
% allow the document to at least be typeset in the default format. Users should
% limit themselves to redefining these macros in such a section and should
% refrain from using the macros throughout their documents.


% Environment Parameters
% ----------------------
% \tolerance tells TeX how tolerant it should be about making bad line and
% page breaks. Here we set it to it's maximum, as
%   1) Computer programs are likely to cause lots of bad breaks.
%   2) In most cases the user would probably rather get the TeX file through
%      TeX without any errors than fiddle with spacings for perfection.
\tolerance=10000

% I don't like indentation as it makes the page look more busy. Instead,
% paragraphs are separated by a little space (see next).
\parindent=0pt

% In many cases, users will produce documents with long runs of paragraphs.
% In order to space out these paragraphs, it is convenient to maintain a
% prevailing non-zero \parskip (end-of-paragaph skip). The only trouble is
% that the skip becomes a problem in macro definitions which require no skip
% and so we have to turn the skip on and off. The following two macros
% simplify this process.
\def\fwparskipon{\parskip=\medskipamount}
\def\fwparskipoff{\parskip=0pt}
\fwparskipon

% Setting raggedbottom allows TeX to leave a bit of space at the bottom of the
% page in order to better vertically align the rest of the page (e.g. skips
% won't stretch as much). It also means that headings are less likely to be
% isolated at the bottom of the page without any following text.
\raggedbottom


% Fonts
% -----
% Most of the typeset output is set in 10pt roman and 10pt tt font.
% The major extra font needs spring from titles and headings.
% For portability's sake we use only the following fonts:
%    cmr10
%    cmbx10
%    cmtt10
% and some enlargements of them. These fonts are all "standard" fonts
% in Plain TeX. See The TeXbook p.350.
\font\fwfontnote=cmr7

\font\fwfontnorm=cmr10
\font\fwfontnorma=cmr10 scaled \magstep1
\font\fwfontnormb=cmr10 scaled \magstep2

\font\fwfontbold=cmbx10
\font\fwfontbolda=cmbx10 scaled \magstep1
\font\fwfontboldb=cmbx10 scaled \magstep2
\font\fwfontboldc=cmbx10 scaled \magstep3
\font\fwfontboldd=cmbx10 scaled \magstep4


% Macros for Stylistic Details
% ----------------------------
% This section contains all the fiddly little macros for setting the details
% of each macro definition.

% Macro definitions are sandwiched by calls to these macros which can be used
% to sort out the spacing before and after the macro definition.
\def\fwbeginmacro{\fwparskipoff\bigskip}
\def\fwendmacro{\fwparskipon\par}

% These macros deal with the macro name and definition line.
\def\fwmacroname#1#2{{\sl #1\/}$\lbrack$#2$\rbrack$}
\def\fwfilename#1#2{{\bf #1}$\lbrack$#2$\rbrack$}
\def\fwzero#1{{\bf Z}}
\def\fwmany#1{{\bf M}}
\def\fwequals{ $\equiv$}
\def\fwplusequals{ $+\equiv$}

% Now for the actual body of the definition. It looks nice to have the tt
% code indented a little. Again, we use macros instead of writing direct TeX,
% so as to allow the user to fiddle this stuff to taste without having to
% modify the FunnelWeb C code.
\def\fwodef{\parindent=15pt\vskip0pt$\lbrace$\parindent=20pt}
\def\fwcdef{$\rbrace$\vskip0pt\parindent=0pt}
\def\fwoquote{`}
\def\fwcquote{'}
\def\fwoparen{$($}
\def\fwcomma{$,$}
\def\fwcparen{$)$}
\def\fwparam#1{$\diamond #1$}
\def\fwparams#1{$(\diamond #1)$}

% These macros deal with the notes that are appended at the end of each
% macro definition. Note that even though \fwisafile,\fwusedin, and \fwseealso
% have the same definition, they are given different names so as to allow the
% user to redefine these macros to typeset each kind of information differently
% if desired.
\def\fwbeginmacronotes{\begingroup\baselineskip=9pt\smallskip}
\def\fwnote#1{{\fwfontnote #1}\par}
\def\fwisafile#1{\fwnote{#1}}
\def\fwusedin#1{\fwnote{#1}}
\def\fwseealso#1{\fwnote{#1}}
\def\fwendmacronotes{\endgroup}


% Macros to Typeset Program Code Verbatim
% ---------------------------------------
% This is by far the hairiest and most difficult part of the typesetting task
% because we have to turn off most of TeX's natural instincts in order to
% typeset the program text exactly as it appears in the input file.
% Two macros are defined to pull this off: \fwbtx and \fwverbatimgobble.
% Their code was inspired by the following sections of "The TeXbook":
%    Appendix D: Dirty Tricks, 3.Verbatim listing, p.380-382.
%    Appendix E: Example Formats, p.421.
% The \fwbtx[ (for "FunnelWeb Begin TeXt") macro does most of the hard work.
% The liberal use of "%" is because I don't understand TeX well enough to
% understand when an end of line will cause trouble, and I am playing it safe.

% Before defining the main \fwbtx macro, we have to stash away some definitions
% in the hidden part of TeX's environment. Let's hope that these "hidden"
% definitions don't affect anything except what is desired to be affected.

% The tt font in which we wish to set the text has two Latin lurking ligatures!
% These are ?` and !`. To disable them, we define the left quote when ACTIVE
% to be defined in such a way as to prevent ligatures. The main TeX text will
% normally not be exposed to this definition because normally the leftquote
% character is not active. The \fwbtx macro temporarily makes the left quote
% character active thus activating the deactivation of left quote ligatures.
% See The TeXbook p.381.
{\catcode`\`=\active \gdef`{\relax\lq}}

% TeX is fairly carefree about spaces and so we have to make it more serious.
% To do so we pull the same trick as above, setting up a definition for active
% space, but only making space active during the span of the verbatim text.
% In Plain TeX the active space is defined to be simply a space, but here we
% define it to be a control space. This ensures that the space cannot
% be gobbled up by one of TeX's mysterious mechanisms when activated.
% See The TeXbook, p.381 and p.352.
{\obeyspaces\global\let =\ }

% Here is the main \fwbtx verbatim text macro.
% Note: The order in which all these pieces of business have to be done is
% still a partial mystery to me. Don't fiddle with this stuff unless you
% think you know what you are doing.
\def\fwbtx[{%
%
% The funnies involved in getting verbatim output are safely housed inside
% this \begingroup, and the \endgroup in \fwverbatimgobble. Groups are used
% instead of curly braces because we have to be able to signal the end of
% this macro with a curly brace.
\begingroup%
%
% \pars at the end of empty lines in the verbatim text won't come out normally
% because TeX is in vertical mode and they get gobbled up. To prevent this,
% we force \par to exit vertical mode first. See The TeXbook p.381.
\def\par{\leavevmode\endgraf}%
%
% Activate the leftquote character so as to avoid ligatures (see above).
\catcode`\`=\active%
%
% The \obeylines macro simply defines end of line (^M) to be \par. This ensures
% that TeX will treat each verbatim line as a new paragraph.
\obeylines%
%
% To get verbatim output, we have to desex all the special characters. This
% is explained in detail in The TeXbook p.380.
\def\do##1{\catcode`##1=12 }\dospecials%
%
% Activate the space character so as to make TeX treat blanks seriously.
% This activation invokes an eralier definition (see above).
\obeyspaces
%
% Interparagraph skips do not help the cause.
% Note: We have to preserve the indentation though, as the code is actually
% indented in the final output. See \fwodef in an earlier section.
\parskip=0pt%
%
% We typeset the verbatim text in tt font (courier on the Macintosh) for a
% number of reasons:
%    - tt font has the same horizontal spacing for each character.
%    - tt font covers the ASCII character set.
%    - tt font doesn't have many surprises (e.g. ligatures).
%    - tt font looks much what you might see on a computer terminal screen.
\tt%
%
% Having set up an environment for verbatim, we are ready to use it.
% By invoking \fwverbatimgobble, this \fwbtx macro gobbles up text verbatim (as
% part of the parameter of \fwverbatimgobble) until it sees the termination
% string "]fwetx=" (the "=" was thrown in to add obscurity as this sequence
% must never occur in the verbatim text).
\fwverbatimgobble}

% The \fwverbatimgobble macro exists to allow \fwbtx to bracket verbatim text.
\def\fwverbatimgobble#1]fwetx={#1\endgroup}


% Table of Contents
% -----------------
% The five levels of table of contents that FunnelWeb supports are identified
% by the five letters [A..E]. These are used throughout the following macros.

% The following macros are utilities to the TOC macros to follow.
\def\fwrule{\medskip\hrule\medskip}
\def\fwqh{\hskip1.5em\relax}
\def\fwbeforesec{\penalty-200\bigskip\medskip\par}

% The following macros are used to typeset the table of contents.
\def\fwtocstart#1{\fwrule\leftline{\fwfontbolda Table of Contents}\fwrule}
\def\fwtoca#1#2{\leftline{{\bf #1 #2}}}
\def\fwtocb#1#2{\leftline{\fwqh #1 #2}}
\def\fwtocc#1#2{\leftline{\fwqh\fwqh #1 #2}}
\def\fwtocd#1#2{\leftline{\fwqh\fwqh\fwqh #1 #2}}
\def\fwtoce#1#2{\leftline{\fwqh\fwqh\fwqh\fwqh #1 #2}}
\def\fwtocfinish#1{\fwrule}

% The following "library" macros define five different strengths of headings
% which can be used later in the section macros.
\def\fwliba#1#2{\vfill\eject{\fwfontboldc #1 #2}\penalty200\smallskip}
\def\fwlibb#1#2{\fwbeforesec{\fwfontboldb #1 #2}\penalty200\smallskip}
\def\fwlibc#1#2{\fwbeforesec{\fwfontnormb #1 #2}\penalty200\smallskip}
\def\fwlibd#1#2{\fwbeforesec{\bf          #1 #2}\penalty200}
\def\fwlibe#1#2{\fwbeforesec{\bf          #1 #2}}

% Here are the macros that actually typeset the section headings throughout
% the document. The fwlib system has been employed so as to easily allow the
% user to redefine the strengths of headings to taste. For example, the
% user could insert in the input document a similar set of definitions to these
% but with the b..e headings set to \fwlibc. This would tone down the output.
\def\fwseca#1#2{\fwliba{#1}{#2}}
\def\fwsecb#1#2{\fwlibb{#1}{#2}}
\def\fwsecc#1#2{\fwlibc{#1}{#2}}
\def\fwsecd#1#2{\fwlibd{#1}{#2}}
\def\fwsece#1#2{\fwlibe{#1}{#2}}


% Support for Explicit Typesetting
% --------------------------------
% FunnelWeb supports pragmas and other constructs that allow
% typesetter-independent typesetting commands to be given. The
% following macros support these features.

% The in-text literal @{sloth@} and emphasise @[walrus@] features.
\def\fwlit#1{{\tt #1}}
\def\fwemp#1{{\it #1}}

% The "@p new_page" pragma.
\def\fwnewpage{\vfill\eject}

% The "@p vskip Nmm" pragma.
\def\fwvskip#1{\null\vskip #1mm}

% The "@p title <font> <align> <text>" pragma.
\def\fwfontnormal#1{{\fwfontnorm {#1}}}
\def\fwfonttitle#1{{\fwfontboldd {#1}}}
\def\fwfontsmalltitle#1{{\fwfontboldb {#1}}}
\def\fwleftline#1{\leftline{#1}}
\def\fwcenterline#1{\centerline{#1}}
\def\fwrightline#1{\rightline{#1}}


% Support for Old FunnelWeb
% -------------------------
% The following macros were used extensively in the first version of
% FunnelWeb and are retained so that these older input files will still
% typeset cleanly.
\def\p#1{{\tt #1}}  % P for Program text.
\def\flagpage#1#2{
   \null
   \vfill
   \centerline{\fwfontboldd #1}
   \vskip 1cm
   \centerline{\fwfontboldd #2}
   \vfill
   \null
   \vfill
}

%====================== End of FunnelWeb TeX Definitions =======================

\fwvskip{50}
\fwcenterline{\fwfonttitle{Exceptions}}
\fwcenterline{\fwfonttitle{Package}}
\fwvskip{10}
\fwcenterline{\fwfontsmalltitle{by Ross Williams}}
\fwcenterline{\fwfontsmalltitle{April 1993}}

\fwnewpage

\fwvskip{20}
\fwcenterline{\fwfonttitle{Contents}}
\fwvskip{10}

\fwtocstart{}
\fwtoca{1}{Overview}
\fwtocb{1.1}{Configuration Header Notice}
\fwtocb{1.2}{Abstract}
\fwtocb{1.3}{Motivation}
\fwtocb{1.4}{What is an Exception?}
\fwtocb{1.5}{Exceptions as Active Statuses}
\fwtocb{1.6}{How to Use This Package}
\fwtoca{2}{Static Parameters of this Package}
\fwtocb{2.1}{Inline Switch Parameter}
\fwtocb{2.2}{Threading Parameter}
\fwtocb{2.3}{Macros for Global Variables}
\fwtoca{3}{Specification}
\fwtocb{3.1}{Specification Includes}
\fwtocb{3.2}{Exception Type}
\fwtocb{3.3}{Macro EX\_RAISE}
\fwtocb{3.4}{Exception Block Construct}
\fwtocb{3.5}{Definition of Semantics}
\fwtocb{3.6}{Exception Information}
\fwtocb{3.7}{Function ex\_str}
\fwtocb{3.8}{A Warning About Names}
\fwtocb{3.9}{Glossary}
\fwtoca{4}{Implementation}
\fwtocb{4.1}{Overview and Data Structure Description}
\fwtocc{4.1.1}{Global Variables}
\fwtocc{4.1.2}{Magic Numbers}
\fwtocb{4.2}{Exception type}
\fwtocb{4.3}{Macros for Declaring and Defining Exceptions}
\fwtocb{4.4}{Macro for Raising Exceptions}
\fwtocb{4.5}{Exception Block Macros (Safe)}
\fwtocb{4.6}{Fast, Inline Versions of the Exception Block Macros}
\fwtocb{4.7}{Function ex\_str}
\fwtocb{4.8}{Support Functions}
\fwtocc{4.8.1}{Function \_exrai}
\fwtocc{4.8.2}{Function ex\_bomb}
\fwtocc{4.8.3}{Function \_expop}
\fwtoca{5}{Test Program}
\fwtocb{5.1}{Function sc01}
\fwtocb{5.2}{Function sc02}
\fwtocb{5.3}{Function sc03}
\fwtocb{5.4}{Function sc04}
\fwtocb{5.5}{Function sc05}
\fwtocb{5.6}{Function sc06}
\fwtocb{5.7}{Function sc07}
\fwtocb{5.8}{Function sc08}
\fwtocb{5.9}{Function sc09}
\fwtocb{5.10}{Function fa01}
\fwtocb{5.11}{Function fa02}
\fwtocb{5.12}{Function fa03}
\fwtocb{5.13}{Function fa04}
\fwtocb{5.14}{Function fa05}
\fwtocb{5.15}{Function fa06}
\fwtocb{5.16}{Function fa07}
\fwtocb{5.17}{Function fa08}
\fwtocb{5.18}{Function fa09}
\fwtoca{6}{Design Notes}
\fwtocb{6.1}{Architectural Discussion}
\fwtocb{6.2}{Exception Identity}
\fwtocb{6.3}{Identifier Names}
\fwtocb{6.4}{Catering for Multi-Threading}
\fwtocb{6.5}{Checking}
\fwtocb{6.6}{Future Improvements}
\fwtocfinish{}


\fwnewpage



\fwseca{1}{Overview}

This overview section provides general information about this package.

Processing this file using FunnelWeb will result in the production of the
specification and implementation files defined below. In addition a test
program for testing this package will be generated. This FunnelWeb source
file and the files that it generates are Copyright (C) Ross Williams 1993.
See the configuration header notice below.

\fwbeginmacro
\fwfilename{except.h}{1}\fwequals \fwodef \fwmacroname{Specification file}{18}\fwbtx[
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwisafile{This macro is attached to an output file.}
\fwendmacronotes
\fwendmacro

\fwbeginmacro
\fwfilename{except.c}{2}\fwequals \fwodef \fwmacroname{Implementation file}{31}\fwbtx[
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwisafile{This macro is attached to an output file.}
\fwendmacronotes
\fwendmacro

\fwbeginmacro
\fwfilename{ex\_test.c}{3}\fwequals \fwodef \fwmacroname{Test program file}{74}\fwbtx[
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwisafile{This macro is attached to an output file.}
\fwendmacronotes
\fwendmacro


The remainder of this overview section contains only descriptions. It does
not contain any code.


\fwsecb{1.1}{Configuration Header Notice}

The following notice applies to this FunnelWeb source file as well as to
the FunnelWeb output files to which it is written.

\fwbeginmacro
\fwmacroname{Configuration header notice}{4}\fwmany{}\fwequals \fwodef \fwbtx[
/*************************************************************************/
/* Package name  : Except.                                               */
/* Version       : 1.0                                                   */
/* Completed     : April 1993.                                           */
/* Released      : 29 September 1993.                                    */
/* First created : This package was first created in April 1993.         */
/* Summary       : This package provides Ada-like exceptions for C.      */
/* Components    : except.fw  - FunnelWeb source file.                   */
/*                 except.h   - Exported header file.                    */
/*                 except.c   - Implementation file.                     */
/*                 ex_test.c  - C test program.                          */
/* Requires      : style.h, as.h, as.c.                                  */
/* Author        : Ross N. Williams (ross@guest.adelaide.edu.au)         */
/*                 Rocksoft^tm Pty Ltd                                   */
/*                 16 Lerwick Avenue, Hazelwood Park 5066, Australia.    */
/* FTP Archive   : This file can be found in                             */
/*                 "ftp.adelaide.edu.au/pub/funnelweb/examples/"         */
/* Disclaimer    : This program is distributed WITHOUT ANY WARRANTY;     */
/*                 without even the implied warranty of MERCHANTABILITY  */
/*                 or FITNESS FOR A PARTICULAR PURPOSE.                  */
/* Copyright     : Copyright (C) Ross Williams 1993.                     */
/*                 However, permission is granted for anyone to copy,    */
/*                 modify, and distribute this work for any purpose,     */
/*                 commercial or non-commercial, so long as this notice  */
/*                 is included verbatim, and so long as all              */
/*                 modifications are recorded in the change log below.   */
/* Changes       : Please log any changes to this software either in the */
/*                 originating FunnelWeb source file, or, if you must,   */
/*                 in the C source files produced from the FunnelWeb     */
/*                 file.                                                 */
/* --<Start of Change Log>--                                             */
/* ??-Apr-93: RNW: Created this package.                                 */
/* 29-Sep-93: RNW: Released this package.                                */
/* --<End of Change Log>--                                               */
/*************************************************************************/
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definitions 18, 31, and 74.}
\fwendmacronotes
\fwendmacro



\fwsecb{1.2}{Abstract}

This package provides an \fwemp{exceptions} facility for C that is very similar to
the exceptions facility in the Ada programming language. An exception is a
control-flow event that causes control to be transferred up the stack
(with the stack unwinding as it goes) until a \fwemp{handler} for the particular
exception invoked is found. The exception facility is totally under the
client's control. The client defines a set of exceptions, and \fwemp{raises} an
exception event by calling \fwlit{EX\_RAISE}. Other functions defined by the client
can catch the exceptions by name. The exception facility is useful for
error handling and package interface definition.


\fwsecb{1.3}{Motivation}

The motivation for creating this package was to provide a simpler, safer, and
more sophisticated non-local jump facility than is provided by the standard
ANSI \fwlit{setjmp} (ANSI 7.6.1.1) and \fwlit{longjmp} (7.6.2.1) primitives. In
particular, the biggest problem with the ANSI functions is that they
require that the thrower and catcher of the control event be sufficiently
coordinated to share a single global variable containing the catcher's
context. The requirement for this link is unacceptable because it precludes
the use of non-local jumps as an element of the interface of packages
having an abstract client (unless \fwlit{jmpbuf}s are passed as parameters - yuk!).
This lack of abstraction results in the following disadvantages:

* A global variable of type \fwlit{jmpbuf} must be agreed upon between thrower
and catcher for each potential throw. The result is a proliferation of
global context variables, whose validity at any particular instant is often
unclear.

* If the programmer wishes to set up a nest of handlers for a particular
condition, the global \fwlit{jmpbuf} buffer for the condition must be explicitly
and carefully saved and restored by each function in the nest.

* The interface to \fwlit{setjmp} and \fwlit{longjmp} is a bit raw, requiring
fiddling with integer values and embedding calls in conditional statements.

A better solution to the problem of non-local jumps is a system of
exceptions.


\fwsecb{1.4}{What is an Exception?}

An exception is essentially a non-local \fwlit{goto} to the nearest dynamically
enclosing target label in the stack of suspended functions. To execute an
exception \fwlit{goto}, one \fwemp{raises} the exception, for example with a \fwlit{raise}
statement \fwlit{raise sloth\_exception;}. Control is then immediately transferred
to the nearest dynamically enclosing handler (label) for \fwlit{sloth\_exception}.

In fact handlers are not simply labels, but block-structured constructs
that define an execution zone within which the set of exceptions that they
handle will be caught. For example, the following exception handling
anonymous block might appear in a program written in the Ada programming
language:

\fwbeginmacro
\fwmacroname{Example of an Ada exception handling block}{5}\fwzero{}\fwequals \fwodef \fwbtx[
declare
   n : integer := 2*x+y;
begin
   sloth_action(n);
   walrus_action(n*n);
exception
   when sloth_exception    => PUT("The sloth    exception went off.");
   when aardvark_exception => PUT("The aardvark exception went off.");
end
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is NEVER invoked.}
\fwendmacronotes
\fwendmacro


In the above example, the code between \fwlit{declare} and \fwlit{exception} is
the code within which exceptions will be caught. The code between
\fwlit{exception} and \fwlit{end} contains two exception handlers that will catch
the exceptions \fwlit{sloth\_exception} and \fwlit{aardvark\_exception} should they
be raised by the execution of the declarations or \fwlit{sloth\_action} or
\fwlit{walrus\_action}. Any other exception that is raised within the controlled
zone will simply propagate further up the call chain to the nearest handler
that can handle it.

A most important aspect of the exceptions provided by Ada and this package
is that an exception propagates to the nearest \fwemp{dynamically} enclosing
exception handler. This means that, apart from the shared knowledge of the
definition of the exception, there is not necessarily any static relationship
between the function that raises an exception and the function that catches
it. This makes exceptions both dangerous and powerful. Dangerous because a
programmer can code a \fwlit{raise} statement with no knowledge of the function
catching the exception. Powerful, because this very abstraction allows
packages to raise exceptions that can be caught by abstract clients.


\fwsecb{1.5}{Exceptions as Active Statuses}

Over the years, exceptions have received a lot of bad press and have
generally been considered to be dangerous things. For example, Tony Hoare,
in his Turing Award lecture of 1980, when covering the programming
language Ada, remarked:

\fwemp{Gradually these objectives have been sacrificed in favour of power,
supposedly achieved by a plethora of features and notational conventions,
many of them unncessary and some of them, like exception handling,
even dangerous.} --- Charles Antony Richard Hoare, Turing Award Speech, 1980.

Certainly exceptions can be dangerous things. However, I believe that, on
balance, exceptions enhance reliability rather than deteriorating it. The
reason for this belief is that exceptions \fwemp{actively} indicate problems,
whereas their alternative in this capacity, statuses, \fwemp{passively} indicate
problems.

To see this, consider the simple example case of a function that is supposed
to write its argument character to its argument device. This is a
straightforward operation, unless the device fails in some way, in which case
this fact must be indicated to the caller. The traditional way of defining such
a function is to have it return a status indicating whether the call succeeded.

\fwbeginmacro
\fwmacroname{Example of a function returning a status}{6}\fwzero{}\fwequals \fwodef \fwbtx[
EXPORT bool writdev P_((dev_t,char));
/* Returns TRUE upon success, FALSE if the write failed. */
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is NEVER invoked.}
\fwendmacronotes
\fwendmacro


This results in calling code that should look something like this:

\fwbeginmacro
\fwmacroname{Example of call to function returning a status}{7}\fwzero{}\fwequals \fwodef \fwbtx[
if (!writdev(slothdev,'x'))
  bomb("Sloth device failed - aborting.\n");
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is NEVER invoked.}
\fwendmacronotes
\fwendmacro


but often looks like this:

\fwbeginmacro
\fwmacroname{Example of call without checking to a function returning a status}{8}\fwzero{}\fwequals \fwodef \fwbtx[
writdev(slothdev,'x');
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is NEVER invoked.}
\fwendmacronotes
\fwendmacro


Code such as this is extremely dangerous because a program written in this
way might operate correctly for years, but then suddenly start behaving in
odd ways when undetected errors occur. Unfortunately, it
is extremely easy to write code such as this, as is easy to forget that
a particular function even returns a status! Code such as this is quite
common.

Now consider how \fwlit{writdev} looks if it is defined using an exception to
take care of the error case:

\fwbeginmacro
\fwmacroname{Example of a function that uses an exception}{9}\fwzero{}\fwequals \fwodef \fwbtx[
EXPORT void writdev P_((dev_t,char));
/* Raises writedev_ex exception if the write fails. */
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is NEVER invoked.}
\fwendmacronotes
\fwendmacro


By casting the error condition in terms of an exception, the function
\fwemp{by default} ensures that something will happen if an error arises.
In fact, one of two things must happen if the exception is ever raised: either
the programmer codes a catcher for the exception and deals with it (in which
case, it will probably be dealt with properly) or the exception propagates
up out of \fwlit{main()} where it will cause the exceptions package to
initiate a controlled program bomb describing the unhandled exception.
Both of these alternatives ensure that the condition is explicitly handled
which is the important thing.

By using exceptions, the programmer can ensure that \fwemp{by default} any
error condition that arises will cause a program bomb. This is such a
strong safety net that it actually \fwemp{legitimizes} the no-error checking
style of programming so criticized earlier. If you are in a hurry to write
a program and do not wish to bother with error checking, the use of
functions that raise exceptions upon errors ensures that if the code
terminates normally, then it has terminated error-free --- even though
the programmer did not code any checking of return conditions.

Another advantage of exceptions is that they allow whole classes of errors
that might arise in a span of code to be handled at one point. For example:

\fwbeginmacro
\fwmacroname{Example of single-point error handling}{10}\fwzero{}\fwequals \fwodef \fwbtx[
EX_BEGIN
   f_file_t file1, file2;
   char line[1000];
   f_open(file1,read,"sloth.dat");
   f_open(file2,write,"walrus.dat");
   while (!f_eof(file1))
     {
      f_readline (file1,line,1000);
      f_writeline(file2,line,1000);
     }
   fclose(file1);
   fclose(file2);
EX_FORGET
   EX_WHEN(f_open_ex ) goto f_handle;
   EX_WHEN(f_read_ex ) goto f_handle;
   EX_WHEN(f_write_ex) goto f_handle;
   EX_WHEN(f_close_ex)
   f_handle:
      f_delete(file2);
      printf("Error performing copy.");
EX_END]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is NEVER invoked.}
\fwendmacronotes
\fwendmacro


In the above code, a single exception handler handles all the error conditions
that might arise during all the file operations. The resultant code is far
cleaner than the code that would be necessary if the status of each call
had to be checked independently. Using exceptions, the normal and the
exceptional cases can each be expressed clearly.

\fwemp{Summary:} There is no doubt that, when misused, exceptions can be
an extremely dangerous language construct. However, they also have the
outstanding quality of enabling functions to be written that \fwemp{actively}
indicate errors, thus ensuring either that the client code does \fwemp{something}
about the error, or that the program will bomb with an unhandled exception
error. In this capacity exceptions act as \fwemp{active statuses}. In addition,
exceptions allow error handling to be separated from ordinary execution.
These two properties of exceptions mean that, in my opinion, they improve
reliability on balance, and are a worthy programming tool.


\fwsecb{1.6}{How to Use This Package}

Using this package is easy - just follow the following steps!

\fwemp{STEP 1: Define the exception.} Before raising or catching an exception,
you have to define it and make it visible to every entity that needs to
refer to the exception. To define it, you need to think of an identifier that
will be used to represent the exception, and you need to think of a short
(one-line) description for the exception. Having done this, if you want
the exception to be visible only within the current program file, insert
a call to the macro \fwlit{EX\_LOCAL} in the variable section. For example:

\fwbeginmacro
\fwmacroname{Example exception definition}{11}\fwzero{}\fwequals \fwodef \fwbtx[
EX_LOCAL(buf_full,"buf_full: Buffer is full exception.");
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is NEVER invoked.}
\fwendmacronotes
\fwendmacro


The first argument is the \fwemp{exception identifier} and the second argument is
the \fwemp{exception description}. The \fwlit{EX\_LOCAL} macro translates into a
string constant declaration having the name \fwlit{buf\_full} and the value
\fwlit{\char`\"buf\_full: Buff...\char`\"}. It is important that the exception identifer be
unique within its scope as it is implemented by an ordinary constant. It
is also very important that the description of the exception be unique
within the set of exceptions in the program. If each exception has a unique
description, then unhandled exceptions (see later) can be easily identified.

If you want the exception to be visible within all clients of the module
declaring it, replace \fwlit{EX\_LOCAL} above with \fwlit{EX\_EXPORT} and insert a
call to \fwlit{EX\_EXCEPT} in the header file for the module. \fwlit{EX\_EXCEPT}
requires just the variable name.

\fwbeginmacro
\fwmacroname{Example exception declaration}{12}\fwzero{}\fwequals \fwodef \fwbtx[
EX_EXCEPT(buf_full);
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is NEVER invoked.}
\fwendmacronotes
\fwendmacro


\fwemp{STEP 2: Raise the exception.} Having completed step 1, you can now raise the
exception in any module that can see the exception (i.e. the \fwlit{.c} file
with the \fwlit{EX\_LOCAL} or \fwlit{EX\_EXPORT}, and any \fwlit{.c} file that includes
the header file containing the \fwlit{EX\_EXCEPT}) simply be calling \fwlit{EX\_RAISE}.
Note: \fwlit{EX\_RAISE} is syntactically equivalent to a compound statement.

\fwbeginmacro
\fwmacroname{Example of raising an exception}{13}\fwzero{}\fwequals \fwodef \fwbtx[
/* If the buffer is full, raise the full buffer exception. */
if (bufsiz > BUF_MAX)
   EX_RAISE(buf_ful);
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is NEVER invoked.}
\fwendmacronotes
\fwendmacro


The effect of a call to \fwlit{EX\_RAISE} is that control will leave the current
function, and the stack will unwind until a function is encountered whose
context contains an active exception handler construct that specifies a
catcher for the exception that has been raised (in this case \fwlit{buf\_ful}.
If no such handler exists, the exception package will bomb the program,
printing out an error message stating that an exception has not been
handled, and giving the description of the exception.

\fwemp{STEP 3: Catch the exception.} Catching exceptions is a little tricker than
raising them. To catch an exception, you need to specify so in advance
by enclosing the code that might raise the exception within an \fwemp{exception
block} construct provided by the \fwlit{EX\_} macros \fwlit{EX\_BEGIN}, \fwlit{EX\_FORGET},
\fwlit{EX\_WHEN} and \fwlit{EX\_END}. Here is an abstract example:

\fwbeginmacro
\fwmacroname{Exception block syntax}{14}\fwzero{}\fwequals \fwodef \fwbtx[
EX_BEGIN
   <Code that might raise an exception>
EX_FORGET
   EX_WHEN(<name of exception 1>)
      <Code to handle exception 1>
   EX_WHEN(<name of exception 2>)
      <Code to handle exception 2>
   EX_WHEN(<name of exception 3>)
      <Code to handle exception 3>
EX_END
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is NEVER invoked.}
\fwendmacronotes
\fwendmacro


The entire context (from \fwlit{EX\_BEGIN} to \fwlit{EX\_END}) is syntactically
equivalent to a compound statement (\fwlit{\char`\{\char`\}}). Its semantics are that the
code that might raise an exception is executed, and, if no exceptions are
raised, terminates. If an exception is raised, the code aborts to
the corresponding handler, or is propagated upwards if no matching handler
is present. For a more detailed description of the semantics, see the
specification section.


\fwseca{2}{Static Parameters of this Package}

This package has a few static (compile-time) parameters which can be used
to modify its behavior.


\fwsecb{2.1}{Inline Switch Parameter}

Exceptions are tricky constructs, particularly in a programming language
like C, and it makes sense to incorporate lots of checking into a package
such as this one. At the same time, exceptions are a fundamental language
construct that are likely to be used extensively, and it should be possible
to configure them to be as efficient as possible.

To satisfy these twin needs, this package provides a boolean parameter which
can be used to select two different kinds of implementation. Set \fwlit{\_EX\_FAST}
to \fwlit{FALSE} if you want the exported macros to generate function calls and to
perform lots of checks. Set \fwlit{\_EX\_FAST} to \fwlit{TRUE} if you want the exported
macros to generate inline code that runs as fast as possible with no checking
at all. It is strongly recommended that this symbol be set to \fwlit{FALSE}
unless performance requirements absolutely demand that it be set to \fwlit{TRUE}.

\fwbeginmacro
\fwmacroname{Symbol \_EX\_FAST}{15}\fwequals \fwodef \fwbtx[
#define _EX_FAST FALSE
/* Set _EX_FAST to TRUE to turn on inlining and turn off checking. */
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 32.}
\fwendmacronotes
\fwendmacro


Note: Some other packages (such as the \fwlit{link} package) allow parameters
like this to be set by the client package, thus enabling different client
modules to specify different safety/efficiency trade-offs. However, this level
of parameterization granularity could not be achieved in this package as
some of the checking is magic number checking which must be employed globally
or not at all. The problem is that a module with checks on might complain
about incorrect magic numbers that were not set by another module with checks
off.


\fwsecb{2.2}{Threading Parameter}

The parameter \fwlit{\_EX\_THRD} tells the package whether it is operating within
a multi-threaded environment (\fwlit{TRUE}) (thus prohibiting single-instance
global variables). If you set this to \fwlit{TRUE}, you will also need to
modify the macros for global variables in the next section.

\fwbeginmacro
\fwmacroname{Symbol \_EX\_THRD}{16}\fwequals \fwodef \fwbtx[
#define _EX_THRD FALSE
/* To configure this package to work under a multi-threaded environment, */
/* set _EX_THRD to TRUE and modify the k_var calls later on in the file. */
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 32.}
\fwendmacronotes
\fwendmacro



\fwsecb{2.3}{Macros for Global Variables}

This package uses three global variables --- \fwlit{\_ex\_curr}, \fwlit{\_ex\_id},
and \fwlit{\_ex\_info} --- which root the exception context stack, and store
information about the most recently raised exception. Unfortunately,
global variables such as these cause problems on multi-threaded
systems which require that separate instances of all global variables be
maintained for each thread.

The solution to this problem is to define the global variables as usual,
but to refer to them only through a set of lvalue-yielding macros. These
macros can then be configured to point either directly to a single set of
global variables (non-threaded system), or to thread-instance variables
(threaded system). This is the approach that has been taken in this package.
Accordingly the macros have been defined in this package static
parameter section. Both unthreaded and threaded versions appear below.

\fwbeginmacro
\fwmacroname{Macros for global variables}{17}\fwequals \fwodef \fwbtx[
#if !_EX_THRD
/* Non-threaded system macros simply point to variables. */
#define _EX_CURR _ex_curr
#define  EX_ID   ((p_ex_t) _ex_id)
#define _EX_ID   _ex_id
#define  EX_INFO _ex_info
#else
/* Threaded system macros translate to kernel calls.          */
/* To make this package work in a multi-threaded environment, */
/* set _EX_THRD to TRUE and modify these definitions.         */
/* Note: The kernel should initialize _EX_CURR to NULL.       */
#define _EX_CURR           (* ((_ex_cx_t *) k_var(51)))
#define  EX_ID   ((p_ex_t) (* ((p_ex_t   *) k_var(52))))
#define _EX_ID             (* ((p_ex_t   *) k_var(52)))
#define  EX_INFO           (* ((ptrint   *) k_var(53)))
#endif
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 32.}
\fwendmacronotes
\fwendmacro


(The 51, 52 and so on are just example variable numbers. By the way, each of
the three global variables will fit into a \fwlit{ptrint}.).

The global variable \fwlit{\_ex\_curr} is not supposed to be used by the client
so its symbol starts with \fwlit{\_}. \fwlit{EX\_ID} and \fwlit{EX\_INFO} are
intended to be visible to the client. However, the client is not allowed
to write to \fwlit{EX\_ID} and so two forms have been provided, one hidden
read/write form (\fwlit{\_EX\_ID}) and one read-only form (\fwlit{EX\_ID}). The type cast
in \fwlit{EX\_ID} is there solely to convert the value from an lvalue to an rvalue
(ANSI 6.3.4 (footnote 44)) so that the client can't write to it.

If these macros are changed to point to thread instance variables, be
sure to initialize the \fwlit{\_EX\_CURR} variable to \fwlit{NULL} (before performing
any exception actions) if you want unhandled exceptions to be correctly
detected. The other two variables don't need to be initialized.

Because these macros can translate to function calls, an
attempt has been made in the rest of the package to minimize references to
them (e.g. assign their values to temporary variables and manipulate them
rather than using the macro itself multiple times).


\fwseca{3}{Specification}

Because this package exports lots of macros, its specification (\fwlit{.h}) file
contains lots of stuff that should really be in the implementation file out
of sight of the client.  Luckily, FunnelWeb allows most of these implementation
details to be located in the implementation section of this FunnelWeb file,
leaving this section to describe, as cleanly as possible, only those components
in the specification file intended to be presented to the client.

In a nutshell, the package exports an exception type, and macros to raise
and catch exceptions.

\fwbeginmacro
\fwmacroname{Specification file}{18}\fwequals \fwodef \fwbtx[
]fwetx=%
\fwmacroname{Configuration header notice}{4}\fwbtx[
#ifndef _EX_DONE
#define _EX_DONE 1
]fwetx=%
\fwmacroname{Specification includes}{19}\fwbtx[
]fwetx=%
\fwmacroname{Exception type}{20}\fwbtx[
]fwetx=%
\fwmacroname{Hidden definitions}{32}\fwbtx[
]fwetx=%
\fwmacroname{Macro EX\_RAISE}{22}\fwbtx[
]fwetx=%
\fwmacroname{Macros for constructing exception blocks}{23}\fwbtx[
]fwetx=%
\fwmacroname{Function spec ex\_str}{30}\fwbtx[
]fwetx=%
\fwmacroname{Hidden function specs}{33}\fwbtx[
#endif
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 1.}
\fwendmacronotes
\fwendmacro



\fwsecb{3.1}{Specification Includes}

The specification file requires just the following includes. The \fwlit{style.h}
include file contains basic C style stuff. The ANSI standard \fwlit{setjmp.h}
include file (ANSI Standard Section 7.6) is required because the \fwlit{setjmp}
and \fwlit{longjmp} functions/macros are used to implement the package.

\fwbeginmacro
\fwmacroname{Specification includes}{19}\fwequals \fwodef \fwbtx[
#include "style.h"
#include <setjmp.h>
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 18.}
\fwendmacronotes
\fwendmacro



\fwsecb{3.2}{Exception Type}

Under this package, each exception is represented by an explicit object that
resides in memory. However, the package does not export this object type.
Like many C packages that export abstract types, this package exports only
a pointer-to-object type, the intent being that the client should only ever
manipulate the abstract objects through pointers. Thus, this package exports
a pointer-to-exception type \fwlit{p\_ex\_t}, but does not export a corresponding
exception type \fwlit{ex\_t}.

Most packages that export abstract objects by pointer type also export
functions to dynamically create and destroy the abstract objects. However,
in the case of exceptions there is no need for this. In fact there is a
positive need to create exceptions at compile time and bind them statically
(Dynamic creation would mean that an exception would have to be created before
being raised, which would be awkward to coordinate at run time).
So, instead of exporting a function to create an exception, this package
exports macros that allow the client to statically create (i.e. at compile
time) a new (hidden) exception object and, simultaneously, define a constant
pointer (of type \fwlit{p\_ex\_t}) that points to the new exception object, and
to which an identifier of the client programmer's choosing can be bound.
Here are the macros that do this.

\fwbeginmacro
\fwmacroname{Exception type}{20}\fwequals \fwodef \fwbtx[
]fwetx=%
\fwmacroname{Type p\_ex\_t}{40}\fwbtx[
#define EX_EXCEPT(NAME)      ]fwetx=%
\fwmacroname{Implementation of EX\_EXCEPT}{41}\fwbtx[
#define EX_EXPORT(NAME,DESC) ]fwetx=%
\fwmacroname{Implementation of EX\_EXPORT}{42}\fwbtx[
#define EX_LOCAL(NAME,DESC)  ]fwetx=%
\fwmacroname{Implementation of EX\_LOCAL}{43}\fwbtx[
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 18.}
\fwendmacronotes
\fwendmacro


The macros \fwlit{EX\_EXPORT} and \fwlit{EX\_LOCAL} each create a brand new exception
object. They can be called only at places in a module where variables can be
declared. The argument \fwlit{DESC} must be a one-line constant string that
describes the exception; it will be written out if the exception is involved
in some kind of error (e.g. if it propagates out of \fwlit{main()} and has to be
described to the user). The \fwlit{NAME} argument must be a program identifier
which will be the name of the pointer constant that will point to the
new exception. Macros \fwlit{EX\_EXPORT} and \fwlit{EX\_LOCAL} are identical except
that \fwlit{EX\_EXPORT} makes the constant pointer globally visible in the
program (i.e. it is present in the symbol table at link time), whereas
\fwlit{EX\_LOCAL} does not. If \fwlit{EX\_EXPORT} has been used, the constant pointer
to the exception can be made visible in other modules by adding an instance
of the \fwlit{EX\_EXCEPT} macro in the header file of the module containing the
exception definition.

Here is an example of a global exception declaration:

\fwbeginmacro
\fwmacroname{Example exception declarations}{21}\fwzero{}\fwequals \fwodef \fwbtx[
In sloth.h:
   EX_EXCEPT(sloth_exception);

In sloth.c:
   EX_EXPORT(sloth_exception,"Sloth exception");
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is NEVER invoked.}
\fwendmacronotes
\fwendmacro



\fwsecb{3.3}{Macro EX\_RAISE}

The macro \fwlit{EX\_RAISE} raises its argument exception. The argument exception
must be an expression evaluating to a pointer to the exception to be raised.
See a later section for the precise semantics of an exception raise.

This macro is syntactically equivalent to a compound statement. It is
guaranteed that its argument will be evaluated exactly once.

\fwbeginmacro
\fwmacroname{Macro EX\_RAISE}{22}\fwequals \fwodef \fwbtx[
#if _EX_FAST
#define EX_RAISE(P_EX) ]fwetx=%
\fwmacroname{Fast implementation of EX\_RAISE(P\_EX)}{45}\fwbtx[
#else
#define EX_RAISE(P_EX) ]fwetx=%
\fwmacroname{Safe implementation of EX\_RAISE(P\_EX)}{44}\fwbtx[
#endif
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 18.}
\fwendmacronotes
\fwendmacro



\fwsecb{3.4}{Exception Block Construct}

The only way to catch one or more exceptions is to declare a construct
that encloses the code that could raise the exceptions, along with the handler
code. This construct is called an exception block and is implemented using
a small set of preprocessor macros. Here they are:

\fwbeginmacro
\fwmacroname{Macros for constructing exception blocks}{23}\fwequals \fwodef \fwbtx[
#if _EX_FAST
#define EX_BEGIN    \
]fwetx=%
\fwmacroname{Fast implementation of EX\_BEGIN}{52}\fwbtx[
#define EX_FORGET      ]fwetx=%
\fwmacroname{Fast implementation of EX\_FORGET}{53}\fwbtx[
#define EX_WHEN(P_EX)  ]fwetx=%
\fwmacroname{Fast implementation of EX\_WHEN(P\_EX)}{54}\fwbtx[
#define EX_OTHERS      ]fwetx=%
\fwmacroname{Fast implementation of EX\_OTHERS}{55}\fwbtx[
#define EX_END         ]fwetx=%
\fwmacroname{Fast implementation of EX\_END}{56}\fwbtx[
#define EX_POP         ]fwetx=%
\fwmacroname{Fast implementation of EX\_POP}{57}\fwbtx[
#else
#define EX_BEGIN    \
]fwetx=%
\fwmacroname{Safe implementation of EX\_BEGIN}{46}\fwbtx[
#define EX_FORGET      ]fwetx=%
\fwmacroname{Safe implementation of EX\_FORGET}{47}\fwbtx[
#define EX_WHEN(P_EX)  ]fwetx=%
\fwmacroname{Safe implementation of EX\_WHEN(P\_EX)}{48}\fwbtx[
#define EX_OTHERS      ]fwetx=%
\fwmacroname{Safe implementation of EX\_OTHERS}{49}\fwbtx[
#define EX_END         ]fwetx=%
\fwmacroname{Safe implementation of EX\_END}{50}\fwbtx[
#define EX_POP         ]fwetx=%
\fwmacroname{Safe implementation of EX\_POP}{51}\fwbtx[
#endif
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 18.}
\fwendmacronotes
\fwendmacro


These macros must be used in accordance with the following syntax:

\fwbeginmacro
\fwmacroname{Syntax of exception block}{24}\fwzero{}\fwequals \fwodef \fwbtx[
compound_statement = other_forms_of_compound_statement | exception_block
                   | EX_POP
exception_block = "EX_BEGIN" c_code "EX_FORGET" { handler } "EX_END"
handler         = "EX_WHEN(" expression ")" c_code
handler         = "EX_OTHERS"
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is NEVER invoked.}
\fwendmacronotes
\fwendmacro


The argument to each instantiation of \fwlit{EX\_WHEN} must be an rvalue of type
\fwlit{p\_ex\_t}. It is guaranteed that this argument will be evaluated \fwemp{at most}
once.

The macro \fwlit{EX\_POP} should be invoked only from within the normal code of
an exception block.


\fwsecb{3.5}{Definition of Semantics}

This section contains a detailed English description of the semantics of the
exception constructs provided by this package. Normally this sort of
information would be laced throughout the package specification. However, in
this package, there are so many special cases that it was thought best to
collect all the tricky stuff in one place. The reader is advised to study
this section thoroughly, as a lack of knowledge about the precise semantics
of the exception construct can be very dangerous.

\fwemp{Basic semantics:} When control hits an exception block,
the code between \fwlit{EX\_BEGIN} and \fwlit{EX\_FORGET} (the
\fwemp{normal code}) is executed. If, during the execution of the normal code, no
exceptions propagate up to this construct then, upon completion of the normal
code, execution of the entire construct terminates. If, during the execution
of the normal code, an exception is raised (in the code or any function it
calls) that propagates up to this construct, control exits the normal code at
that point and is transferred to the code associated with the handler for
the exception raised (the \fwemp{handler code}). If there is no handler for the
exception raised, the exception is propagated to the next dynamically
enclosing handler in the dynamic chain. If there is a handler for the target
exception, the code associated with that handler is executed and the
construct terminates. If an exception propagates out of \fwlit{main()}, the
exception package bombs the program with an error message explaining what
has happened and printing out the description of the offending exception.

\fwemp{State of the function:} You may be wondering why the middle keyword
in the exception construct is \fwlit{EX\_FORGET}. The reason is that the ANSI
standard (ANSI 7.6.2.1) states: \fwemp{All accessible objects have values as of
the time longjmp was called, except that the values of objects of automatic
storage duration that are local to the function containing the invocation
of the corresponding setjmp macro that do not have volatile-qualified type
and have been changed between the setjmp invocation and longjmp call
are indeterminate.} These are strong words! Because this exception package
is implemented using \fwlit{setjmp} and \fwlit{longjmp}, these words mean that
following the raising of an exception, you cannot rely on the value of any
\fwlit{auto}matic variable that was modified within the normal code of an
exception construct before the exception was raised. The \fwlit{EX\_FORGET} syntax
has been designed to act as a continual reminder of this danger.

\fwemp{Direct exits from normal code:} Because the exception package
maintains an explicit stack of exception handling contexts, there are some
restrictions about how control can leave such constructs. ``Acceptable'' ways
of leaving the main code of an exception block are 1) reaching the end of the
block, and 2) raising an exception (handled or unhandled). However, control
can also exit the construct in four other ``unacceptable'' ways. These are
1) by executing a \fwlit{goto} out of the block,
2) by executing a \fwlit{return},
3) by executing an explicit \fwlit{longjmp},
4) by executing \fwlit{exit} or some other program terminating function
(actually this case does not matter as much as the program ends anyway).
To ensure that the exception package correctly maintains its stack of
live exception blocks, each instance of any of the four unacceptable ways
of exiting a block should be prededed by a call to \fwlit{EX\_POP}. Here is
an example of a correct explicit exception block termination.

\fwbeginmacro
\fwmacroname{Example of a correct direct exit from an exception block}{25}\fwzero{}\fwequals \fwodef \fwbtx[
EX_BEGIN
   add_char(buffer,'x');
   if (is_full(buffer)) {EX_POP; return TRUE;}
EX_FORGET
   EX_WHEN(buf_ful)
      return TRUE;
EX_END
return FALSE;
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is NEVER invoked.}
\fwendmacronotes
\fwendmacro


\fwlit{EX\_POP} can only be called from within the normal code of an exception
block.

\fwemp{No restrictions on exiting handler code:} By the time control reaches any
exception handler code, the current exception context has been popped, so
there are no constraints at all on exits from handler code. In the example
above, the \fwlit{return TRUE} from the normal code must be preceeded by a call
to \fwlit{EX\_POP}, but no such call is required for the \fwlit{return TRUE} in the
handler code. In fact, such a call would be erroneous. As soon
as control hits handler code it is guaranteed that the current context
has been popped.

\fwemp{Exception handler code can jump to other exception handlers:} Just place a
label inside one handler and a goto in another. This is useful where the code
in one handler is suitable for many exceptions. For example:

\fwbeginmacro
\fwmacroname{Example of goto in exception handler}{26}\fwzero{}\fwequals \fwodef \fwbtx[
EX_BEGIN
   add_char(buffer,'x');
EX_FORGET
   EX_WHEN(misc_1) goto doit;
   EX_WHEN(misc_2) goto doit;
   EX_WHEN(misc_3) goto doit;
   EX_WHEN(misc_4) goto doit;
   EX_WHEN(misc_5)
     doit:
        printf("Miscellaneous exception happened.\n");
        return FALSE;
EX_END
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is NEVER invoked.}
\fwendmacronotes
\fwendmacro


Because there are no restrictions on how handlers can exit, the \fwlit{gotos}
could have pointed outside the construct too.

\fwemp{Local variables:} Each normal code and handler code segment is actually
framed as a compound statement. This means that you can declare local
variables if desired. For example:

\fwbeginmacro
\fwmacroname{Example of local variables in an exception block}{27}\fwzero{}\fwequals \fwodef \fwbtx[
EX_BEGIN
   int result;
   result=add_char(buffer,'x');
   if (result > 10) {EX_POP; return TRUE;}
EX_FORGET
   EX_WHEN(buf_ful)
      string walrus = "An example string.\n";
      printf(walrus);
      return TRUE;
EX_END
return FALSE;
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is NEVER invoked.}
\fwendmacronotes
\fwendmacro


\fwemp{Exception blocks can be nested:} Functions can contain many exception
blocks. Exception blocks can even be nested. However, be very sure to obey
the other rules. Here is an example:

\fwbeginmacro
\fwmacroname{Example of nested exception handlers}{28}\fwzero{}\fwequals \fwodef \fwbtx[
EX_BEGIN
   add_char(buffer,'x');
   EX_BEGIN
      big_func();
      EX_FORGET
         EX_WHEN(buf_ful) printf("big_func raised buf_ful.\n");
   EX_END
EX_FORGET
   EX_WHEN(buf_ful) printf("add_char raised buf_ful.\n");
   EX_WHEN(sloth)   printf("either add_char or big_func raised sloth.\n");
EX_END
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is NEVER invoked.}
\fwendmacronotes
\fwendmacro


\fwemp{OTHERS handler:} The \fwlit{EX\_OTHERS} handler catches all exceptions.

\fwemp{Handler precedence:} The first handler that matches an exception
catches the exception. If more than one handler matches the same exception,
the first handler will be activated.

\fwemp{Re-raising an exception:} To re-raise an exception, simply
code the statement \fwlit{EX\_RAISE(EX\_ID);}.


\fwsecb{3.6}{Exception Information}

When an exception is raised, two symbols provide information about the
exception being raised. These symbols are macros and do not necessarily
translate to variable names. However, it is guaranteed that \fwlit{EX\_ID} will be
an rvalue (ANSI 6.2.2.1 (footnote 31)) of type \fwlit{p\_ex\_t}, and that \fwlit{EX\_INFO}
will behave like an modifiable lvalue (ANSI 6.2.2.1) of type \fwlit{ptrint} (see
the header file \fwlit{style.h} for this type). The declarations of these macros
appear in the static parameters section of this document.

Whenever an exception is raised, \fwlit{EX\_ID} contains the ID of the exception
being raised. This value persists until the next exception is raised.
This variable is only marginally useful in the current version of
this package, as each exception handler will always statically ``know'' the
exception that it has caught. In long and complex handlers though, the
capacity for self-reference that \fwlit{EX\_ID} provides enables such handlers
to be coded without hard-wiring the exception in question whenever it is
re-raised. This allows exceptions to be more easily renamed. The macro is
also useful because it allows exceptions to be dynamically re-raised from
code to which many handlers have been pointed to with \fwlit{goto}s. For example:

\fwbeginmacro
\fwmacroname{Example of use of EX\_ID}{29}\fwzero{}\fwequals \fwodef \fwbtx[
EX_BEGIN
   add_char(buffer,'x');
EX_FORGET
   EX_WHEN(misc_1) goto doit;
   EX_WHEN(misc_2) goto doit;
   EX_WHEN(misc_3) goto doit;
   EX_WHEN(misc_4) goto doit;
   EX_WHEN(misc_5)
     doit:
        printf("Miscellaneous exception happened.\n");
        EX_RAISE(EX_ID);
EX_END
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is NEVER invoked.}
\fwendmacronotes
\fwendmacro


\fwlit{EX\_ID} has been configured as an rvalue so that it cannot be written.
Thus, it is guaranteed always to contain the ID of the exception most recently
raised.

The variable \fwlit{EX\_INFO} is more under client control. It exists simply to
act as an abstract channel for code raising exceptions to communicate with
code catching exceptions. There are no rules for this value --- it can be
written to, or read from any piece of code at any time; make up your own
rules. The type of \fwlit{EX\_INFO} has been set to \fwlit{ptrint} so as to allow
any pointer or integer to be conveyed through the variable. This effectively
allows any amount of information to be passed.


\fwsecb{3.7}{Function ex\_str}

The function \fwlit{ex\_str} accepts a pointer to an exception and returns a
pointer to a constant static string being the one line description of the
exception that was provided when the exception was defined with \fwlit{EX\_LOCAL}
or \fwlit{EX\_EXPORT}.

\fwbeginmacro
\fwmacroname{Function spec ex\_str}{30}\fwequals \fwodef \fwbtx[EXPORT string ex_str P_((p_ex_t));]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 18.}
\fwendmacronotes
\fwendmacro



\fwsecb{3.8}{A Warning About Names}

This package exports a number of compile-time and link-time symbols that
pollute the symbol table and link table. This pollution is necessary because
this package relies significantly on exported macros that reference exported
variables. To reduce naming conflicts, nearly all exported names that are
supposed to be visible to the client commence with \fwlit{ex\_} and all exported
names that are supposed to be invisible to the client commence with \fwlit{\_ex}.
Please be careful to avoid names with these prefixes.


\fwsecb{3.9}{Glossary}

\fwlit{Abstract client} --- A client of this package about which no information
is known.

\fwlit{Catch} --- When an exception is raised, it propagates up the run-time
context stack until it encounters a corresponding handler at which point it
is said to have been caught.

\fwlit{Client} --- Any code that uses this package.

\fwlit{Exception} --- A dynamic non-local control-flow event.

\fwlit{Exception block} --- A special kind of anonymous block (called a compound
statement in C) containing exception handlers.

\fwlit{Exception description} --- A single-line string briefly describing the
exception. This string is printed out whenever an exception has to be
identified to the user.

\fwlit{Exception identifier} --- A program identifier that is bound to a constant
whose value is a pointer pointing to an exception object.

\fwlit{Exception handler} --- An exception/code binding that appears at the
end of an exception block and catches the specified exception should it
propagate to that level.

\fwlit{Direct exit} --- The termination of an exception block in a way that
bypasses the exception package (for example, by \fwlit{return} or explicit
\fwlit{longjmp}). The macro \fwlit{EX\_POP} should be called before all such exits.

\fwlit{Raise} --- An exception is raised by an \fwlit{EX\_RAISE} statement. Once
raised, an exception unwinds the stack until it encounters a handler for
the specific exception.


\fwseca{4}{Implementation}

This section describes the implementation of this package. The implementation
is short, but is rather messy because of the fast/safe alternatives, and
because of the fact that much of the functionality of the package is provided
in the \fwlit{.h} file. Much of that functionality has been deferred using
FunnelWeb macros to this section.

The implementation (\fwlit{.c}) file itself is fairly simply, consisting only
of some global variables and a few function definitions.

\fwbeginmacro
\fwmacroname{Implementation file}{31}\fwequals \fwodef \fwbtx[
]fwetx=%
\fwmacroname{Configuration header notice}{4}\fwbtx[
#include "except.h"
#include "as.h"
]fwetx=%
\fwmacroname{Global variables (.c)}{35}\fwbtx[
]fwetx=%
\fwmacroname{Function ex\_str}{58}\fwbtx[
]fwetx=%
\fwmacroname{Function ex\_bomb}{67}\fwbtx[
]fwetx=%
\fwmacroname{Function \_exrai}{60}\fwbtx[
]fwetx=%
\fwmacroname{Function \_expop}{69}\fwbtx[
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 2.}
\fwendmacronotes
\fwendmacro


All the real action happens in the definitions in the specification (\fwlit{.h})
file that are hidden from the client.

\fwbeginmacro
\fwmacroname{Hidden definitions}{32}\fwequals \fwodef \fwbtx[
]fwetx=%
\fwmacroname{Symbol \_EX\_FAST}{15}\fwbtx[
]fwetx=%
\fwmacroname{Symbol \_EX\_THRD}{16}\fwbtx[
]fwetx=%
\fwmacroname{Exception block context type}{34}\fwbtx[
]fwetx=%
\fwmacroname{Global variables (.h)}{36}\fwbtx[
]fwetx=%
\fwmacroname{Macros for global variables}{17}\fwbtx[
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 18.}
\fwendmacronotes
\fwendmacro


\fwbeginmacro
\fwmacroname{Hidden function specs}{33}\fwequals \fwodef \fwbtx[
]fwetx=%
\fwmacroname{Function spec \_exrai}{59}\fwbtx[
]fwetx=%
\fwmacroname{Function spec \_expop}{68}\fwbtx[
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 18.}
\fwendmacronotes
\fwendmacro



\fwsecb{4.1}{Overview and Data Structure Description}

This section gives an overview of the implementation of this package.

This package operates by maintaining an explicit stack of currently active
exception blocks. Whenever an exception block is entered (\fwlit{EX\_BEGIN}),
a \fwlit{setjmp} is executed and the resultant \fwlit{jmp\_buf} is inserted into a
stack node and pushed onto the stack. Whenever an exception block is exited
normally (\fwlit{EX\_END}), the stack node on the top of the stack is popped. When
an exception is raised, the top of the stack is popped off and a \fwlit{longjmp}
is executed to its context. The context then searches its handlers for a
handler for the exception raised. If it finds one, it executes it. If it
doesn't, it pops and \fwlit{longjmp}s the top of stack again. This goes on
until the exception is caught, or the stack is empty.

The stack is composed of a singly-linked list of records of the following
type:

\fwbeginmacro
\fwmacroname{Exception block context type}{34}\fwequals \fwodef \fwbtx[
typedef struct _ex_cxt_
  {
]fwetx=%
\fwmacroname{Header magic number field}{37}\fwbtx[
   jmp_buf          _ex_jmbf;  /* Exception block context.          */
   struct _ex_cxt_ *_ex_prev;  /* Pointer to previous stack record. */
]fwetx=%
\fwmacroname{Trailer magic number field}{38}\fwbtx[
  } _ex_cx_t;
]fwetx=%
\fwmacroname{Magic number symbols}{39}\fwbtx[
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 32.}
\fwendmacronotes
\fwendmacro


The sneaky part is that instead of storing this stack explicitly on the
heap, it is stored on the run-time stack itself. This is done by having the
\fwlit{EX\_BEGIN} macro create a compound statement containing a local
automatic variable of type \fwlit{\_ex\_cx\_t} which forms a node of the stack.
These nodes are threaded into a linked list that is rooted by the global
variable \fwlit{\_ex\_curr} which points to the node at the top of the stack,
or \fwlit{NULL} if the stack is empty. Two other hidden global variables
\fwlit{\_ex\_id} and \fwlit{\_ex\_info} store the exception id and the exception
information.


\fwsecc{4.1.1}{Global Variables}

This package requires three global variables to keep track of everything.
The variable \fwlit{\_ex\_curr} points to the context record on the top of the
stack, or \fwlit{NULL} if the stack is empty. The variable \fwlit{\_ex\_id} contains
a pointer to the exception most recently raised. The variable \fwlit{\_ex\_info}
is provided for the use of the client.

To enable this package (and its client code) to be converted over to a
multi-threaded system at a later date, these global variables are referred
to only through a set of macros. The macros are described in the static
parameters section of this document. They are called \fwlit{\_EX\_CURR},
\fwlit{EX\_ID}, \fwlit{\_EX\_ID}, \fwlit{EX\_INFO}.

\fwbeginmacro
\fwmacroname{Global variables (.c)}{35}\fwequals \fwodef \fwbtx[
#if !_EX_THRD
GLOVAR _ex_cx_t *_ex_curr = NULL;
GLOVAR p_ex_t    _ex_id;
GLOVAR ptrint    _ex_info;
#endif
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 31.}
\fwendmacronotes
\fwendmacro


Here is the version of these variables that appears in the header file.

\fwbeginmacro
\fwmacroname{Global variables (.h)}{36}\fwequals \fwodef \fwbtx[
#if !_EX_THRD
extern _ex_cx_t *_ex_curr;
extern p_ex_t    _ex_id;
extern ptrint    _ex_info;
#endif
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 32.}
\fwendmacronotes
\fwendmacro



\fwsecc{4.1.2}{Magic Numbers}

In order to detect corruptions in exception context records, two magic
number fields have been placed at the start and end of the record. In C, there
are hundreds of ways for corruptions to occur, but in particular, in this
package, if a client exits an exception context without first popping it,
it is quite likely that the context will be ``run over'' by stack frames of
functions called later. If the context is then invoked, the program will
crash. The following magic number fields greatly improve the chances of
detecting such corruptions.

\fwbeginmacro
\fwmacroname{Header magic number field}{37}\fwequals \fwodef \fwbtx[#if !_EX_FAST
   ulong _ex_mag1;  /* Header magic number. */
#endif]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 34.}
\fwendmacronotes
\fwendmacro


\fwbeginmacro
\fwmacroname{Trailer magic number field}{38}\fwequals \fwodef \fwbtx[#if !_EX_FAST
   ulong _ex_mag2;  /* Trailer magic number. */
#endif]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 34.}
\fwendmacronotes
\fwendmacro


\fwbeginmacro
\fwmacroname{Magic number symbols}{39}\fwequals \fwodef \fwbtx[
#define _EX_MAG1 0xFB8A5D30
#define _EX_MAG2 0x09F2E7A2]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 34.}
\fwendmacronotes
\fwendmacro



\fwsecb{4.2}{Exception type}

Here is the definition of the pointer-to-exception type. Normally, a hidden
exception type would be declared to which the pointer type would point, but as
exceptions have only a single attribute, their description string, it makes
sense simply to declare the pointer type to be \fwlit{string} type (pointer to
char).

\fwbeginmacro
\fwmacroname{Type p\_ex\_t}{40}\fwequals \fwodef \fwbtx[typedef string p_ex_t;]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 20.}
\fwendmacronotes
\fwendmacro



\fwsecb{4.3}{Macros for Declaring and Defining Exceptions}

The three exception declaration macros make use of the fact that \fwlit{p\_ex\_t}
is really just a string pointer. There is a slight danger that a too-clever
C compiler might overlap two strings for which one is a non-strict suffix
of the other. However, this is considered unlikely.

\fwbeginmacro
\fwmacroname{Implementation of EX\_EXCEPT}{41}\fwequals \fwodef \fwbtx[extern const p_ex_t NAME]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 20.}
\fwendmacronotes
\fwendmacro

\fwbeginmacro
\fwmacroname{Implementation of EX\_EXPORT}{42}\fwequals \fwodef \fwbtx[       const p_ex_t NAME = DESC]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 20.}
\fwendmacronotes
\fwendmacro

\fwbeginmacro
\fwmacroname{Implementation of EX\_LOCAL}{43}\fwequals \fwodef \fwbtx[static const p_ex_t NAME = DESC]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 20.}
\fwendmacronotes
\fwendmacro



\fwsecb{4.4}{Macro for Raising Exceptions}

Two forms of the \fwlit{EX\_RAISE} macro are given. The first simply calls
\fwlit{\_exrai} which performs lots of checks before raising the argument exception.
The fast form does not perform any checking --- it just performs the
essential operations of setting the ID and executing the \fwlit{longjmp}.

\fwbeginmacro
\fwmacroname{Safe implementation of EX\_RAISE(P\_EX)}{44}\fwequals \fwodef \fwbtx[{_exrai(P_EX);}]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 22.}
\fwendmacronotes
\fwendmacro


\fwbeginmacro
\fwmacroname{Fast implementation of EX\_RAISE(P\_EX)}{45}\fwequals \fwodef \fwbtx[{_EX_ID = (P_EX); longjmp(_EX_CURR->_ex_jmbf,NON_ZERO);}]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 22.}
\fwendmacronotes
\fwendmacro



\fwsecb{4.5}{Exception Block Macros (Safe)}

The exception block macros are messy and deserve some explanation.
These macros operate as a coherent whole, so it is probably best to read
them through a few times to see how they interact, rather than attempting
to understand each one independently.  Two versions of the exception block
macros are given --- the safe version and the fast version. The safe version
is described first.

The \fwlit{EX\_BEGIN} macro sets the stage for the entire exception block by
starting a compound statement, declaring a local variable for the stack
node (\fwlit{\_ex\_cxlc}), initializing its magic checking numbers, pushing it onto
the stack, and finally saving the current execution context in the \fwlit{\_ex\_jmbf}
field of the newly created stack node. This work has to be done in this macro
as most of the operations require direct access to the local context. Not much
checking can be done here either as we have no way of cross checking the value
of \fwlit{\_EX\_CURR} upon entry. The open \fwlit{if} statement encloses the entire
normal code of the exception block.

\fwbeginmacro
\fwmacroname{Safe implementation of EX\_BEGIN}{46}\fwequals \fwodef \fwbtx[{_ex_cx_t _ex_cxlc;              \
 _ex_cxlc._ex_mag1 = _EX_MAG1;   \
 _ex_cxlc._ex_mag2 = _EX_MAG2;   \
 _ex_cxlc._ex_prev = _EX_CURR;   \
 _EX_CURR          = &_ex_cxlc;  \
 if (!setjmp(_ex_cxlc._ex_jmbf)) { ]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 23.}
\fwendmacronotes
\fwendmacro


At the point of forgetting, we need to terminate the compound statement
for the normal code, pop the current exception context and then test the
currently live exception against the candidate handlers. This is most
simply performed with a cascaded \fwlit{if} statement. The \fwlit{if} statement
has to start with a \fwlit{FALSE} branch so as to establish the syntactic
context for the first \fwlit{EX\_WHEN} macro.

An earlier version of this package that used integers to represent exceptions
used a \fwlit{switch} statement instead of an \fwlit{if} chain. A \fwlit{switch} statement
is actually preferable to an \fwlit{if} chain because \fwlit{switch}es prohibit
duplicate labels. However, \fwlit{switch}es had to be abandoned because when the
package was changed over so that it used pointers as exception ids, it was
noticed that K\&R78 section 9.7 says that the argument to \fwlit{switch} must be of
type \fwlit{int}. K\&R88 (section A9.4) and ANSI (section 6.6.4.2) weaken this to
include all integral types, but still preclude pointers. So an \fwlit{if} chain
had to be used.

\fwbeginmacro
\fwmacroname{Safe implementation of EX\_FORGET}{47}\fwequals \fwodef \fwbtx[;EX_POP} else {EX_POP; if (FALSE) {]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 23.}
\fwendmacronotes
\fwendmacro


The start of each handler in the exception block is marked by a call to the
\fwlit{EX\_WHEN} macro. All it does is add an extra clause onto the \fwlit{if} chain.

\fwbeginmacro
\fwmacroname{Safe implementation of EX\_WHEN(P\_EX)}{48}\fwequals \fwodef \fwbtx[} else if ((P_EX) == (EX_ID)) {]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 23.}
\fwendmacronotes
\fwendmacro


The \fwlit{EX\_OTHERS} macro is also easily implemented (but, like \fwlit{EX\_FORGET},
could conceivably provoke some inconvenient warnings from \fwlit{lint}.

\fwbeginmacro
\fwmacroname{Safe implementation of EX\_OTHERS}{49}\fwequals \fwodef \fwbtx[} else if (TRUE) {]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 23.}
\fwendmacronotes
\fwendmacro


To end the construct, we terminate the current handler, re-raise the
currently live exception if it has not already been caught, and terminate
the \fwlit{else} of \fwlit{EX\_FORGET} and the outer braces of the entire construct.

\fwbeginmacro
\fwmacroname{Safe implementation of EX\_END}{50}\fwequals \fwodef \fwbtx[} else _exrai(EX_ID); }}]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 23.}
\fwendmacronotes
\fwendmacro


Popping the current exception context is easily achieved with a function call.
Note: The reference to \fwlit{\_ex\_cxlc} will simply not compile if there
isn't a current context. This correctly precludes the use of this macro
outside an exception block. It also guarantees that the argument to \fwlit{\_expop}
will be a pointer to the context record of the innermost statically-enclosing
exception block.

\fwbeginmacro
\fwmacroname{Safe implementation of EX\_POP}{51}\fwequals \fwodef \fwbtx[{_expop(&_ex_cxlc);}]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 23.}
\fwendmacronotes
\fwendmacro



\fwsecb{4.6}{Fast, Inline Versions of the Exception Block Macros}

Here are the fast, inline versions of the exported macros. This version
of the macros operates in exactly the same way as the other version except
that no checking is performed whatsoever. This version of the macros
performs everything on the spot, without calling any support functions at all.

\fwbeginmacro
\fwmacroname{Fast implementation of EX\_BEGIN}{52}\fwequals \fwodef \fwbtx[{_ex_cx_t _ex_cxlc;              \
 _ex_cxlc._ex_prev = _EX_CURR;   \
 _EX_CURR          = &_ex_cxlc;  \
 if (!setjmp(_ex_cxlc._ex_jmbf)) { ]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 23.}
\fwendmacronotes
\fwendmacro


\fwbeginmacro
\fwmacroname{Fast implementation of EX\_FORGET}{53}\fwequals \fwodef \fwbtx[;EX_POP} else {EX_POP; if (FALSE) {]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 23.}
\fwendmacronotes
\fwendmacro

\fwbeginmacro
\fwmacroname{Fast implementation of EX\_WHEN(P\_EX)}{54}\fwequals \fwodef \fwbtx[} else if ((P_EX) == (EX_ID)) {]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 23.}
\fwendmacronotes
\fwendmacro

\fwbeginmacro
\fwmacroname{Fast implementation of EX\_OTHERS}{55}\fwequals \fwodef \fwbtx[} else if (TRUE) {]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 23.}
\fwendmacronotes
\fwendmacro


\fwbeginmacro
\fwmacroname{Fast implementation of EX\_END}{56}\fwequals \fwodef \fwbtx[} else longjmp(_EX_CURR->_ex_jmbf,NON_ZERO); }}]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 23.}
\fwendmacronotes
\fwendmacro


\fwbeginmacro
\fwmacroname{Fast implementation of EX\_POP}{57}\fwequals \fwodef \fwbtx[{_EX_CURR = _EX_CURR->_ex_prev;}]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 23.}
\fwendmacronotes
\fwendmacro



\fwsecb{4.7}{Function ex\_str}

The function \fwlit{ex\_str} is easily implemented. Because exceptions are just
pointers to strings, all it has to do is return its argument!

\fwbeginmacro
\fwmacroname{Function ex\_str}{58}\fwequals \fwodef \fwbtx[
EXPORT string ex_str (p_ex) p_ex_t p_ex; {return p_ex;}]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 31.}
\fwendmacronotes
\fwendmacro



\fwsecb{4.8}{Support Functions}

Although most of what this package exports is macros, some of the macros
translate into calls to the support functions described in this section.
Functions have been used for operations that are particularly long-winded.


\fwsecc{4.8.1}{Function \_exrai}

The function \fwlit{\_exrai} raises an exception. This function performs
all the grunt work for the \fwlit{EX\_RAISE} macro, which merely translates to a
call of this function. The function specification appears in the header file
but is not supposed to be seen by the client.

\fwbeginmacro
\fwmacroname{Function spec \_exrai}{59}\fwequals \fwodef \fwbtx[EXPORT void _exrai P_((p_ex_t));]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 33.}
\fwendmacronotes
\fwendmacro


\fwbeginmacro
\fwmacroname{Function \_exrai}{60}\fwequals \fwodef \fwbtx[
EXPORT void _exrai (p_ex)
p_ex_t p_ex;
{
#if _EX_FAST
 as_bomb("_exrai: This function should not be called with _EX_FAST==TRUE.");
#else
 ]fwetx=%
\fwmacroname{Take a copy of \_EX\_CURR in p\_curr}{61}\fwbtx[
 ]fwetx=%
\fwmacroname{Set the exception ID}{62}\fwbtx[
 ]fwetx=%
\fwmacroname{Bomb if the stack is empty}{63}\fwbtx[
 ]fwetx=%
\fwmacroname{Bomb if the target context is not on the stack}{64}\fwbtx[
 ]fwetx=%
\fwmacroname{Bomb if the target context is corrupted}{65}\fwbtx[
 ]fwetx=%
\fwmacroname{Raise the exception}{66}\fwbtx[
#endif
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 31.}
\fwendmacronotes
\fwendmacro


This function refers to the value of \fwlit{\_EX\_CURR} lots of times. However,
\fwlit{\_EX\_CURR} could be a function call. To avoid excessive use of this
variable, we take a copy of its value in \fwlit{p\_curr}.

\fwbeginmacro
\fwmacroname{Take a copy of \_EX\_CURR in p\_curr}{61}\fwmany{}\fwequals \fwodef \fwbtx[_ex_cx_t * p_curr = _EX_CURR;]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definitions 60 and 69.}
\fwendmacronotes
\fwendmacro


We set the global exception ID variable \fwlit{\_EX\_ID} \fwemp{before} performing
all the sanity checks so that if one of them fails, the current exception
can be printed out by \fwlit{ex\_bomb}.

\fwbeginmacro
\fwmacroname{Set the exception ID}{62}\fwequals \fwodef \fwbtx[_EX_ID = p_ex;]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 60.}
\fwendmacronotes
\fwendmacro


If the context stack is empty then there is no handler to catch the exception
and we have to bomb the program.

\fwbeginmacro
\fwmacroname{Bomb if the stack is empty}{63}\fwequals \fwodef \fwbtx[
if (p_curr == NULL) {as_wl("_exrai: Unhandled exception."); ex_bomb();}]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 60.}
\fwendmacronotes
\fwendmacro


If the target context is lower down in memory than the stack frame of \fwemp{this}
function (\fwlit{\_exrai}), then because stacks nearly always grow downwards, it
is almost certain that a context was not popped when it should have been.
Strictly speaking, this test is non-portable. However, in
practice, stacks grow downward in the address space on nearly all machines,
and it's such a powerful check, it seems worth the potential portability
problems.

\fwbeginmacro
\fwmacroname{Bomb if the target context is not on the stack}{64}\fwequals \fwodef \fwbtx[
if (UWIDE(&p_curr) > UWIDE(&p_curr->_ex_jmbf))
  {
   as_wl("_exrai: Target exception context is no longer legitimate.");
   as_wl("        Exception context resides beneath the top of stack.");
   as_wl("        This means that earlier on, control must have left an");
   as_wl("        exception context without first popping its handler.");
   as_wl("        Look for jumps out of exception contexts that are not");
   as_wl("        immediately preceded by calls to EX_POP.");
   ex_bomb();
  }]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 60.}
\fwendmacronotes
\fwendmacro


Check the target context for corruptions. There is no point doing a \fwlit{longjmp}
to a corrupted context!

\fwbeginmacro
\fwmacroname{Bomb if the target context is corrupted}{65}\fwequals \fwodef \fwbtx[
if ((p_curr->_ex_mag1 != _EX_MAG1) || (p_curr->_ex_mag2 != _EX_MAG2))
  {
   as_wl("_exrai: Target exception context has been corrupted. This could");
   as_wl("        be because an exception context wasn't popped, or it");
   as_wl("        could be just a common garden-variety C corruption :-)");
   ex_bomb();
  }]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 60.}
\fwendmacronotes
\fwendmacro


Actually raising the exception is the easy part! All that is required is a
\fwlit{longjmp}.

\fwbeginmacro
\fwmacroname{Raise the exception}{66}\fwequals \fwodef \fwbtx[longjmp(p_curr->_ex_jmbf,NON_ZERO);]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 60.}
\fwendmacronotes
\fwendmacro



\fwsecc{4.8.2}{Function ex\_bomb}

The function \fwlit{ex\_bomb} writes out a description of the most recently
raised exception and then bombs the program. This function is used by
\fwlit{\_exrai}.

\fwbeginmacro
\fwmacroname{Function ex\_bomb}{67}\fwequals \fwodef \fwbtx[
LOCAL void ex_bomb P_((void));
LOCAL void ex_bomb ()
{
 char s[100];
 as_wr("        Exception desc is : \""); as_wr(EX_ID); as_wl("\".");
 as_wr("        Exception id   is : ");
 sprintf(s,"%lu (= %lX)",ULONG(EX_ID),ULONG(EX_ID)); as_wl(s);
 as_wr("        Exception info is : ");
 sprintf(s,"%lu (= %lX)",ULONG(EX_INFO),ULONG(EX_INFO)); as_wl(s);
 as_bomb("Aborting program after exception error.");
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 31.}
\fwendmacronotes
\fwendmacro



\fwsecc{4.8.3}{Function \_expop}

The function \fwlit{\_expop} pops the current exception block from the context
stack. Before doing this, it performs a few checks. To assist it with its
checks, the caller must pass a pointer to the current context record
in the first parameter. This can always be done by the caller directly
(without referencing \fwlit{\_EX\_CURR}) because popping is only supposed to take
place within the static context of an enclosing exception block.

\fwbeginmacro
\fwmacroname{Function spec \_expop}{68}\fwequals \fwodef \fwbtx[EXPORT void _expop P_((_ex_cx_t *));]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 33.}
\fwendmacronotes
\fwendmacro


\fwbeginmacro
\fwmacroname{Function \_expop}{69}\fwequals \fwodef \fwbtx[
EXPORT void _expop (p_check)
_ex_cx_t *p_check;
{
#if _EX_FAST
 as_bomb("_exrai: This function should not be called with _EX_FAST==TRUE.");
#else
 ]fwetx=%
\fwmacroname{Take a copy of \_EX\_CURR in p\_curr}{61}\fwbtx[
 ]fwetx=%
\fwmacroname{Bomb if the current context is not the top of stack context}{70}\fwbtx[
 ]fwetx=%
\fwmacroname{Bomb if current context is corrupted}{71}\fwbtx[
 ]fwetx=%
\fwmacroname{Zap the current context}{72}\fwbtx[
 ]fwetx=%
\fwmacroname{Pop the context}{73}\fwbtx[
#endif
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 31.}
\fwendmacronotes
\fwendmacro


The first check test is to make sure that the context about to be popped is
the current context --- the one statically enclosing the pop call.

\fwbeginmacro
\fwmacroname{Bomb if the current context is not the top of stack context}{70}\fwequals \fwodef \fwbtx[
if (p_curr != p_check)
  {
   if (p_curr == NULL)
      as_bomb("_expop: Context stack is empty.");
   else
      as_bomb("_expop: Top of context stack is not the current context.");
  }
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 69.}
\fwendmacronotes
\fwendmacro


The second check tests the current context (the one about to be popped) to
make sure that it isn't corrupted. If it is, then the program should be
bombed.

\fwbeginmacro
\fwmacroname{Bomb if current context is corrupted}{71}\fwequals \fwodef \fwbtx[
if ((p_curr->_ex_mag1 != _EX_MAG1) || (p_curr->_ex_mag2 != _EX_MAG2))
  {
   as_wl("_ex_rai: Target exception context has been corrupted. This could");
   as_wl("         be because an exception context wasn't popped, or it");
   as_wl("         could be just a common garden-variety C corruption :-)");
   as_bomb("Aborting program after exception error.");
  }
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 69.}
\fwendmacronotes
\fwendmacro


Before popping the current context, we need to zap its magic numbers so that
they don't float around in stack memory where they might cause some future
magic number test to succeed when it should have failed.

\fwbeginmacro
\fwmacroname{Zap the current context}{72}\fwequals \fwodef \fwbtx[
p_curr->_ex_mag1 = ~_EX_MAG1;
p_curr->_ex_mag2 = ~_EX_MAG2;
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 69.}
\fwendmacronotes
\fwendmacro


Having checked and zapped the context, popping it is easy!

\fwbeginmacro
\fwmacroname{Pop the context}{73}\fwequals \fwodef \fwbtx[_EX_CURR = p_curr->_ex_prev;]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 69.}
\fwendmacronotes
\fwendmacro



\fwseca{5}{Test Program}

This section provides a test program which can be used to test the exceptions
package. The program provides nine success tests and nine failure tests.
The success tests do not cause the program to terminate, and so can all
be performed in a single run. However, each failure test causes the
program to bomb with an assertion error, and so the failure tests must
be performed separately as nine separate invocations of the test
program. At the end of this testing, the user can have a high degree of
confidence that the package is working.

Each of the eighteen tests is embodied in a separate function.
The global boolean variable \fwlit{flag} is a miscellaneous temporary variable
which is usually used to tell if an exception has fired.

\fwbeginmacro
\fwmacroname{Test program file}{74}\fwequals \fwodef \fwbtx[
]fwetx=%
\fwmacroname{Configuration header notice}{4}\fwbtx[

#include "style.h"
#include "except.h"
#include "as.h"

EX_LOCAL(sloth_ex,"Sloth exception");
EX_LOCAL(walrus_ex,"Walrus exception");

GLOVAR bool flag;

]fwetx=%
\fwmacroname{Function sc01}{75}\fwbtx[
]fwetx=%
\fwmacroname{Function sc02}{76}\fwbtx[
]fwetx=%
\fwmacroname{Function sc03}{77}\fwbtx[
]fwetx=%
\fwmacroname{Function sc04}{78}\fwbtx[
]fwetx=%
\fwmacroname{Function sc05}{79}\fwbtx[
]fwetx=%
\fwmacroname{Function sc06}{80}\fwbtx[
]fwetx=%
\fwmacroname{Function sc07}{81}\fwbtx[
]fwetx=%
\fwmacroname{Function sc08}{82}\fwbtx[
]fwetx=%
\fwmacroname{Function sc09}{83}\fwbtx[

]fwetx=%
\fwmacroname{Function fa01}{84}\fwbtx[
]fwetx=%
\fwmacroname{Function fa02}{85}\fwbtx[
]fwetx=%
\fwmacroname{Function fa03}{86}\fwbtx[
]fwetx=%
\fwmacroname{Function fa04}{87}\fwbtx[
]fwetx=%
\fwmacroname{Function fa05}{88}\fwbtx[
]fwetx=%
\fwmacroname{Function fa06}{89}\fwbtx[
]fwetx=%
\fwmacroname{Function fa07}{90}\fwbtx[
]fwetx=%
\fwmacroname{Function fa08}{91}\fwbtx[
]fwetx=%
\fwmacroname{Function fa09}{92}\fwbtx[

main()
{
 char ch;

 printf("Test Program for the EXCEPT Package\n");
 printf("===================================\n");
 printf("This test program provides a number of different tests. Because\n");
 printf("some tests provoke the package to bomb on purpose, this test\n");
 printf("program must be run a number of times, once for each test.\n");
 printf("The 0 test performs a group of tests that are not supposed to\n");
 printf("fail. The 1..9 tests each perform a test that is supposed to\n");
 printf("bomb the program if the test succeeds. The 0 test should be run\n");
 printf("with the package compiled with both _EX_FAST==FALSE and\n");
 printf("_EX_FAST==TRUE. The 1..9 tests should use only _EX_FAST==FALSE.\n");
 printf("\n");
 if (_EX_FAST)
 printf("Current value of EX_FAST == TRUE.\n");
 else
 printf("Current value of EX_FAST == FALSE.\n");
 printf("\n");
 printf("Enter 0 for success tests, or 1..9 for one of nine fail tests>");
 ch=getchar(); printf("\n");
 if (ch == '0')
   {
    printf("Success Tests\n");
    printf("-------------\n");
    printf("The following tests (sc01..sc09) test the normal features\n");
    printf("the exceptions package. You should see nine success lines\n");
    printf("appear on the screen. If the package bombs during this test,\n");
    printf("then something is wrong and should be fixed.\n");
    printf("\n");
    sc01();
    sc02();
    sc03();
    sc04();
    sc05();
    sc06();
    sc07();
    sc08();
    sc09();
    printf("\n");
    printf("All of the success tests SUCCEEDED.\n");
   }
 else
   {
    if (_EX_FAST)
      {
       as_wl("Error in test configuration. An attempt was made to perform");
       as_wl("a 1..9 test with _EX_FAST==TRUE. This does not make sense as");
       as_wl("these tests test the error checking capability of the package");
       as_wl("and _EX_FAST=TRUE has all error checking turned off!");
       as_bomb("Please recompile with _EX_FAST==FALSE and try again.");
      }
    switch (ch)
     {
      case '1': fa01();
      case '2': fa02();
      case '3': fa03();
      case '4': fa04();
      case '5': fa05();
      case '6': fa06();
      case '7': fa07();
      case '8': fa08();
      case '9': fa09();
      default:
         printf("\nCharacter entered was not 0..9. Aborting...\n");
     }
    }
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 3.}
\fwendmacronotes
\fwendmacro



\fwsecb{5.1}{Function sc01} This test checks to make sure that exception blocks operate correctly
when no exceptions are raised.

\fwbeginmacro
\fwmacroname{Function sc01}{75}\fwequals \fwodef \fwbtx[
LOCAL void sc01 P_((void));
LOCAL void sc01 ()
{
 printf("Test SC01: Exception block with no exceptions raised.\n");

 /* The NULL exception block should be OK. */
 EX_BEGIN
 EX_FORGET
 EX_END

 /* Now put some code in the normal section. */
 flag=FALSE;
 EX_BEGIN
    flag=TRUE;
 EX_FORGET
 EX_END
 as_cold(flag,"sc01: First flag block test failed.");

 /* Make sure the EX_OTHERS branch only applies to exceptions. */
 flag=FALSE;
 EX_BEGIN
    flag=TRUE;
 EX_FORGET
    EX_OTHERS
       as_bomb("sc01: Raise failed.");
 EX_END
 as_cold(flag,"sc01: Second flag block test failed.");
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 74.}
\fwendmacronotes
\fwendmacro



\fwsecb{5.2}{Function sc02} This test tests to make sure that an exception raised within an exception
block can be caught by that block.

\fwbeginmacro
\fwmacroname{Function sc02}{76}\fwequals \fwodef \fwbtx[
LOCAL void sc02 P_((void));
LOCAL void sc02 ()
{
 printf("Test SC02: Exception caught within immediate block.\n");
 flag = FALSE;
 EX_BEGIN
    EX_RAISE(sloth_ex);
    as_bomb("sc02: Raise failed.");
 EX_FORGET
    EX_WHEN(sloth_ex) flag=TRUE;
 EX_END
 as_cold(flag,"sc02: Exception was not caught by local block.");
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 74.}
\fwendmacronotes
\fwendmacro



\fwsecb{5.3}{Function sc03} This test tests the \fwlit{EX\_OTHERS} feature.

\fwbeginmacro
\fwmacroname{Function sc03}{77}\fwequals \fwodef \fwbtx[
LOCAL void sc03 P_((void));
LOCAL void sc03 ()
{
 printf("Test SC03: Exception is caught by OTHERS clause.\n");
 flag = FALSE;
 EX_BEGIN
    EX_RAISE(sloth_ex);
    as_bomb("sc03: Raise failed.");
 EX_FORGET
    EX_OTHERS flag=TRUE;
 EX_END
 as_cold(flag,"sc03: Exception was not caught by EX_OTHERS clause.");
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 74.}
\fwendmacronotes
\fwendmacro



\fwsecb{5.4}{Function sc04} This test tests nested exception blocks.

\fwbeginmacro
\fwmacroname{Function sc04}{78}\fwequals \fwodef \fwbtx[
LOCAL void sc04 P_((void));
LOCAL void sc04 ()
{
 printf("Test SC04: Exception is caught by nested exception block.\n");

 /* Try a simple nested handler. */
 flag=FALSE;
 EX_BEGIN
    EX_BEGIN
       EX_RAISE(sloth_ex);
       as_bomb("sc04: Raise failed (1).");
    EX_FORGET
       EX_WHEN(walrus_ex)
          as_bomb("sc04: Walrus exception caught (1).");
    EX_END
 EX_FORGET
    EX_WHEN(sloth_ex) flag=TRUE;
    EX_WHEN(walrus_ex) as_bomb("sc04: Walrus exception caught (x).");
 EX_END
 as_cold(flag,"sc04: First nested test failed.");

 /* Test a re-raise. */
 flag=FALSE;
 EX_BEGIN
    EX_BEGIN
       EX_RAISE(sloth_ex);
       as_bomb("sc04: Raise failed (2).");
    EX_FORGET
       EX_WHEN(sloth_ex)
          EX_RAISE(walrus_ex)
          as_bomb("sc04: Raise failed (3).");
       EX_WHEN(walrus_ex)
          as_bomb("sc04: Walrus exception caught (2).");
    EX_END
 EX_FORGET
    EX_WHEN(sloth_ex)
       as_bomb("sc04: Sloth exception escaped.");
    EX_WHEN(walrus_ex)
       flag=TRUE;
 EX_END
 as_cold(flag,"sc04: Second nested test failed.");
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 74.}
\fwendmacronotes
\fwendmacro



\fwsecb{5.5}{Function sc05} This test tests whether \fwlit{EX\_OTHERS} can successfully re-raise an
exception.

\fwbeginmacro
\fwmacroname{Function sc05}{79}\fwequals \fwodef \fwbtx[
LOCAL void sc05 P_((void));
LOCAL void sc05 ()
{
 STAVAR bool flag2;
 printf("Test SC05: Single OTHERS handler reraises current exception.\n");
 flag=FALSE;
 flag2=FALSE;
 EX_BEGIN
    EX_BEGIN
       EX_RAISE(sloth_ex);
       as_bomb("sc05: Raise failed (2).");
    EX_FORGET
       EX_OTHERS
          flag=TRUE;
          EX_RAISE(EX_ID);
          as_bomb("sc05: Raise failed (3).");
    EX_END
 EX_FORGET
    EX_WHEN(sloth_ex)
       flag2=TRUE;
    EX_OTHERS
       as_bomb("sc05: Exception escaped.");
 EX_END
 as_cold(flag ,"sc05: OTHERS test failed (1).");
 as_cold(flag2,"sc05: OTHERS test failed (2).");
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 74.}
\fwendmacronotes
\fwendmacro



\fwsecb{5.6}{Function sc06}


\fwbeginmacro
\fwmacroname{Function sc06}{80}\fwequals \fwodef \fwbtx[
LOCAL void sc06 P_((void));
LOCAL void sc06 ()
{
 printf("Test SC06: Handlers all GOTO same code.\n");
 flag=FALSE;
 EX_BEGIN
    EX_RAISE(sloth_ex);
    as_bomb("sc06: Raise failed.");
 EX_FORGET
    EX_WHEN(sloth_ex) goto handle;
    EX_WHEN(walrus_ex)
       as_bomb("sc06: Walrus exception went off.");
       handle:
       flag=TRUE;
    EX_OTHERS
       as_bomb("sc06: Exception escaped to OTHERS.");
 EX_END
 as_cold(flag,"sc06: GOTO test failed.");
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 74.}
\fwendmacronotes
\fwendmacro



\fwsecb{5.7}{Function sc07} This test simply checks that EX\_INFO can be written to and read from.

\fwbeginmacro
\fwmacroname{Function sc07}{81}\fwequals \fwodef \fwbtx[
LOCAL void sc07 P_((void));
LOCAL void sc07 ()
{
 printf("Test SC07: Exercise EX_INFO.\n");
 EX_INFO = 3;
 as_cold(EX_INFO == 3,"sc07: EX_INFO test failed.");
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 74.}
\fwendmacronotes
\fwendmacro



\fwsecb{5.8}{Function sc08} This test simply checks that the \fwlit{ex\_str} function is working.

\fwbeginmacro
\fwmacroname{Function sc08}{82}\fwequals \fwodef \fwbtx[
LOCAL void sc08 P_((void));
LOCAL void sc08 ()
{
 printf("Test SC08: Exercise ex_str.\n");
 as_cold(ex_str(sloth_ex) == sloth_ex,"sc08: Failed.");
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 74.}
\fwendmacronotes
\fwendmacro



\fwsecb{5.9}{Function sc09} Test the legitimate use of \fwlit{EX\_POP}.

\fwbeginmacro
\fwmacroname{Function sc09}{83}\fwequals \fwodef \fwbtx[
LOCAL void sc09 P_((void));
LOCAL void sc09 ()
{
 printf("Test SC09: Test EX_POP.\n");
 flag=FALSE;
 EX_BEGIN
    EX_BEGIN
       EX_POP; goto finish;
    EX_FORGET
       EX_WHEN(sloth_ex) as_bomb("sc09: Inner catcher caught the sloth.");
    EX_END
    finish: EX_RAISE(sloth_ex);
 EX_FORGET
    EX_WHEN(sloth_ex) flag=TRUE;
 EX_END
 as_cold(flag,"sc09: Sloth exception failed to work.");
 as_cold(_EX_CURR == NULL,"sc09: EX_POP failed to pop correctly.");
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 74.}
\fwendmacronotes
\fwendmacro



\fwsecb{5.10}{Function fa01} This test tests that an unhandled exception will be properly caught.

\fwbeginmacro
\fwmacroname{Function fa01}{84}\fwequals \fwodef \fwbtx[
LOCAL void fa01 P_((void));
LOCAL void fa01 ()
{
 printf("Test FA01: Unhandled Exception\n");
 printf("------------------------------\n");
 printf("This test raises the sloth exception but doesn't handle it.\n");
 printf("The result should be an \"unhandled exception\" bomb specifying\n");
 printf("the sloth exception. Here we go...\n");
 printf("\n");
 EX_RAISE(sloth_ex);
 as_wl  ("FA01 FAILED: the exception package did not catch the\n");
 as_bomb("unhandled sloth exception.\n");
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 74.}
\fwendmacronotes
\fwendmacro



\fwsecb{5.11}{Function fa02} This test tests two calls to \fwlit{EX\_POP}.

\fwbeginmacro
\fwmacroname{Function fa02}{85}\fwequals \fwodef \fwbtx[
LOCAL void fa02 P_((void));
LOCAL void fa02 ()
{
 printf("Test FA02: Double EX_POP\n");
 printf("------------------------\n");
 printf("This test executes two calls to EX_POP within the normal code of\n");
 printf("an exception block. The second one should cause a\n");
 printf("\"context stack is empty\" bomb. Here we go...\n");
 printf("\n");
 EX_BEGIN
    EX_POP;
    EX_POP;
    as_bomb("FA02 FAILED: Second EX_POP did not cause bomb (1).");
 EX_FORGET
 EX_END
 as_bomb("FA02 FAILED: Second EX_POP did not cause bomb (2).");
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 74.}
\fwendmacronotes
\fwendmacro



\fwsecb{5.12}{Function fa03} This test tests a single call to \fwlit{EX\_POP} followed by a normal
termination of the normal code.

\fwbeginmacro
\fwmacroname{Function fa03}{86}\fwequals \fwodef \fwbtx[
LOCAL void fa03 P_((void));
LOCAL void fa03 ()
{
 printf("Test FA03: EX_POP Followed by Normal Termination\n");
 printf("------------------------------------------------\n");
 printf("This test executes a call to EX_POP then falls through to the\n");
 printf("end of the normal code of the exception block. The result should\n");
 printf("be a \"context stack is empty\" bomb. Here we go...\n");
 printf("\n");
 EX_BEGIN
    EX_POP;
 EX_FORGET
 EX_END
 as_bomb("FA03 FAILED: Fallthough after EX_POP did not cause bomb.");
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 74.}
\fwendmacronotes
\fwendmacro



\fwsecb{5.13}{Function fa04} This test checks to make sure that a context can detect when it is popping
the wrong context.

\fwbeginmacro
\fwmacroname{Function fa04}{87}\fwequals \fwodef \fwbtx[
LOCAL void fa04 P_((void));
LOCAL void fa04 ()
{
 printf("Test FA04: Exit a block without EX_POPing\n");
 printf("-----------------------------------------\n");
 printf("This test exits an exception block using a goto without first\n");
 printf("EX_POPing. The exception block is nested within another, and this\n");
 printf("test is to make sure that the outer block detects that it is\n");
 printf("popping the wrong context. The result should be a\n");
 printf("\"not current context\" bomb. Here we go...\n");
 printf("\n");
 EX_BEGIN
    EX_BEGIN
       goto there;
    EX_FORGET
    EX_END
    there:
 EX_FORGET
 EX_END
 as_bomb("FA04 FAILED: Outer block FAILED to detect stack misalignment.");
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 74.}
\fwendmacronotes
\fwendmacro



\fwsecb{5.14}{Function fa05} This test tests for the detection of an unpopped invalid stack context.

\fwbeginmacro
\fwmacroname{Function fa05}{88}\fwequals \fwodef \fwbtx[
LOCAL void fa05_x P_((void));
LOCAL void fa05_x ()
{
 EX_BEGIN
    return;
 EX_FORGET
 EX_END
}

LOCAL void fa05 P_((void));
LOCAL void fa05 ()
{
 printf("Test FA05: Target Context Does Not Exist\n");
 printf("----------------------------------------\n");
 printf("This test exits an exception block from within a function using\n");
 printf("a return statement. Thus, the context remains stacked even though\n");
 printf("the enclosing C block has terminated. This test checks to see\n");
 printf("whether this problem is detected next time an exception is raised.\n");
 printf("The result should be an illegitimate context error. Here we go...\n");
 printf("\n");
 EX_BEGIN
    fa05_x();
    EX_RAISE(sloth_ex);
    as_bomb("FA05 FAILED: Failed to raise sloth.");
 EX_FORGET
    EX_WHEN(sloth_ex)
       as_bomb("FA05 FAILED: Sloth exception was raised.");
 EX_END
 as_bomb("FA05 FAILED: Costruct terminated normally - it shouldn't have.");
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 74.}
\fwendmacronotes
\fwendmacro



\fwsecb{5.15}{Function fa06} This test is identical to the previous one except that the test is made
at the point of exit of the outer block, not at the point of raising an
exception.

\fwbeginmacro
\fwmacroname{Function fa06}{89}\fwequals \fwodef \fwbtx[
LOCAL void fa06 P_((void));
LOCAL void fa06 ()
{
 printf("Test FA06: Target Context Does Not Exist (Fallthrough)\n");
 printf("------------------------------------------------------\n");
 printf("This test is identical to test FA05 except that it does not\n");
 printf("raise an exception in the outer block. The result should be a\n");
 printf("\"not current context\" error. Here we go...\n");
 printf("\n");
 EX_BEGIN
    fa05_x();
 EX_FORGET
 EX_END
 as_bomb("FA06 FAILED: Costruct terminated normally - it shouldn't have.");
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 74.}
\fwendmacronotes
\fwendmacro



\fwsecb{5.16}{Function fa07}

\fwbeginmacro
\fwmacroname{Function fa07}{90}\fwequals \fwodef \fwbtx[
LOCAL void fa07 P_((void));
LOCAL void fa07 ()
{
 as_bomb("Test FA07: Test FA06 is the last test.");
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 74.}
\fwendmacronotes
\fwendmacro


\fwsecb{5.17}{Function fa08}

\fwbeginmacro
\fwmacroname{Function fa08}{91}\fwequals \fwodef \fwbtx[
LOCAL void fa08 P_((void));
LOCAL void fa08 ()
{
 as_bomb("Test FA08: Test FA06 is the last test.");
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 74.}
\fwendmacronotes
\fwendmacro


\fwsecb{5.18}{Function fa09}

\fwbeginmacro
\fwmacroname{Function fa09}{92}\fwequals \fwodef \fwbtx[
LOCAL void fa09 P_((void));
LOCAL void fa09 ()
{
 as_bomb("Test FA09: Test FA06 is the last test.");
}
]fwetx=%
\fwcdef 
\fwbeginmacronotes
\fwusedin{This macro is invoked in definition 74.}
\fwendmacronotes
\fwendmacro



\fwseca{6}{Design Notes}

This section contains a detailed design discussion of particular aspects of
this package. Inserting these notes into the implementation section would have
cluttered it up too much.


\fwsecb{6.1}{Architectural Discussion}

The basic engine for exceptions is provided by the ANSI standard \fwlit{setjmp}
and \fwlit{longjmp} primitives which provide simple non-local jumps. The challenge
is organizing them into an exception facility. To see the problems involved
in doing this, we need only focus on an executing program at the time that
an exception is raised. At this time, the exceptions package must locate
the closest handler for the particular exception. From this, two things
become immediately clear: 1) that the exceptions package is going to have to
perform ``work'' whenever an exception block is encountered as well as whenever
an exception is raised, 2) some sort of stacking of \fwlit{jmp\_buf} contexts
is required.

This reasoning suggests two organizations:

1) Maintain a stack for each exception. Whenever an exception block is
entered, push all the handlers for that block on their respective stacks.
Pop them when exiting the handler. If an exception is raised, simply look
on the top of its stack.

2) Maintain a stack of exception blocks. If an exception is raised, search
each block in turn for a matching handler.

Of these two organizations, the second is by far the better. Exceptions are
almost by definition rare events, and so in assessing the two organizations,
the emphasis should be placed on the efficiency of the ordinary case which
is the pushing and popping. The first alternative may require multiple pushes
and pops per exception block, whereas the second requires just one. There
are also a number of more practical reasons why the second alternative is
better.

Having decided that a stack of exception blocks should be maintained, the
next thing to decide is where it should be stored. The first thing that
pops to mind is to organize for the exceptions package to maintain a stack
in a linked list growing out of a global variable. While completely feasible,
this solution is distasteful as it requires a memory allocation and
deallocation per exception block instance. A far better scheme is simply
to store the stack on the run-time stack! This can be done by storing
each node of the stack in an automatic variable within the stack frame
of the function containing the exception block. These automatic variables
can then be threaded together with points to form the originally desired
explicit stack.


\fwsecb{6.2}{Exception Identity}

One interesting aspect of the design is the identity of exceptions.
When the client raises an exception by calling \fwlit{ex\_raise}, an argument
must be provided that in some way identifies the exception being raised.
A number of possible schemes spring to mind:

\fwemp{Integer/preprocessor constant:} Each exception could be mapped
onto a unique integer which would represent the exception.  These integers
could be managed by defining preprocessor symbols for them. To raise an
exception, the client would simply pass the preprocessor symbol. This solution
is simple and provides compile-time checking (if the client programmer
mistypes a number, the problem won't be discovered until the exception is
raised and not caught, but if the client mistypes a preprocessor symbol, the
compiler will issue an ``unknown symbol'' error), but it does not provide
any way to ensure that two different exceptions in two different modules
are not using the same number to represent the two different exceptions.
There are organizational solutions to this problem such as having the
programmer maintain a global list of exceptions, but these are generally
unacceptable in the long run. One other solution is to make exception
integers wide (e.g. 32-bits) and have the programmer choose the integer
for each exception by tossing a coin 32 times. The probability of a collision
would be tiny. To be sure that two exceptions were not using the same
number, exceptions could be registered with the exceptions package which
would check the uniqueness of each registered exception integer. Registration
would also allow the exception package to bind a string name to each
exception number.

\fwemp{Integer/variable:} The first solution is clean because it uses
preprocessor symbols. A slightly different solution is to use global variables
instead. Under this scheme, a module exporting an exception exports a global
integer variable that represents the exception. When the package starts
up, it registers the exception with the exception package. Registration in
this case is active, not passive; the exceptions package allocates an
exception number which is assigned to the variable. This solution has the
advantage of guaranteeing that exception numbers are unique. However,
exceptions often happen under strange conditions and it is probably a
disadvantage to have an exception represented by a writeable variable.

\fwemp{Pointer to record:} An alternative to integers is to represent
exceptions by pointers to records describing the exceptions. Each record
could be declared statically (thus ensuring that each record has a unique
pointer) and could contain a description of the exception and possibly
other useful information (e.g. a count of how often the exception has fired).
The  pointers to the records could be constants.

\fwemp{Pointer to string:} Pointers to records are OK, but are rather messy
to declare. As it seems that the only information that really needs to be
bound to an exception is a string describing the exception, a far better
more direct scheme is simply to represent exceptions as pointers to strings.
Each exception can be statically declared as a \fwlit{const} pointer to a string.
This solves all the problems: 1) the exception identity is read-only,
2) the exception identity is unique (because each string is stored at
a different address), 3) the exception identity is easy to declare,
4) the exceptions package doesn't have to manage a table of exceptions,
5) the exception variable names are subject to compile-time checking.
The only disadvantages are that 1) the compiler might overlap two constant
strings if one is a non-strict suffix of the other, 2) the exception is
represented by an object that is basically a variable which could be
accidentally written-to if the program goes haywire before the exception is
raised. The \fwlit{const} attribute helps, but may be ignored by many compilers
which will place the variable in writeable memory. These disadvantages are
considered minor compared to the advantages.

Of the solutions given above, the simplest and cleanest is the pointer to
string solution, and this is the scheme that is used in this package. This
is a particularly satisfactory solution because it solves the problem of
exception identity and exception description in one go.


\fwsecb{6.3}{Identifier Names}

Because it contains macros that refer to global variables, this package
exposes the major proportion of its names to the client. As such, particular
care must be taken with names.

To assist portability to brain-dead compilers, all names have generally been
restricted to six characters for external identifiers and eight for internal
identifiers. Upper case has been used for preprocessor symbols and lower case
for other identifiers. Although the use of upper case in the main exception
syntax is a little loud, it is also a continuous reminder that this is a
dangerous construct.

The menemonic for this package is \fwlit{ex} and this appears at the beginning of
every exported symbol. This will assist to reduce symbol collisions.
In addition, any symbol that is not intended to be seen by the client has
been prepended with an underscore. This is a little bit naughty as it
contravenes the ANSI standard's rule 7.13 on identifiers reserved for
libraries (``\fwemp{All identifiers that begin with an underscore are always
reserved for use as identifiers with file scrope in both the ordinary
identifier and tag name spaces}''), but as this package is supposed to be
a library package too, it seems only a minor breach, and completely in keeping
with the style of the ANSI library.

The names of all the exported constructs were chosen very carefully.
Because most of the exported items were macros, by universal convention,
their identifiers had to be in upper case. This requirement was not a
disadvantage though as exception handlers are so important that they ought
to be syntactically ``loud''. Prefixing each symbol with \fwlit{EX\_} is a little
verbose, but was worthwhile because it immediately binds the symbol so
tightly to this package that generic suffixes such as \fwlit{BEGIN} can be used
as a suffix. Thus \fwlit{EX\_BEGIN} and \fwlit{EX\_END} strongly convey their identity
as the boundaries of an anonymous block, but also strongly indicate that the
block is designed to handle exceptions.

As mentioned earlier, the identifier \fwlit{EX\_FORGET} was chosen so as to
continually remind the programmer that, in the event of an exception, all
automatic variables defined within the function containing the exception block
and which have been written since the \fwlit{EX\_BEGIN} of the block, will be
undefined. This is such an important semantic point that it was considered
worthy of being embodied in the syntax too.

The hardest identifier to choose was \fwlit{EX\_RAISE}. For a long time, this
construct was simply to take the form of an exported function with the
name \fwlit{ex\_rai}. However, in the end, it was decided that it would be
better to give this facility the same syntactic feel as the other constructs.
In addition, the raising of an exception is an event that should probably
be syntactically loud. Finally \fwlit{EX\_RAISE} is more readable than \fwlit{ex\_rai}.


\fwsecb{6.4}{Catering for Multi-Threading}

An increasing amount of code is being run in a multi-threading environment
and it is important to ensure that all library packages (such as this one)
are compatible with multi-threading. A key requirement of multi-threading
is that there be no global variables, ar at least that all declarations
and uses of the global variables that do exist have been encapsulated in
macros that can be redefined to work with multi-threading. In this package,
the only global variables are \fwlit{\_ex\_curr}, \fwlit{\_ex\_id}, and \fwlit{\_ex\_info}.
To simplify possible future conversion for use with a multi-threading package,
all uses of these variables have been expressed in terms of the macros
\fwlit{\_EX\_CURR}, \fwlit{\_EX\_ID}, \fwlit{EX\_ID}, and \fwlit{EX\_INFO}.


\fwsecb{6.5}{Checking}

As mentioned before, exceptions are slippery things that can easily go
wrong particularly when the exception facility is hacked together, as it
has here, out of macros and \fwlit{longjmp}s. This section contains a list of
likely errors and failures and explains how the package copes with them.
The errors listed here are caught only in the checking version of this
package. If \fwlit{\_EX\_FAST} then no checking is performed.

\fwemp{Exception has no handler:} This simple case is caught by the \fwlit{\_exrai}
function which will detect a \fwlit{NULL} pointer in \fwlit{\_EX\_CURR} if there
are no more exception blocks to search for handlers.

\fwemp{Client pops the context too often:} This case will occur if the
client calls \fwlit{EX\_POP} and then exits the exception block normally, or
if the client calls \fwlit{EX\_POP} more than once within the same exception
block. Both these errors are detected by the \fwlit{\_expop} function which
tests to ensure that the context it is being asked to pop is the context
enclosing the \fwlit{EX\_POP} call. (Note: \fwlit{EX\_POP} won't compile unless it
is called from within an exception block, so there is no chance of a
context being popped from an external function).

\fwemp{Client exits context without popping it:} This is the single biggest
headache, as there is no way that this error can be detected when it occurs.
There is nothing to stop the client from executing a \fwlit{return} or explicit
\fwlit{longjmp} from within an exception block, and if the client does, the
exception block will still be registered as the top context on the stack
of exception contexts, and control will be transferred to it if an exception
goes off, and if this happens, the program is likely to crash, as the
stack frame containing the exception block no longer exists.

This problem cannot be solved, but it can be attenuated somewhat using
the three-pronged approach adopted in this package:

1) Whenever a context is popped, a check is performed to ensure that the
context being popped is the statically enclosing exception block. If it
isn't, the program bombs. This check means that the stack will be properly
aligned following each non-illegal termination of each exception block.

2) Whenever an exception is raised, a check is performed to ensure that
the address of the context on the top of the context stack is lower than
that of the start of the stack frame of the function raising the exception.
If it is, then it must be an erroneously unpopped context.

3) Corruptions of context records are detected by having two magic number
fields in the record, one at the start of the record and one at the end.
If a record is corrupted, the corruption is likely to be detected the
next time the record is manipulated.

The last two checks do a good job of covering the two main cases that can
arise. When an exception block terminates without its context being popped,
control will often leave the function. If it does, then the top of the
run-time stack will be higher (in address value for stacks that grow down)
than the unpopped context. This is detected by the second test. If, later,
the stack grows again, it is likely to overwrite the unpopped
context, including the magic numbers it contains. If this happens, then the
error will be detected the next time an exception is raised or the stack is
popped.

Obviously, there are ways in which a computer program might satisfy all
these tests and still be erroneous, but at least these tests provide some
sort of safety net.


\fwsecb{6.6}{Future Improvements}

This section gives a list of possible future improvements to this package.

* It might be useful to allow the client to specify a block of code that
is executed after an exception is raised, but before the handlers are scanned.
This would allow an opportunity for cleaning up.

* Rework the terminology so that it is more consistent.

* Hierarchical exceptions.

That's the end of this package!


\bye


%*******************************************************************************
%*                    END OF AUTOMATICALLY GENERATED TEX FILE                  *
%*******************************************************************************