ban2fail/ez.h

129 行
4.9 KiB
C

/*****************************************************************************
* In an effort to make C programming both easier and more secure, I present
* the EZ method.
*
* Reasoning for this is simple; Many function calls can fail for a variety of
* reasons, some or even most of which are obscure. However, it is both
* insecure and counterproductive not to check for said failures. Unfortunately
* coding proper checks and/or recovery from failures will involve (often
* complex) logic constructs, and detracts from understanding the primary logic
* of your source code.
*
* Sometimes your app needs to recover, and so you must supply this code, but
* more often than not a "boilplate" approach is sufficient. The EZ method is a
* consistent convention to supply centralized and reusable "boilerplate" error
* handling on an _optional_ basis, both for existing library functions and
* your own.
*
* Modern programming languages address this problem by throwing "exceptions",
* which by default result in your program getting terminated. To avoid
* termination you must write code to "catch" such exceptions, but this code
* exists separated in source code from the function call, and tends to be both
* confusing to read and hideous to look at. If you thought "goto" statements
* were in poor taste, then this will make you vomit.
*
* Enter the EZ method; from a practical coding standpoint you merely prepend
* "ez_" to any function call for which you desire default error handling. When
* an error occurs a very helpful error message is printed (in DEBUG mode this
* includes the source code location from which the function was called), and
* your program is terminated. If your app needs to recover from such an error,
* simply erase the "ez_" prefix from the function call and supply the recovery
* code, where God intended it to be - right where you made the function call!
*
* In effect the EZ method provides the utility of throwing exceptions, but
* without the catch - Woohoo!
*****************************************************************************/
#ifndef EZ_H
#define EZ_H
/*****************************************************************************
* These macros ease the drudgery of writing prototypes for the _ez_XXX()
* wrappers of functions, and reduce the liklihood of bugs due to typing
* errors.
*
* The elipses is for your function's argument list.
*****************************************************************************/
#ifdef DEBUG
#define ez_proto(rtn, funcname, ...) \
rtn _ez_##funcname( \
const char *fileName, \
int lineNo, \
const char *funcName, \
##__VA_ARGS__ \
)
#define ez_hdr_proto(rtn, funcname, ...) \
ez_proto(rtn, funcname, ##__VA_ARGS__); \
rtn funcname(__VA_ARGS__)
#else
#define ez_proto(rtn, funcname, ...) \
rtn _ez_##funcname(__VA_ARGS__)
#define ez_hdr_proto(rtn, funcname, ...) \
ez_proto(rtn, funcname, ##__VA_ARGS__); \
rtn funcname(__VA_ARGS__)
#endif
/*****************************************************************************
* For example, if you have the following function prototype:
*
* int myfunc (struct foo *f, double bar)
*
* In the header file where the function prototype goes,
* you will need this:
*
* ez_hdr_proto (int, myfunc, struct foo *f, double bar);
*
* #ifdef DEBUG
* # define ez_myfunc(...) \
* _ez_myfunc(__FILE__, __LINE__, __func__, ##__VA_ARGS__)
* #else
* # define ez_myfunc(...) \
* _ez_myfunc(__VA_ARGS__)
* #endif
*
* This will expand to the standard function prototype as listed above, as well
* as the _ez_myfunc() prototype correct for either DEBUG version or production
* version, depending on whether or not DEBUG is #define'd. Also, there is now
* a macro ez_myfunc() which will expand to the correct _ez_myfunc()
* function call.
*
* In the implmentation (*.c) file, you will need to supply code for
* _ez_myfunc(), which looks like so:
*
* ez_proto(int, myfunc, struct foo *f, double bar)
* {
* // implementation goes here
* }
*
* Notice that the prototype section is is the same as what you placed in the
* corresponding header file, minus "_hdr" in the ez_hdr_proto() macro.
*
* For the case where you are supplying only the ez_XXX() version of an
* existing function found in some library 'liba2z', you can place the
* following in your own header file, "ez_liba2z.h":
*
* ez_proto(struct rtnType*, liba2z_funcname, struct foo *f, double bar);
*
* Everything else works similar to the previous examples.
* Now you can use the EZ error handling like so:
*
* #include "ez_liba2z.h"
* int main(int argc, char **argv)
* {
* struct foo Foo;
* double bar;
* struct rtnType *rtn= ez_liba2z_funcname(&Foo, bar);
* }
*
*****************************************************************************/
#endif