@@@ misc mess
[mLib] / utils / macros.h
index 95d0ddb..dba22a7 100644 (file)
 
 /*----- Miscellaneous utility macros --------------------------------------*/
 
+/* --- @N@ --- *
+ *
+ * Arguments:  @type v[]@ = an actual array, not a pointer
+ *
+ * Returns:    The number of elements in @v@.
+ */
+
 #define N(v) (sizeof(v)/sizeof(*(v)))
 
+/* --- @STR@ --- *
+ *
+ * Arguments:  @x@ = some tokens
+ *
+ * Returns:    A string literal containing the macro-expanded text of @x@.
+ */
+
 #define MLIB__STR(x) #x
 #define STR(x) MLIB__STR(x)
 
+/* --- @GLUE@ --- *
+ *
+ * Arguments:  @x, y@ = two sequences of tokens
+ *
+ * Returns:    A single token formed by gluing together the macro-expansions
+ *             of @x@ and @y@.
+ */
+
 #define MLIB__GLUE(x, y) x##y
 #define GLUE(x, y) MLIB__GLUE(x, y)
 
+/* --- @STATIC_ASSERT@ --- *
+ *
+ * Arguments:  @int cond@ = a condition
+ *             @msg@ = a string literal message
+ *
+ * Returns:    ---
+ *
+ * Use:                Fail at compile time unless @cond@ is nonzero.  The failure
+ *             might report @msg@.
+ */
+
 #ifdef static_assert
 #  define STATIC_ASSERT(cond, msg) static_assert(!!(cond), msg)
 #else
        IGNORABLE extern char static_assert_failed[2*!!(cond) - 1]
 #endif
 
+/* --- @COMMA@ --- *
+ *
+ * Arguments:  ---
+ *
+ * Returns:    A `%|,|%' token, which can be usefully passed to macros to
+ *             avoid argument splitting.
+ */
+
 #define COMMA ,
 
 /*----- String and character hacks ----------------------------------------*/
 
+/* --- @IS...@ --- *
+ *
+ * Arguments:  @int ch@ = a character code, but not @EOF@
+ *
+ * Returns:    Nonzero if @ch@ is in the relevant @<ctype.h>@ category.
+ *
+ * Use:                Classifies characters, but safely even if characters are
+ *             signed.
+ *
+ *             There is a macro for each of the @<ctype.h>@ @is...@
+ *             functions.
+ */
+
 #define CTYPE_HACK(func, ch) (func((unsigned char)(ch)))
 
 #define ISALNUM(ch) CTYPE_HACK(isalnum, ch)
 #define ISUPPER(ch) CTYPE_HACK(isupper, ch)
 #define ISXDIGIT(ch) CTYPE_HACK(isxdigit, ch)
 
+/* --- @TO...@ --- *
+ *
+ * Arguments:  @int ch@ = a character code, but not @EOF@
+ *
+ * Returns:    The converted character code.
+ *
+ * Use:                Converts characters, but safely even if characters are
+ *             signed.
+ *
+ *             There is a macro for each of the @<ctype.h>@ @to...@
+ *             functions.
+ */
+
 #define TOASCII(ch) CTYPE_HACK(toascii, ch)
 #define TOLOWER(ch) CTYPE_HACK(tolower, ch)
 #define TOUPPER(ch) CTYPE_HACK(toupper, ch)
 
+/* --- @MEMCMP@, @STRCMP@, @STRNCMP@ --- *
+ *
+ * Arguments:  @const type *x, *y@ = pointers to strings
+ *             @op@ = a relational operator symbol
+ *             @size_t n@ = length of the strings
+ *
+ * Returns:    Nonzero if the relationship between the strings satisfies the
+ *             operator @op@, otherwise zero.
+ *
+ * Use:                These macros mitigate the author's frequent error of failing
+ *             to compare the result of the underlying standard functions
+ *             against zero, effectively reversing the sense of an intended
+ *             test for equality.
+ */
+
 #define MEMCMP(x, op, y, n) (memcmp((x), (y), (n)) op 0)
 #define STRCMP(x, op, y) (strcmp((x), (y)) op 0)
 #define STRNCMP(x, op, y, n) (strncmp((x), (y), (n)) op 0)
 
