gen: general definitions
debug: debugging and tracing
assert: assertion handling and aborts
heap: memory allocation
exc: exception handling
rpool: resource pools
cdefs: C language portability macros
io: buffered i/o
When we aren't implementing a standard interface, we use a naming convention that attempts to maximize portability across platforms, and minimize conflicts with other libraries. Except for a few seemingly benign exceptions, all names begin with SM_, Sm or sm_.
The ISO C, Posix and Unix standards forbid applications from using names beginning with __ or _[A-Z], and place restrictions on what sorts of names can begin with _[a-z]. Such names are reserved for the compiler and the standard libraries. For this reason, we avoid defining any names that begin with _. For example, all libsm header file idempotency macros have the form SM_FOO_H (no leading _).
Type names begin with SM_ and end with _T. Note that the Posix standard reserves all identifiers ending with _t.
All functions that are capable of raising an exception have names ending in _x, and developers are encouraged to use this convention when writing new code. This naming convention may seem unnecessary at first, but it becomes extremely useful during maintenance, when you are attempting to reason about the correctness of a block of code, and when you are trying to track down exception-related bugs in existing code.
The extern is useless, but required for stylistic reasons. The parameter names are optional; if present they are lowercase and begin with _ to avoid namespace conflicts. Each parameter is written on its own line to avoid very long lines.extern int foo __P(( int _firstarg, int _secondarg));
For each structure struct sm_foo defined by libsm, there is a typedef:
and there is a global variable which is defined as follows:typedef struct sm_foo SM_FOO_T;
The first member of each structure defined by libsm isconst char SmFooMagic = "sm_foo";
For all instances of struct sm_foo, sm_magic contains SmFooMagic, which points to a unique character string naming the type. It is used for debugging and run time type checking.const char *sm_magic;
Each function with a parameter declared SM_FOO_T *foo contains the following assertion:
which is equivalent toSM_REQUIRE_ISA(foo, SmFooMagic);
When an object of type SM_FOO_T is deallocated, the member sm_magic is set to NULL. That will cause the above assertion to fail if a dangling pointer is used.SM_REQUIRE(foo != NULL && foo->sm_magic == SmFooMagic);