/*************************************************************************/ /* 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. */ /* ---- */ /* ??-Apr-93: RNW: Created this package. */ /* 29-Sep-93: RNW: Released this package. */ /* ---- */ /*************************************************************************/ #include "style.h" #include "except.h" #include "as.h" EX_LOCAL(sloth_ex,"Sloth exception"); EX_LOCAL(walrus_ex,"Walrus exception"); GLOVAR bool flag; 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."); } 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."); } 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."); } 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."); } 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)."); } 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."); } 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."); } 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."); } 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."); } 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"); } 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)."); } 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."); } 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."); } 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."); } 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."); } LOCAL void fa07 P_((void)); LOCAL void fa07 () { as_bomb("Test FA07: Test FA06 is the last test."); } LOCAL void fa08 P_((void)); LOCAL void fa08 () { as_bomb("Test FA08: Test FA06 is the last test."); } LOCAL void fa09 P_((void)); LOCAL void fa09 () { as_bomb("Test FA09: Test FA06 is the last test."); } 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"); } } }