-/*----- Compiler diagnostics ----------------------------------------------*/
+/*----- Compiler-specific definitions -------------------------------------*/
 
-/* --- Compiler-specific definitions --- */
+/* The descriptions of these are given below, with the fallback
+ * definitions.
+ */
 
 #if GCC_VERSION_P(2, 5) || CLANG_VERSION_P(3, 3)
 #  define NORETURN __attribute__((__noreturn__))
 
 /* --- Fallback definitions, mostly trivial --- */
 
-#ifndef DEPRECATED
-#  define DEPRECATED(msg)
-#endif
-
-#ifndef EXECL_LIKE
-#  define EXECL_LIKE(ntrail)
-#endif
+/* --- @DISCARD@ --- *
+ *
+ * Arguments:  @x@ = a function call
+ *
+ * Returns:    ---
+ *
+ * Use:                Explicitly discard the result of @x@.  This counteracts a
+ *             @MUST_CHECK@ attribute on the called function.
+ */
 
 #ifndef DISCARD
 #  define DISCARD(x) do if (x); while (0)
 #endif
 
+/* --- @IGNORE@ --- *
+ *
+ * Arguments:  @x@ = any expression
+ *
+ * Returns:    ---
+ *
+ * Use:                Ignore the value of @x@, overriding compiler warnings.
+ */
+
 #ifndef IGNORE
 #  define IGNORE(x) ((void)(x))
 #endif
 
-#ifndef MUFFLE_WARNINGS_DECL
-#  define MUFFLE_WARNINGS_DECL(warns, body) body
-#endif
+/* --- @LAUNDER@ --- *
+ *
+ * Arguments:  @x@ = some integer expression
+ *
+ * Returns:    @x@.
+ *
+ * Use:                Causes a compiler to know nothing about the value of @x@,
+ *             even if it looks obvious, e.g., it's a constant.
+ */
 
-#ifndef MUFFLE_WARNINGS_EXPR
-#  define MUFFLE_WARNINGS_EXPR(warns, body) (body)
+#ifndef LAUNDER
+#  define LAUNDER(x) (x)
 #endif
 
-#ifndef MUFFLE_WARNINGS_STMT
-#  define MUFFLE_WARNINGS_STMT(warns, body) do { body } while (0)
-#endif
+/* --- @RELAX@ --- *
+ *
+ * Arguments:  ---
+ *
+ * Returns:    ---
+ *
+ * Use:                Does nothing, but the compiler doesn't know that.
+ */
 
-#ifndef PRINTF_LIKE
-#  define PRINF_LIKE(fmtix, argix)
+#ifndef RELAX
+#  define RELAX
 #endif
 
-#ifndef SCANF_LIKE
-#  define SCANF_LIKE(fmtix, argix)
+/* --- @DEPRECATED@, @NORETURN@, @IGNORABLE@, @MUST_CHECK@ --- *
+ *
+ * Use:                These are (mostly) function attributes; write them among the
+ *             declaration specifiers for a function definition or
+ *             declaration.  These may not do anything, but the intended
+ *             behaviour is as follows.
+ *
+ *               * @DEPRECATED(msg)@ -- report a warning, quoting the string
+ *                 literal @msg@, if the function is called.
+ *
+ *               * @NORETURN@ -- promise that the function doesn't return to
+ *                 its caller: either it kills the process, or it performs
+ *                 some nonlocal transfer.
+ *
+ *               * @IGNORABLE@ -- the item (which might be data rather than
+ *                 a function) might not be referred to, but that's OK:
+ *                 don't warn about it.
+ *
+ *               @ @MUST_CHECK@ -- warn if the return value of a function is
+ *                 ignored.  Use @DISCARD@ if you really don't care.
+ */
+
+#ifndef DEPRECATED
+#  define DEPRECATED(msg)
 #endif
 
 #ifndef NORETURN
 #  define MUST_CHECK
 #endif
 
