7. Error Codes

Error codes! We need error codes for stack overflows, empty stacks, invalid types, and a generic error. Oh, and an "OK" would be good to have too I guess.

It may also be helpful to build error messages associated with each macro.

Enter some mild mannered macro abuse. Because who doesn't want to do it every now and then?

This is a trick I've use in a few of my projects now.

The way we will do it is with an error list of error codes, consisting of their macro and their associated error message. We'll call this ERRORCODE.

<<errorlist.h>>=
ERRORCODE(TXTVM_OK, "everything is ok.")
ERRORCODE(TXTVM_NOT_OK, "something went wrong.")
<<errorlist>>
ERRORCODE(TXTVM_UNKNOWN, "not sure what happened.")

From there, the macro preprocessor will process the the ERRORCODE entries found in errorlist.h in two different ways. ERRORCODE will be (re)defined to behave differently in each context.

The first will be inside of an enum. The ERRORCODEmacro will be defined to only include the error code portion.

<<macros>>=
#define ERRORCODE(C,S) C,
enum {
#include "errorlist.h"
TXTVM_OOF /* you don't want to reach here */
};
#undef ERRORCODE

The messages portion will be an array of strings. Similar deal as the enums, only take the message portion.

Doing it this way, the enum values will line up with message array indices.

<<constants>>=
#define ERRORCODE(C, S) S,
static const char *errmsg[] =
{
#include "errorlist.h"
};
#undef ERRORCODE

The function txtvm_errmsg returns the associated error message.

<<funcdefs>>=
const char* txtvm_errmsg(int rc);
<<funcs>>=
const char* txtvm_errmsg(int rc)
{
    if (rc < 0 || rc > TXTVM_UNKNOWN) rc = TXTVM_UNKNOWN;
    return errmsg[rc];
}

the function txtvm_errcheck checks the error code to see if things are okie-dokie.

<<funcdefs>>=
int txtvm_errcheck(int rc);
<<funcs>>=
int txtvm_errcheck(int rc)
{
    return rc != TXTVM_OK;
}
<<funcdefs>>=
int txtvm_ok(void);
<<funcs>>=
int txtvm_ok(void)
{
    return TXTVM_OK;
}
<<funcdefs>>=
int txtvm_not_ok(void);
<<funcs>>=
int txtvm_not_ok(void)
{
    return TXTVM_NOT_OK;
}
<<exported_macros>>=
#define TXTVM_ERROR_CHECK(A) \
    if (txtvm_errcheck(A)) return A;
<<exported_macros>>=
#define TXTVM_ERROR_GOTO(A, L) \
    if (txtvm_errcheck(A)) goto L;



prev | home | next