Exceptions/Catch an exception thrown in a nested call: Difference between revisions
Content added Content deleted
m (→{{header|Lasso}}: Corrected output) |
|||
Line 303:
=={{header|C}}==
C doesn't have an exception handling
decide what we want from an exception.
1. Return from a function with an error added to exception context.
2. Detect that a exception was thrown by checking the context after a function call.
3. Recover an error type and message.
4. Return from a function after throwing/catching an exception in a way which allows cleanup code to be called (vs. jumping outside the function).
In conclusion, try/throw/catch keywords are not available in C, nor is
their functionality, so while the following code tries to fulfill the task's
requirements, no attempt is made to minic them. The goal has been to provide
some modicum level of usefulness for someone actually looking at this for
ideas for their own code.
U0 and U1 are boring for debugging purposes. Added something to help with that.
<lang C>#include <stdio.h>
#include <stdlib.h>
typedef struct exception {
int extype;
char what[128];
} exception;
typedef struct exception_ctx {
exception * exs;
int size;
int pos;
} exception_ctx;
exception_ctx * Create_Ex_Ctx(int length) {
const int safety = 8; // alignment precaution.
char * tmp = (char*) malloc(safety+sizeof(exception_ctx)+sizeof(exception)*length);
exception_ctx * ctx = (exception_ctx*)tmp;
ctx->size = length;
ctx->pos = -1;
ctx->exs = (exception*) (tmp + sizeof(exception_ctx));
return ctx;
}
void Free_Ex_Ctx(exception_ctx * ctx) {
free(ctx);
}
int Has_Ex(exception_ctx * ctx) {
return (ctx->pos >= 0) ? 1 : 0;
}
int Is_Ex_Type(exception_ctx * exctx, int extype) {
return (exctx->pos >= 0 && exctx->exs[exctx->pos].extype == extype) ? 1 : 0;
}
void Pop_Ex(exception_ctx * ctx) {
if (ctx->pos >= 0) --ctx->pos;
}
const char * Get_What(exception_ctx * ctx) {
if (ctx->pos >= 0) return ctx->exs[ctx->pos].what;
return NULL;
}
int Push_Ex(exception_ctx * exctx, int extype, const char * msg) {
// Use last slot and report error.
}
snprintf(exctx->exs[exctx->pos].what, sizeof(exctx->exs[0].what), "%s", msg);
exctx->exs[exctx->pos].extype = extype;
return -1;
}
//////////////////////////////////////////////////////////////////////
exception_ctx * GLOBALEX = NULL;
enum { U0_DRINK_ERROR = 10, U1_ANGRYBARTENDER_ERROR };
void baz(int n) {
if (! n) {
Push_Ex(GLOBALEX, U0_DRINK_ERROR , "Drink Error. Insufficient drinks in bar Baz.");
return;
}
else {
Push_Ex(GLOBALEX, U1_ANGRYBARTENDER_ERROR , "Bartender Error. Bartender kicked customer out of bar Baz.");
return;
}
}
void bar(int n) {
fprintf(stdout, "Bar door is open.\n");
baz(n);
if (Has_Ex(GLOBALEX)) goto bar_cleanup;
fprintf(stdout, "Baz has been called without errors.\n");
bar_cleanup:
fprintf(stdout, "Bar door is closed.\n");
}
while (Is_Ex_Type(GLOBALEX, U0_DRINK_ERROR)) {
fprintf(stderr, "I am foo() and I deaall wrth U0 DriNk Errors with my own bottle... GOT oNE! [%s]\n", Get_What(GLOBALEX));
}
if (Has_Ex(GLOBALEX)) return;
fprintf(stdout, "Foo left the bar.\n");
fprintf(stdout, "Foo entering bar again.\n");
bar(1);
while (Is_Ex_Type(GLOBALEX, U0_DRINK_ERROR)) {
fprintf(stderr, "I am foo() and I deaall wrth U0 DriNk Errors with my own bottle... GOT oNE! [%s]\n", Get_What(GLOBALEX));
Pop_Ex(GLOBALEX);
}
if (Has_Ex(GLOBALEX)) return;
fprintf(stdout, "Foo left the bar.\n");
}
int main(int argc, char ** argv) {
exception_ctx * ctx = Create_Ex_Ctx(5);
GLOBALEX = ctx;
foo();
if (Has_Ex(ctx)) goto main_ex;
fprintf(stdout, "No errors encountered.\n");
main_ex:
while (Has_Ex(ctx)) {
fprintf(stderr, "*** Error: %s\n", Get_What(ctx));
Pop_Ex(ctx);
}
Free_Ex_Ctx(ctx);
return 0;
}
</lang>
Output:
<lang>Foo entering bar.
Bar door is open.
Bar door is closed.
I am foo() and I deaall wrth U0 DriNk Errors with my own bottle... GOT oNE! [Drink Error. Insufficient drinks in bar Baz.]
Foo left the bar.
Foo entering bar again.
Bar door is open.
Bar door is closed.
*** Error: Bartender Error. Bartender kicked customer out of bar Baz.
</lang>
=={{header|C++}}==
|