-#ifndef LAUNDER
-#  define LAUNDER
+/* --- @PRINTF_LIKE@, @SCANF_LIKE@, @EXECL_LIKE@ --- *
+ *
+ * Arguments:  @int fmtix@ = format string argument index (starting from 1)
+ *             @int argix@ = variable format argument tail index (starting
+ *                     from 1)
+ *             @int ntrail@ = number of arguments following terminator
+ *
+ * Use:                These are function attributes.  Again, they might not do
+ *             anything at all.  By intention, they give the compiler
+ *             information about a variadic function's arguments, so that it
+ *             can warn about misuse.
+ *
+ *               * @PRINTF_LIKE@ -- the function takes a @printf@-style
+ *                 format string as argument @fmtix@ and an argument tail
+ *                 (which may be empty) beginning with argument @argix@.
+ *
+ *               * @SCANF_LIKE@ -- the function takes a @scanf@-style
+ *                 format string as argument @fmtix@ and an argument tail
+ *                 (which may be empty) beginning with argument @argix@.
+ *
+ *               * @EXECL_LIKE@ -- the function takes a sequence of pointer
+ *                 arguments terminated by a null pointer, followed by
+ *                 @ntrail@ further arguments.
+ */
+
+#ifndef PRINTF_LIKE
+#  define PRINF_LIKE(fmtix, argix)
 #endif
 
-#ifndef RELAX
-#  define RELAX
+#ifndef SCANF_LIKE
+#  define SCANF_LIKE(fmtix, argix)
 #endif
 
+#ifndef EXECL_LIKE
+#  define EXECL_LIKE(ntrail)
+#endif
+
+/* --- @MUFFLE_WARNINGS_...@ --- *
+ *
+ * Arguments:  @warns@ = a sequence of @..._WARNING@ calls (see below)
+ *             @body@ = some program text
+ *
+ * Use:                Muffle specific warnings within the program text.
+ *
+ *             For @MUFFLE_WARNINGS_DECL@, the program text is a
+ *             declaration; for @MUFFLE_WARNINGS_EXPR@, it is an expression,
+ *             and for @MUFFLE_WARNINGS_STMT@, it is a statement.
+ *
+ *             The warnings to be muffled are given as a list of
+ *             @..._WARNING@ macros, with no separators.  The list can
+ *             list warnings from multiple different compilers: entries for
+ *             irrelevant compilers will be ignored.
+ */
+
+#ifndef MUFFLE_WARNINGS_DECL
+#  define MUFFLE_WARNINGS_DECL(warns, body) body
+#endif
+
+#ifndef MUFFLE_WARNINGS_EXPR
+#  define MUFFLE_WARNINGS_EXPR(warns, body) (body)
+#endif
+
+#ifndef MUFFLE_WARNINGS_STMT
+#  define MUFFLE_WARNINGS_STMT(warns, body) do { body } while (0)
+#endif
+
+/* --- @GCC_WARNING@ --- *
+ *
+ * Arguments:  @warn@ = a string literal naming a warning, with `%|-W...|%'
+ *                     prefix
+ *
+ * Use:                Names a GCC warning: use within @MUFFLE_WARNINGS_...@.
+ *
+ *             Note that GCC's warning suppression is very buggy.
+ */
+
 #ifndef GCC_WARNING
 #  define GCC_WARNING(warn)
 #endif
 
+/* --- @CLANG_WARNING@ --- *
+ *
+ * Arguments:  @warn@ = a string literal naming a warning, with `%|-W...|%'
+ *                     prefix
+ *
+ * Use:                Names a Clang warning: use within @MUFFLE_WARNINGS_...@.
+ */
+
 #ifndef CLANG_WARNING
 #  define CLANG_WARNING(warn)
 #endif