mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-10-07 00:31:11 +00:00
Squashed 'src/c-stdaux/' changes from 99fe83cd5698..1407a1fb2754
1407a1fb2754 ci: add clang to RTD scripts 8404c4ca6d06 ci: build documentation 044c65c2e134 docs: add sphinx-based API documentation ad8449068d96 ci: use ci-c-util for macos runs 179987035687 build: adjust for v1.1.0 release 55d787178c84 build: prepare v1.1.0 release 29ca943e636a c-stdaux: avoid NULL arithmetic even in dead-code c6358e956c29 c-stdaux: avoid NULL-dereference in constant expressions 7fab258bdf6a c-stdaux: improve kerneldoc comments 434b75a796c0 build: export 'version-scripts' configuration 33d56a6aecb9 c-stdaux: encapsulate C_EXPR_ASSERT() aca7ee0ece60 ci: add macos run 0aa338b1f0de test: prefer pipe() over eventfd() for portability adda5ff3e9d9 build: export cflags via pkg-config 7a8493bebc59 api: add c_memcpy() a01615aefe48 build: prepare v1.0.0 1685fc39db3d api: provide c_memzero() 1257244f886a api: add c_memset() git-subtree-dir: src/c-stdaux git-subtree-split: 1407a1fb275494f9efc1abbef2fd19856fb1f43d
This commit is contained in:
parent
1c260f5a96
commit
9d1772bd73
17
.github/workflows/ci.yml
vendored
17
.github/workflows/ci.yml
vendored
|
@ -7,11 +7,24 @@ on:
|
|||
- cron: '0 0 * * *'
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
name: CI with Default Configuration
|
||||
ci-linux:
|
||||
name: Linux CI
|
||||
uses: bus1/cabuild/.github/workflows/ci-c-util.yml@v1
|
||||
with:
|
||||
cabuild_ref: "v1"
|
||||
linux: true
|
||||
m32: true
|
||||
matrixmode: true
|
||||
valgrind: true
|
||||
ci-macos:
|
||||
name: MacOS CI
|
||||
uses: bus1/cabuild/.github/workflows/ci-c-util.yml@v1
|
||||
with:
|
||||
cabuild_ref: "v1"
|
||||
linux: false
|
||||
macos: true
|
||||
ci-docs:
|
||||
name: Documentation CI
|
||||
uses: bus1/cabuild/.github/workflows/ci-sphinx.yml@main
|
||||
with:
|
||||
source: "./src/docs"
|
||||
|
|
20
.readthedocs.yaml
Normal file
20
.readthedocs.yaml
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Read the Docs configuration file
|
||||
|
||||
version: 2
|
||||
|
||||
build:
|
||||
apt_packages:
|
||||
- "clang"
|
||||
os: "ubuntu-22.04"
|
||||
tools:
|
||||
python: "3"
|
||||
|
||||
formats: "all"
|
||||
|
||||
python:
|
||||
install:
|
||||
- requirements: "src/docs/requirements.txt"
|
||||
system_packages: true
|
||||
|
||||
sphinx:
|
||||
configuration: "src/docs/conf.py"
|
4
AUTHORS
4
AUTHORS
|
@ -34,5 +34,9 @@ COPYRIGHT: (ordered alphabetically)
|
|||
|
||||
AUTHORS: (ordered alphabetically)
|
||||
David Rheinsberg <david.rheinsberg@gmail.com>
|
||||
Evgeny Vereshchagin <evvers@ya.ru>
|
||||
Lorenzo Arena <lorenzo.arena@powersoft.com>
|
||||
Michele Dionisio <michele.dionisio@gmail.com>
|
||||
Thomas Haller <thaller@redhat.com>
|
||||
Tom Gundersen <teg@jklm.no>
|
||||
Yuri Chornoivan <yurchor@ukr.net>
|
||||
|
|
37
NEWS.md
37
NEWS.md
|
@ -1,11 +1,38 @@
|
|||
# c-stdaux - Auxiliary macros and functions for the C standard library
|
||||
|
||||
## CHANGES WITH 1:
|
||||
## CHANGES WITH 1.1.0:
|
||||
|
||||
* Add c_memcpy() as a safe wrapper around memcpy(3) that supports
|
||||
empty arenas as NULL pointers.
|
||||
|
||||
* Support building on MacOS-X.
|
||||
|
||||
* Rework the apidoc comments and properly document the entire API.
|
||||
|
||||
* Export 'version-scripts' configuration variable alongside the
|
||||
existing 'cflags' variable. It defines whether c-stdaux was built
|
||||
with GNU-linker version-scripts, or not. Dependent projects can
|
||||
use this to decide whether to use version-scripts or not.
|
||||
Additionally, the new 'version-scripts' meson-option allows
|
||||
specifying whether to use version-scripts, auto-detect whether to
|
||||
enable it, or disable it.
|
||||
|
||||
* Fix the export of `cflags` to also be exported in pkg-config, not
|
||||
just meson subprojects.
|
||||
|
||||
* Avoid NULL-pointers in compile-time macros. This silences possible
|
||||
false-positives from code sanitizers that otherwise trip over the
|
||||
NULL pointer dereferences.
|
||||
|
||||
Contributions from: David Rheinsberg, Evgeny Vereshchagin
|
||||
|
||||
- Brno, 2022-06-22
|
||||
|
||||
## CHANGES WITH 1.0.0:
|
||||
|
||||
* Initial release of c-stdaux.
|
||||
|
||||
* TBD
|
||||
Contributions from: David Rheinsberg, Lorenzo Arena, Michele Dionisio,
|
||||
Yuri Chornoivan
|
||||
|
||||
Contributions from: TBD
|
||||
|
||||
- TBD, YYYY-MM-DD
|
||||
- Dußlingen, 2022-05-12
|
||||
|
|
26
meson.build
26
meson.build
|
@ -1,3 +1,7 @@
|
|||
#
|
||||
# Global Project Setup
|
||||
#
|
||||
|
||||
project(
|
||||
'c-stdaux',
|
||||
'c',
|
||||
|
@ -6,7 +10,7 @@ project(
|
|||
],
|
||||
license: 'Apache',
|
||||
meson_version: '>=0.60.0',
|
||||
version: '1.0.0',
|
||||
version: '1.1.0',
|
||||
)
|
||||
major = meson.project_version().split('.')[0]
|
||||
project_description = 'Auxiliary macros and functions for the C standard library'
|
||||
|
@ -23,6 +27,7 @@ mod_pkgconfig = import('pkgconfig')
|
|||
# well. Since these exports are limited to strings, we need to be careful that
|
||||
# the individual entries do not contain spaces (see the assertion below).
|
||||
#
|
||||
|
||||
cflags = meson.get_compiler('c').get_supported_arguments(
|
||||
# Enable GNU features of our dependencies. See feature_test_macros(7).
|
||||
'-D_GNU_SOURCE',
|
||||
|
@ -81,6 +86,25 @@ cflags = meson.get_compiler('c').get_supported_arguments(
|
|||
assert(not ''.join(cflags).contains(' '), 'Malformed compiler flags.')
|
||||
add_project_arguments(cflags, language: 'c')
|
||||
|
||||
#
|
||||
# Version Scripts
|
||||
#
|
||||
|
||||
use_version_scripts = get_option('version-scripts')
|
||||
if use_version_scripts == 'auto'
|
||||
use_version_scripts = meson.get_compiler('c').has_link_argument(
|
||||
'-Wl,--version-script=' + (meson.current_source_dir() / 'src/libcstdaux.sym')
|
||||
) ? 'yes' : 'no'
|
||||
endif
|
||||
|
||||
#
|
||||
# Subdir Delegation
|
||||
#
|
||||
|
||||
subdir('src')
|
||||
|
||||
#
|
||||
# Meson Subproject Configuration
|
||||
#
|
||||
|
||||
meson.override_dependency('libcstdaux-'+major, libcstdaux_dep, static: true)
|
||||
|
|
7
meson_options.txt
Normal file
7
meson_options.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
option(
|
||||
'version-scripts',
|
||||
choices: ['yes', 'no', 'auto'],
|
||||
description: 'Enable GNU-version-scripts for linking',
|
||||
type: 'combo',
|
||||
value: 'auto',
|
||||
)
|
587
src/c-stdaux.h
587
src/c-stdaux.h
|
@ -1,12 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
/*
|
||||
* Auxiliary macros and functions for the C standard library
|
||||
* c-stdaux: Auxiliary macros and functions for the C standard library
|
||||
*
|
||||
* The `c-stdaux.h` header contains a collection of auxiliary macros and helper
|
||||
* functions around the functionality provided by the different C standard
|
||||
* library implementations, as well as other specifications implemented by
|
||||
* them.
|
||||
* Main public header of the c-stdaux library. All includes of this header are
|
||||
* part of the API!
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* DOC:
|
||||
*
|
||||
* The ``c-stdaux.h`` header contains a collection of auxiliary macros and
|
||||
* helper functions around the functionality provided by the different C
|
||||
* standard library implementations, as well as other specifications
|
||||
* implemented by them.
|
||||
*
|
||||
* Most of the helpers provided here provide aliases for common library and
|
||||
* compiler features. Furthermore, several helpers simply provide other calling
|
||||
|
@ -16,17 +27,27 @@
|
|||
*
|
||||
* The namespace used by this project is:
|
||||
*
|
||||
* * `c_*` for all common C symbols or definitions that behave like proper C
|
||||
* - ``c_*`` for all common C symbols or definitions that behave like proper C
|
||||
* entities (e.g., macros that protect against double-evaluation would use
|
||||
* lower-case names)
|
||||
* lower-case names).
|
||||
*
|
||||
* * `C_*` for all constants, as well as macros that may not be safe against
|
||||
* - ``C_*`` for all constants, as well as macros that may not be safe against
|
||||
* double evaluation.
|
||||
*
|
||||
* - ``c_internal_*`` and ``C_INTERNAL_*`` for all internal symbols that
|
||||
* should not be invoked by the caller and are not part of the API
|
||||
* guarantees.
|
||||
*/
|
||||
/**/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/**
|
||||
* DOC: Guaranteed Includes
|
||||
*
|
||||
* The ``c-stdaux.h`` header includes a set of C Standard Library headers as
|
||||
* well as UNIX headers. All those includes are guaranteed and part of the API.
|
||||
* See the actual header for a comprehensive list.
|
||||
*/
|
||||
/**/
|
||||
|
||||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
|
@ -48,44 +69,152 @@ extern "C" {
|
|||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
* Shortcuts for gcc attributes. See GCC manual for details. They're 1-to-1
|
||||
* mappings to the GCC equivalents. No additional magic here. They are
|
||||
* supported by other compilers as well.
|
||||
/**
|
||||
* DOC: Compiler Attributes
|
||||
*
|
||||
* The GCC compiler uses the ``__attribute__((__xyz__()))`` syntax to annotate
|
||||
* language entities with special attributes. Aliases are provided by this
|
||||
* header which map one-to-one to the respective compiler attributes.
|
||||
*
|
||||
* These attributes are not supported by all compilers, but are always provided
|
||||
* by this header. They are pre-processor macros and do not affect the
|
||||
* compilation, unless used. Note that most compilers support these, not just
|
||||
* GCC.
|
||||
*/
|
||||
/**/
|
||||
|
||||
/**
|
||||
* _c_cleanup_() - Cleanup attribute
|
||||
* @_x: Cleanup function to use
|
||||
*
|
||||
* Alias for ``__attribute__((__cleanup__(_x)))``.
|
||||
*/
|
||||
#define _c_cleanup_(_x) __attribute__((__cleanup__(_x)))
|
||||
|
||||
/**
|
||||
* _c_const_() - Const attribute
|
||||
*
|
||||
* Alias for ``__attribute__((__const__))``.
|
||||
*/
|
||||
#define _c_const_ __attribute__((__const__))
|
||||
|
||||
/**
|
||||
* _c_deprecated_() - Deprecated attribute
|
||||
*
|
||||
* Alias for ``__attribute__((__deprecated__))``.
|
||||
*/
|
||||
#define _c_deprecated_ __attribute__((__deprecated__))
|
||||
|
||||
/**
|
||||
* _c_hidden_() - Hidden attribute
|
||||
*
|
||||
* Alias for ``__attribute__((__visibility__("hidden")))``.
|
||||
*/
|
||||
#define _c_hidden_ __attribute__((__visibility__("hidden")))
|
||||
#define _c_likely_(_x) (__builtin_expect(!!(_x), 1))
|
||||
|
||||
/**
|
||||
* _c_packed_() - Packed attribute
|
||||
*
|
||||
* Alias for ``__attribute__((__packed__))``.
|
||||
*/
|
||||
#define _c_packed_ __attribute__((__packed__))
|
||||
|
||||
/**
|
||||
* _c_printf_() - Printf attribute
|
||||
* @_a: Format expression argument index
|
||||
* @_b: First format-parameter argument index
|
||||
*
|
||||
* Alias for ``__attribute__((__format__(printf, _a, _b)))``.
|
||||
*/
|
||||
#define _c_printf_(_a, _b) __attribute__((__format__(printf, _a, _b)))
|
||||
|
||||
/**
|
||||
* _c_public_() - Public attribute
|
||||
*
|
||||
* Alias for ``__attribute__((__visibility__("default")))``.
|
||||
*/
|
||||
#define _c_public_ __attribute__((__visibility__("default")))
|
||||
|
||||
/**
|
||||
* _c_pure_() - Pure attribute
|
||||
*
|
||||
* Alias for ``__attribute__((__pure__))``.
|
||||
*/
|
||||
#define _c_pure_ __attribute__((__pure__))
|
||||
|
||||
/**
|
||||
* _c_sentinel_() - Sentinel attribute
|
||||
*
|
||||
* Alias for ``__attribute__((__sentinel__))``.
|
||||
*/
|
||||
#define _c_sentinel_ __attribute__((__sentinel__))
|
||||
#define _c_unlikely_(_x) (__builtin_expect(!!(_x), 0))
|
||||
|
||||
/**
|
||||
* _c_unused_() - Unused attribute
|
||||
*
|
||||
* Alias for ``__attribute__((__unused__))``.
|
||||
*/
|
||||
#define _c_unused_ __attribute__((__unused__))
|
||||
|
||||
/**
|
||||
* C_EXPR_ASSERT() - create expression with assertion
|
||||
* @_expr: expression to evaluate to
|
||||
* @_assertion: arbitrary assertion
|
||||
* @_message: message associated with the assertion
|
||||
* DOC: Compiler Intrinsics
|
||||
*
|
||||
* This macro simply evaluates to @_expr. That is, it can be used in any
|
||||
* context that expects an expression like @_expr. Additionally, it takes an
|
||||
* assertion as @_assertion and evaluates it through _Static_assert(), using
|
||||
* @_message as debug message.
|
||||
*
|
||||
* The _Static_assert() builtin of C11 is defined as statement and thus cannot
|
||||
* be used in expressions. This macro circumvents this restriction.
|
||||
*
|
||||
* Return: Evaluates to @_expr.
|
||||
* Aliases for common compiler extensions and intrinsics are provided similar
|
||||
* to the compiler attributes. They are pure preprocessor aliases and do not
|
||||
* affect compilation unless used.
|
||||
*/
|
||||
/**/
|
||||
|
||||
/**
|
||||
* _c_likely_() - Likely attribute
|
||||
* @_x: Expression to evaluate
|
||||
*
|
||||
* Alias for ``__builtin_expect(!!(_x), 1)``.
|
||||
*
|
||||
* Return: The expression ``_x`` is evaluated and returned.
|
||||
*/
|
||||
#define _c_likely_(_x) (__builtin_expect(!!(_x), 1))
|
||||
|
||||
/**
|
||||
* _c_unlikely_() - Unlikely attribute
|
||||
* @_x: Expression to evaluate
|
||||
*
|
||||
* Alias for ``__builtin_expect(!!(_x), 0)``.
|
||||
*
|
||||
* Return: The expression ``_x`` is evaluated and returned.
|
||||
*/
|
||||
#define _c_unlikely_(_x) (__builtin_expect(!!(_x), 0))
|
||||
|
||||
/**
|
||||
* DOC: Utility Macros
|
||||
*
|
||||
* A set of utility macros is provided which aids in creating safe macros
|
||||
* suitable for use in other pre-processor statements as well as in C
|
||||
* expressions.
|
||||
*/
|
||||
/**/
|
||||
|
||||
/**
|
||||
* C_EXPR_ASSERT() - Create expression with assertion
|
||||
* @_expr: Expression to evaluate to
|
||||
* @_assertion: Arbitrary assertion
|
||||
* @_message: Message associated with the assertion
|
||||
*
|
||||
* This macro simply evaluates to ``_expr``. That is, it can be used in any
|
||||
* context that expects an expression like ``_expr``. Additionally, it takes an
|
||||
* assertion as ``_assertion`` and evaluates it through ``_Static_assert()``,
|
||||
* using ``_message`` as debug message.
|
||||
*
|
||||
* The ``_Static_assert()`` builtin of C11 is defined as statement and thus
|
||||
* cannot be used in expressions. This macro circumvents this restriction.
|
||||
*
|
||||
* Return: Evaluates to ``_expr``.
|
||||
*/
|
||||
#define C_EXPR_ASSERT(_expr, _assertion, _message) C_INTERNAL_EXPR_ASSERT((_expr), (_assertion), _message)
|
||||
#if defined(__COVERITY__) // Coverity cannot const-fold __builtin_choose_expr()
|
||||
# define C_EXPR_ASSERT(_expr, _assertion, _message) (_expr)
|
||||
# define C_INTERNAL_EXPR_ASSERT(_expr, _assertion, _message) (_expr)
|
||||
#else
|
||||
# define C_EXPR_ASSERT(_expr, _assertion, _message) \
|
||||
# define C_INTERNAL_EXPR_ASSERT(_expr, _assertion, _message) \
|
||||
/* indentation and line-split to get better diagnostics */ \
|
||||
(__builtin_choose_expr( \
|
||||
!!(1 + 0 * sizeof( \
|
||||
|
@ -99,8 +228,8 @@ _Static_assert(_assertion, _message); \
|
|||
#endif
|
||||
|
||||
/**
|
||||
* C_STRINGIFY() - stringify a token, but evaluate it first
|
||||
* @_x: token to evaluate and stringify
|
||||
* C_STRINGIFY() - Stringify a token, but evaluate it first
|
||||
* @_x: Token to evaluate and stringify
|
||||
*
|
||||
* Return: Evaluates to a constant string literal
|
||||
*/
|
||||
|
@ -108,9 +237,9 @@ _Static_assert(_assertion, _message); \
|
|||
#define C_INTERNAL_STRINGIFY(_x) #_x
|
||||
|
||||
/**
|
||||
* C_CONCATENATE() - concatenate two tokens, but evaluate them first
|
||||
* @_x: first token
|
||||
* @_y: second token
|
||||
* C_CONCATENATE() - Concatenate two tokens, but evaluate them first
|
||||
* @_x: First token
|
||||
* @_y: Second token
|
||||
*
|
||||
* Return: Evaluates to a constant identifier
|
||||
*/
|
||||
|
@ -118,8 +247,8 @@ _Static_assert(_assertion, _message); \
|
|||
#define C_INTERNAL_CONCATENATE(_x, _y) _x ## _y
|
||||
|
||||
/**
|
||||
* C_EXPAND() - expand a tuple to a series of its values
|
||||
* @_x: tuple to expand
|
||||
* C_EXPAND() - Expand a tuple to a series of its values
|
||||
* @_x: Tuple to expand
|
||||
*
|
||||
* Return: Evaluates to the expanded tuple
|
||||
*/
|
||||
|
@ -127,29 +256,32 @@ _Static_assert(_assertion, _message); \
|
|||
#define C_INTERNAL_EXPAND(...) __VA_ARGS__
|
||||
|
||||
/**
|
||||
* C_VAR() - generate unique variable name
|
||||
* @_x: name of variable, optional
|
||||
* @_uniq: unique prefix, usually provided by __COUNTER__, optional
|
||||
* C_VAR() - Generate unique variable name
|
||||
* @_x: Name of variable, optional
|
||||
* @_uniq: Unique prefix, usually provided by ``__COUNTER__``, optional
|
||||
*
|
||||
* This macro shall be used to generate unique variable names, that will not be
|
||||
* shadowed by recursive macro invocations. It is effectively a
|
||||
* C_CONCATENATE of both arguments, but also provides a globally separated
|
||||
* prefix and makes the code better readable.
|
||||
* :c:macro:`C_CONCATENATE` of both arguments, but also provides a globally
|
||||
* separated prefix and makes the code better readable.
|
||||
*
|
||||
* The second argument is optional. If not given, __LINE__ is implied, and as
|
||||
* such the macro will generate the same identifier if used multiple times on
|
||||
* the same code-line (or within a macro). This should be used if recursive
|
||||
* The second argument is optional. If not given, ``__LINE__`` is implied, and
|
||||
* as such the macro will generate the same identifier if used multiple times
|
||||
* on the same code-line (or within a macro). This should be used if recursive
|
||||
* calls into the macro are not expected. In fact, no argument is necessary in
|
||||
* this case, as a mere `C_VAR` will evaluate to a valid variable name.
|
||||
* this case, as a mere ``C_VAR`` will evaluate to a valid variable name.
|
||||
*
|
||||
* This helper may be used by macro implementations that might reasonable well
|
||||
* be called in a stacked fasion, like:
|
||||
*
|
||||
* .. code-block:: c
|
||||
*
|
||||
* c_max(foo, c_max(bar, baz))
|
||||
*
|
||||
* Such a stacked call of c_max() might cause compiler warnings of shadowed
|
||||
* variables in the definition of c_max(). By using C_VAR(), such warnings
|
||||
* can be silenced as each evaluation of c_max() uses unique variable names.
|
||||
* Such a stacked call of :c:macro:`c_max()` might cause compiler warnings of
|
||||
* shadowed variables in the definition of :c:macro:`c_max()`. By using
|
||||
* ``C_VAR()``, such warnings can be silenced as each evaluation of
|
||||
* :c:macro:`c_max()` uses unique variable names.
|
||||
*
|
||||
* Return: This evaluates to a constant identifier.
|
||||
*/
|
||||
|
@ -159,28 +291,28 @@ _Static_assert(_assertion, _message); \
|
|||
#define C_VAR2(_x, _uniq) C_CONCATENATE(c_internal_var_unique_, C_CONCATENATE(_uniq, _x))
|
||||
|
||||
/**
|
||||
* C_CC_MACRO1() - provide safe environment to a macro
|
||||
* @_call: macro to call
|
||||
* @_x1: first argument
|
||||
* @...: further arguments to forward unmodified to @_call
|
||||
* C_CC_MACRO1() - Provide safe environment to a macro
|
||||
* @_call: Macro to call
|
||||
* @_x1: First argument
|
||||
* @...: Further arguments to forward unmodified to ``_call``
|
||||
*
|
||||
* This function simplifies the implementation of macros. Whenever you
|
||||
* implement a macro, provide the internal macro name as @_call and its
|
||||
* argument as @_x1. Inside of your internal macro, you...
|
||||
* implement a macro, provide the internal macro name as ``_call`` and its
|
||||
* argument as ``_x1``. Inside of your internal macro, you...
|
||||
*
|
||||
* - ...are safe against multiple evaluation errors, since C_CC_MACRO1 will
|
||||
* store the initial parameters in temporary variables.
|
||||
* - are safe against multiple evaluation errors, since ``C_CC_MACRO1``
|
||||
* will store the initial parameters in temporary variables.
|
||||
*
|
||||
* - ...support constant folding, as C_CC_MACRO1 takes care to invoke your
|
||||
* macro with the original values, if they are compile-time constant.
|
||||
* - support constant folding, as ``C_CC_MACRO1`` takes care to invoke your
|
||||
* macro with the original values, if they are compile-time constant.
|
||||
*
|
||||
* - ...have unique variable names for recursive callers and will not run into
|
||||
* variable-shadowing-warnings accidentally.
|
||||
* - have unique variable names for recursive callers and will not run into
|
||||
* variable-shadowing-warnings accidentally.
|
||||
*
|
||||
* - ...have properly typed arguments as C_CC_MACRO1 stores the original
|
||||
* arguments in an `__auto_type` temporary variable.
|
||||
* - have properly typed arguments as ``C_CC_MACRO1`` stores the original
|
||||
* arguments in an ``__auto_type`` temporary variable.
|
||||
*
|
||||
* Return: Result of @_call is returned.
|
||||
* Return: Result of ``_call`` is returned.
|
||||
*/
|
||||
#define C_CC_MACRO1(_call, _x1, ...) C_INTERNAL_CC_MACRO1(_call, __COUNTER__, (_x1), ## __VA_ARGS__)
|
||||
#define C_INTERNAL_CC_MACRO1(_call, _x1q, _x1, ...) \
|
||||
|
@ -193,15 +325,15 @@ _Static_assert(_assertion, _message); \
|
|||
}))
|
||||
|
||||
/**
|
||||
* C_CC_MACRO2() - provide safe environment to a macro
|
||||
* @_call: macro to call
|
||||
* @_x1: first argument
|
||||
* @_x2: second argument
|
||||
* @...: further arguments to forward unmodified to @_call
|
||||
* C_CC_MACRO2() - Provide safe environment to a macro
|
||||
* @_call: Macro to call
|
||||
* @_x1: First argument
|
||||
* @_x2: Second argument
|
||||
* @...: Further arguments to forward unmodified to ``_call``
|
||||
*
|
||||
* This is the 2-argument equivalent of C_CC_MACRO1().
|
||||
* This is the 2-argument equivalent of :c:macro:`C_CC_MACRO1()`.
|
||||
*
|
||||
* Return: Result of @_call is returned.
|
||||
* Return: Result of ``_call`` is returned.
|
||||
*/
|
||||
#define C_CC_MACRO2(_call, _x1, _x2, ...) C_INTERNAL_CC_MACRO2(_call, __COUNTER__, (_x1), __COUNTER__, (_x2), ## __VA_ARGS__)
|
||||
#define C_INTERNAL_CC_MACRO2(_call, _x1q, _x1, _x2q, _x2, ...) \
|
||||
|
@ -215,16 +347,16 @@ _Static_assert(_assertion, _message); \
|
|||
}))
|
||||
|
||||
/**
|
||||
* C_CC_MACRO3() - provide safe environment to a macro
|
||||
* @_call: macro to call
|
||||
* @_x1: first argument
|
||||
* @_x2: second argument
|
||||
* @_x3: third argument
|
||||
* @...: further arguments to forward unmodified to @_call
|
||||
* C_CC_MACRO3() - Provide safe environment to a macro
|
||||
* @_call: Macro to call
|
||||
* @_x1: First argument
|
||||
* @_x2: Second argument
|
||||
* @_x3: Third argument
|
||||
* @...: Further arguments to forward unmodified to ``_call``
|
||||
*
|
||||
* This is the 3-argument equivalent of C_CC_MACRO1().
|
||||
* This is the 3-argument equivalent of :c:macro:`C_CC_MACRO1()`.
|
||||
*
|
||||
* Return: Result of @_call is returned.
|
||||
* Return: Result of ``_call`` is returned.
|
||||
*/
|
||||
#define C_CC_MACRO3(_call, _x1, _x2, _x3, ...) C_INTERNAL_CC_MACRO3(_call, __COUNTER__, (_x1), __COUNTER__, (_x2), __COUNTER__, (_x3), ## __VA_ARGS__)
|
||||
#define C_INTERNAL_CC_MACRO3(_call, _x1q, _x1, _x2q, _x2, _x3q, _x3, ...) \
|
||||
|
@ -239,8 +371,17 @@ _Static_assert(_assertion, _message); \
|
|||
}))
|
||||
|
||||
/**
|
||||
* C_ARRAY_SIZE() - calculate number of array elements at compile time
|
||||
* @_x: array to calculate size of
|
||||
* DOC: Standard Library Utilities
|
||||
*
|
||||
* The C Standard Library lacks some crucial and basic support functions. This
|
||||
* section describes the set of helpers provided as extension to the standard
|
||||
* library.
|
||||
*/
|
||||
/**/
|
||||
|
||||
/**
|
||||
* C_ARRAY_SIZE() - Calculate number of array elements at compile time
|
||||
* @_x: Array to calculate size of
|
||||
*
|
||||
* Return: Evaluates to a constant integer expression.
|
||||
*/
|
||||
|
@ -258,9 +399,8 @@ _Static_assert(_assertion, _message); \
|
|||
)
|
||||
|
||||
/**
|
||||
* C_DECIMAL_MAX() - calculate maximum length of the decimal
|
||||
* representation of an integer
|
||||
* @_type: integer variable/type
|
||||
* C_DECIMAL_MAX() - Calculate maximum length of a decimal representation
|
||||
* @_type: Integer variable/type
|
||||
*
|
||||
* This calculates the bytes required for the decimal representation of an
|
||||
* integer of the given type. It accounts for a possible +/- prefix, but it
|
||||
|
@ -292,28 +432,41 @@ _Static_assert(_assertion, _message); \
|
|||
)
|
||||
|
||||
/**
|
||||
* c_container_of() - cast a member of a structure out to the containing structure
|
||||
* @_ptr: pointer to the member or NULL
|
||||
* @_type: type of the container struct this is embedded in
|
||||
* @_member: name of the member within the struct
|
||||
* c_container_of() - Cast a member of a structure out to the containing type
|
||||
* @_ptr: Pointer to the member or NULL
|
||||
* @_type: Type of the container struct this is embedded in
|
||||
* @_member: Name of the member within the struct
|
||||
*
|
||||
* This uses `offsetof(3)` to turn a pointer to a structure-member into a
|
||||
* This uses ``offsetof(3)`` to turn a pointer to a structure-member into a
|
||||
* pointer to the surrounding structure.
|
||||
*
|
||||
* Return: Pointer to the surrounding object.
|
||||
*/
|
||||
#define c_container_of(_ptr, _type, _member) C_CC_MACRO1(C_CONTAINER_OF, (_ptr), _type, _member)
|
||||
#define C_CONTAINER_OF(_ptr, _type, _member) \
|
||||
__extension__ ({ \
|
||||
/* trigger warning if types do not match */ \
|
||||
(void)(&((_type *)0)->_member == (_ptr)); \
|
||||
_ptr ? (_type*)( (char*)_ptr - offsetof(_type, _member) ) : NULL; \
|
||||
})
|
||||
C_EXPR_ASSERT( \
|
||||
(_ptr ? (_type*)c_internal_container_of((void *)_ptr, offsetof(_type, _member)) : NULL), \
|
||||
__builtin_types_compatible_p( \
|
||||
__typeof__(*(_ptr)), \
|
||||
__typeof__(((_type){})._member) \
|
||||
) || __builtin_types_compatible_p( \
|
||||
__typeof__(_ptr), \
|
||||
__typeof__(NULL) \
|
||||
), \
|
||||
"Invalid use of C_CONTAINER_OF()" \
|
||||
)
|
||||
static inline void *c_internal_container_of(void *ptr, size_t offset) {
|
||||
/*
|
||||
* Arithmetic on NULL is UB, even if in dead-code. Hide it in a proper
|
||||
* C function, so the macro never emits it as code.
|
||||
*/
|
||||
return (char *)ptr - offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* c_max() - compute maximum of two values
|
||||
* @_a: value A
|
||||
* @_b: value B
|
||||
* c_max() - Compute maximum of two values
|
||||
* @_a: Value A
|
||||
* @_b: Value B
|
||||
*
|
||||
* Calculate the maximum of both passed values. Both arguments are evaluated
|
||||
* exactly once, under all circumstances. Furthermore, if both values are
|
||||
|
@ -329,9 +482,9 @@ _Static_assert(_assertion, _message); \
|
|||
#define C_MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b))
|
||||
|
||||
/**
|
||||
* c_min() - compute minimum of two values
|
||||
* @_a: value A
|
||||
* @_b: value B
|
||||
* c_min() - Compute minimum of two values
|
||||
* @_a: Value A
|
||||
* @_b: Value B
|
||||
*
|
||||
* Calculate the minimum of both passed values. Both arguments are evaluated
|
||||
* exactly once, under all circumstances. Furthermore, if both values are
|
||||
|
@ -347,32 +500,32 @@ _Static_assert(_assertion, _message); \
|
|||
#define C_MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b))
|
||||
|
||||
/**
|
||||
* c_less_by() - calculate clamped difference of two values
|
||||
* @_a: minuend
|
||||
* @_b: subtrahend
|
||||
* c_less_by() - Calculate clamped difference of two values
|
||||
* @_a: Minuend
|
||||
* @_b: Subtrahend
|
||||
*
|
||||
* Calculate [_a - _b], but clamp the result to 0. Both arguments are evaluated
|
||||
* exactly once, under all circumstances. Furthermore, if both values are
|
||||
* constant expressions, the result will be constant as well.
|
||||
* Calculate ``_a - _b``, but clamp the result to 0. Both arguments are
|
||||
* evaluated exactly once, under all circumstances. Furthermore, if both values
|
||||
* are constant expressions, the result will be constant as well.
|
||||
*
|
||||
* The comparison of their values is performed with the types given by the
|
||||
* caller. It is the caller's responsibility to convert them to suitable types
|
||||
* if necessary.
|
||||
*
|
||||
* Return: This computes [_a - _b], if [_a > _b]. Otherwise, 0 is returned.
|
||||
* Return: This computes ``_a - _b``, if ``_a > _b``. Otherwise, 0 is returned.
|
||||
*/
|
||||
#define c_less_by(_a, _b) C_CC_MACRO2(C_LESS_BY, (_a), (_b))
|
||||
#define C_LESS_BY(_a, _b) ((_a) > (_b) ? (_a) - (_b) : 0)
|
||||
|
||||
/**
|
||||
* c_clamp() - clamp value to lower and upper boundary
|
||||
* @_x: value to clamp
|
||||
* @_low: lower boundary
|
||||
* @_high: higher boundary
|
||||
* c_clamp() - Clamp value to lower and upper boundary
|
||||
* @_x: Value to clamp
|
||||
* @_low: Lower boundary
|
||||
* @_high: Higher boundary
|
||||
*
|
||||
* This clamps @_x to the lower and higher bounds given as @_low and @_high.
|
||||
* All arguments are evaluated exactly once, and yield a constant expression if
|
||||
* all arguments are constant as well.
|
||||
* This clamps ``_x`` to the lower and higher bounds given as ``_low`` and
|
||||
* ``_high``. All arguments are evaluated exactly once, and yield a constant
|
||||
* expression if all arguments are constant as well.
|
||||
*
|
||||
* The comparison of their values is performed with the types given by the
|
||||
* caller. It is the caller's responsibility to convert them to suitable types
|
||||
|
@ -384,18 +537,18 @@ _Static_assert(_assertion, _message); \
|
|||
#define C_CLAMP(_x, _low, _high) ((_x) > (_high) ? (_high) : (_x) < (_low) ? (_low) : (_x))
|
||||
|
||||
/**
|
||||
* c_div_round_up() - calculate integer quotient but round up
|
||||
* @_x: dividend
|
||||
* @_y: divisor
|
||||
* c_div_round_up() - Calculate integer quotient but round up
|
||||
* @_x: Dividend
|
||||
* @_y: Divisor
|
||||
*
|
||||
* Calculates [x / y] but rounds up the result to the next integer. All
|
||||
* Calculates ``x / y`` but rounds up the result to the next integer. All
|
||||
* arguments are evaluated exactly once, and yield a constant expression if all
|
||||
* arguments are constant.
|
||||
*
|
||||
* Note:
|
||||
* [(x + y - 1) / y] suffers from an integer overflow, even though the
|
||||
* **Note:**
|
||||
* ``(x + y - 1) / y`` suffers from an integer overflow, even though the
|
||||
* computation should be possible in the given type. Therefore, we use
|
||||
* [x / y + !!(x % y)]. Note that on most CPUs a division returns both the
|
||||
* ``x / y + !!(x % y)``. Note that on most CPUs a division returns both the
|
||||
* quotient and the remainder, so both should be equally fast. Furthermore, if
|
||||
* the divisor is a power of two, the compiler will optimize it, anyway.
|
||||
*
|
||||
|
@ -409,34 +562,35 @@ _Static_assert(_assertion, _message); \
|
|||
#define C_DIV_ROUND_UP(_x, _y) ((_x) / (_y) + !!((_x) % (_y)))
|
||||
|
||||
/**
|
||||
* c_align_to() - align value to a multiple
|
||||
* @_val: value to align
|
||||
* @_to: align to multiple of this
|
||||
* c_align_to() - Align value to a multiple
|
||||
* @_val: Value to align
|
||||
* @_to: Align to multiple of this
|
||||
*
|
||||
* This aligns @_val to a multiple of @_to. If @_val is already a multiple of
|
||||
* @_to, @_val is returned unchanged. This function operates within the
|
||||
* boundaries of the type of @_val and @_to. Make sure to cast them if needed.
|
||||
* This aligns ``_val`` to a multiple of ``_to``. If ``_val`` is already a
|
||||
* multiple of ``_to``, ``_val`` is returned unchanged. This function operates
|
||||
* within the boundaries of the type of ``_val`` and ``_to``. Make sure to cast
|
||||
* them if needed.
|
||||
*
|
||||
* The arguments of this macro are evaluated exactly once. If both arguments
|
||||
* are a constant expression, this also yields a constant return value.
|
||||
*
|
||||
* Note that @_to must be a power of 2, otherwise the behavior will not match
|
||||
* expectations.
|
||||
* Note that ``_to`` must be a power of 2, otherwise the behavior will not
|
||||
* match expectations.
|
||||
*
|
||||
* Return: @_val aligned to a multiple of @_to
|
||||
* Return: ``_val`` aligned to a multiple of ``_to``.
|
||||
*/
|
||||
#define c_align_to(_val, _to) C_CC_MACRO2(C_ALIGN_TO, (_val), (_to))
|
||||
#define C_ALIGN_TO(_val, _to) (((_val) + (_to) - 1) & ~((_to) - 1))
|
||||
|
||||
/**
|
||||
* c_assert() - runtime assertions
|
||||
* @expr_result: result of an expression
|
||||
* c_assert() - Runtime assertions
|
||||
* @expr_result: Result of an expression
|
||||
*
|
||||
* This function behaves like the standard `assert(3)` macro. That is, if
|
||||
* `NDEBUG` is defined, it is a no-op. In all other cases it will assert that
|
||||
* This function behaves like the standard ``assert(3)`` macro. That is, if
|
||||
* ``NDEBUG`` is defined, it is a no-op. In all other cases it will assert that
|
||||
* the result of the passed expression is true.
|
||||
*
|
||||
* Unlike the standard `assert(3)` macro, this function always evaluates its
|
||||
* Unlike the standard ``assert(3)`` macro, this function always evaluates its
|
||||
* argument. This means side-effects will always be evaluated! However, if the
|
||||
* macro is used with constant expressions, the compiler will be able to
|
||||
* optimize it away.
|
||||
|
@ -447,13 +601,13 @@ _Static_assert(_assertion, _message); \
|
|||
})
|
||||
|
||||
/**
|
||||
* c_errno() - return valid errno
|
||||
* c_errno() - Return valid errno
|
||||
*
|
||||
* This helper should be used to shut up gcc if you know 'errno' is valid (ie.,
|
||||
* errno is > 0). Instead of "return -errno;", use
|
||||
* "return -c_errno();" It will suppress bogus gcc warnings in case it assumes
|
||||
* 'errno' might be 0 (or <0) and thus the caller's error-handling might not be
|
||||
* triggered.
|
||||
* This helper should be used to shut up gcc if you know ``errno`` is valid
|
||||
* (ie., ``errno`` is greater than 0). Instead of ``return -errno;``, use
|
||||
* ``return -c_errno();`` It will suppress bogus gcc warnings in case it
|
||||
* assumes ``errno`` might be 0 (or smaller than 0) and thus the caller's
|
||||
* error-handling might not be triggered.
|
||||
*
|
||||
* This helper should be avoided whenever possible. However, occasionally we
|
||||
* really want to shut up gcc (especially with static/inline functions). In
|
||||
|
@ -470,62 +624,179 @@ static inline int c_errno(void) {
|
|||
return _c_likely_(errno > 0) ? errno : ENOTRECOVERABLE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Common Destructors
|
||||
/**
|
||||
* c_memset() - Fill memory region with constant byte
|
||||
* @p: Pointer to memory region, if non-empty
|
||||
* @c: Value to fill with
|
||||
* @n: Size of the memory region in bytes
|
||||
*
|
||||
* Followingly, there're a bunch of common 'static inline' destructors, which
|
||||
* simply call the function that they're named after, but return "INVALID"
|
||||
* instead of "void". This allows direct assignment to any member-field and/or
|
||||
* variable they're defined in, like:
|
||||
* This function works like ``memset(3)`` if ``n`` is non-zero. If ``n`` is
|
||||
* zero, this function is a no-op. Therefore, unlike ``memset(3)`` it is safe
|
||||
* to call this function with ``NULL`` as ``p`` if ``n`` is 0.
|
||||
*
|
||||
* foo = c_free(foo);
|
||||
* Return: ``p`` is returned.
|
||||
*/
|
||||
static inline void *c_memset(void *p, int c, size_t n) {
|
||||
if (n > 0)
|
||||
memset(p, c, n);
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* c_memzero() - Clear memory area
|
||||
* @p: Pointer to memory region, if non-empty
|
||||
* @n: Size of the memory region in bytes
|
||||
*
|
||||
* or
|
||||
* Clear a memory area to 0. If the memory area is empty, this is a no-op.
|
||||
* Similar to ``c_memset()``, this function allows ``p`` to be ``NULL`` if the
|
||||
* area is empty.
|
||||
*
|
||||
* foo->bar = c_close(foo->bar);
|
||||
* Return: ``p`` is returned.
|
||||
*/
|
||||
static inline void *c_memzero(void *p, size_t n) {
|
||||
return c_memset(p, 0, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* c_memcpy() - Copy memory area
|
||||
* @dst: Pointer to target area
|
||||
* @src: Pointer to source area
|
||||
* @n: Length of area to copy
|
||||
*
|
||||
* Copy the memory of size ``n`` from ``src`` to ``dst``, just as ``memcpy(3)``
|
||||
* does, except this function allows either to be ``NULL`` if ``n`` is zero. In
|
||||
* the latter case, the operation is a no-op.
|
||||
*
|
||||
* Return: ``p`` is returned.
|
||||
*/
|
||||
static inline void *c_memcpy(void *dst, const void *src, size_t n) {
|
||||
if (n > 0)
|
||||
memcpy(dst, src, n);
|
||||
return dst;
|
||||
}
|
||||
|
||||
/**
|
||||
* DOC: Common Destructors
|
||||
*
|
||||
* A set of destructors is provided which extends standard library destructors
|
||||
* to adhere to some adjuvant rules. In particular, they return an invalid
|
||||
* value of the particular object, rather than void. This allows direct
|
||||
* assignment to any member-field and/or variable they are defined in, like:
|
||||
*
|
||||
* .. code-block:: c
|
||||
*
|
||||
* foo = c_free(foo);
|
||||
* foo->bar = c_close(foo->bar);
|
||||
*
|
||||
* Furthermore, all those destructors can be safely called with the "INVALID"
|
||||
* value as argument, and they will be a no-op.
|
||||
*/
|
||||
/**/
|
||||
|
||||
/**
|
||||
* c_free() - Destructor-wrapper for free()
|
||||
* @p: Value to pass to destructor, or NULL
|
||||
*
|
||||
* Wrapper around ``free()``, but always returns ``NULL``.
|
||||
*
|
||||
* Return: NULL is returned.
|
||||
*/
|
||||
static inline void *c_free(void *p) {
|
||||
free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* c_close() - Destructor-wrapper for close()
|
||||
* @fd: File-descriptor to pass to destructor, or negative value
|
||||
*
|
||||
* Wrapper around ``close()``, but a no-op if a negative value is provided.
|
||||
* Always returns ``-1``.
|
||||
*
|
||||
* Return: -1 is returned.
|
||||
*/
|
||||
static inline int c_close(int fd) {
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* c_fclose() - Destructor-wrapper for fclose()
|
||||
* @f: File handle to pass to destructor, or NULL
|
||||
*
|
||||
* Wrapper around ``fclose()``, but a no-op if ``NULL`` is passed. Always
|
||||
* returns ``NULL``.
|
||||
*
|
||||
* Return: NULL is returned.
|
||||
*/
|
||||
static inline FILE *c_fclose(FILE *f) {
|
||||
if (f)
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* c_closedir() - Destructor-wrapper for closedir)
|
||||
* @d: Directory handle to pass to destructor, or NULL
|
||||
*
|
||||
* Wrapper around ``closedir()``, but a no-op if ``NULL`` is passed. Always
|
||||
* returns ``NULL``.
|
||||
*
|
||||
* Return: NULL is returned.
|
||||
*/
|
||||
static inline DIR *c_closedir(DIR *d) {
|
||||
if (d)
|
||||
closedir(d);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Common Cleanup Helpers
|
||||
/**
|
||||
* DOC: Common Cleanup Helpers
|
||||
*
|
||||
* A bunch of _c_cleanup_(foobarp) helpers that are used all over the place.
|
||||
* Note that all of those have the "if (IS_INVALID(foobar))" check inline, so
|
||||
* compilers can optimize most of the cleanup-paths in a function. However, if
|
||||
* the function they call already does this _inline_, then it might be skipped.
|
||||
* A set of helpers that aid in creating functions suitable for use with
|
||||
* :c:macro:`_c_cleanup_()`. Furthermore, a collection of predefined cleanup
|
||||
* functions of a set of standard library objects ready for use with
|
||||
* :c:macro:`_c_cleanup_()`.
|
||||
* Those cleanup helpers are always suffixed with a ``p``.
|
||||
*
|
||||
* The helpers that are provided are:
|
||||
*
|
||||
* - ``c_freep()``: Wrapper around :c:func:`c_free()`.
|
||||
* - ``c_closep()``: Wrapper around :c:func:`c_close()`.
|
||||
* - ``c_fclosep()``: Wrapper around :c:func:`c_fclose()`.
|
||||
* - ``c_closedirp()``: Wrapper around :c:func:`c_closedir()`.
|
||||
*/
|
||||
/**/
|
||||
|
||||
/**
|
||||
* C_DEFINE_CLEANUP() - Define cleanup helper
|
||||
* @_type: Type of object to cleanup
|
||||
* @_func: Destructor of the respective type
|
||||
*
|
||||
* Define a C static inline function that takes a single argument of type
|
||||
* `_type` and calls `_func` on it, if its dereferenced value of its argument
|
||||
* evaluates to true. Otherwise, it is a no-op.
|
||||
*
|
||||
* This macro allows for very simple and fast creation of cleanup helpers for
|
||||
* use with ``_c_cleanup_()``, based on any destructor and type you provide to
|
||||
* it.
|
||||
*/
|
||||
#define C_DEFINE_CLEANUP(_type, _func) \
|
||||
static inline void _func ## p(_type *p) { \
|
||||
if (*p) \
|
||||
_func(*p); \
|
||||
} struct c_internal_trailing_semicolon
|
||||
|
||||
/**
|
||||
* C_DEFINE_DIRECT_CLEANUP() - Define direct cleanup helper
|
||||
* @_type: Type of object to cleanup
|
||||
* @_func: Destructor of the respective type
|
||||
*
|
||||
* This works like :c:macro:`C_DEFINE_CLEANUP()` but does not check the
|
||||
* dereferenced value of its argument. It always unconditionally invokes the
|
||||
* destructor.
|
||||
*/
|
||||
#define C_DEFINE_DIRECT_CLEANUP(_type, _func) \
|
||||
static inline void _func ## p(_type *p) { \
|
||||
_func(*p); \
|
||||
|
|
5
src/docs/api.rst
Normal file
5
src/docs/api.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
API
|
||||
===
|
||||
|
||||
.. c:autodoc:: c-*.h
|
||||
:transform: kerneldoc
|
43
src/docs/conf.py
Normal file
43
src/docs/conf.py
Normal file
|
@ -0,0 +1,43 @@
|
|||
#
|
||||
# Sphinx Documentation Configuration
|
||||
#
|
||||
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
|
||||
import capidocs.kerneldoc
|
||||
import hawkmoth
|
||||
|
||||
# Global Setup
|
||||
|
||||
project = 'c-stdaux'
|
||||
|
||||
author = 'C-Util Community'
|
||||
copyright = '2022, C-Util Community'
|
||||
|
||||
# Hawkmoth C-Audodoc Setup
|
||||
|
||||
capidocs.kerneldoc.hawkmoth_conf()
|
||||
|
||||
# Extensions
|
||||
|
||||
exclude_patterns = []
|
||||
|
||||
extensions = [
|
||||
'hawkmoth',
|
||||
]
|
||||
|
||||
# Hawkmoth Options
|
||||
|
||||
cautodoc_clang = capidocs.kerneldoc.hawkmoth_include_args()
|
||||
|
||||
cautodoc_root = os.path.abspath('..')
|
||||
|
||||
cautodoc_transformations = {
|
||||
'kerneldoc': capidocs.kerneldoc.hawkmoth_converter,
|
||||
}
|
||||
|
||||
# HTML Options
|
||||
|
||||
html_theme = 'sphinx_rtd_theme'
|
14
src/docs/index.rst
Normal file
14
src/docs/index.rst
Normal file
|
@ -0,0 +1,14 @@
|
|||
Introduction
|
||||
============
|
||||
|
||||
The **c-stdaux** project contains support-macros and auxiliary functions around
|
||||
the functionality of common C standard libraries. This includes helpers for the
|
||||
ISO-C Standard Library, but also other common specifications like POSIX or
|
||||
common extended features of wide-spread compilers like gcc and clang.
|
||||
|
||||
.. toctree::
|
||||
:caption: Library Documentation
|
||||
:hidden:
|
||||
|
||||
self
|
||||
api
|
3
src/docs/requirements.txt
Normal file
3
src/docs/requirements.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
c-apidocs>=0.0.2
|
||||
clang>=6
|
||||
hawkmoth>=0.7
|
6
src/libcstdaux.sym
Normal file
6
src/libcstdaux.sym
Normal file
|
@ -0,0 +1,6 @@
|
|||
LIBCSTDAUX_1 {
|
||||
global:
|
||||
c_internal_dummy;
|
||||
local:
|
||||
*;
|
||||
};
|
|
@ -4,9 +4,14 @@
|
|||
# future, if we add more complex helpers.)
|
||||
#
|
||||
|
||||
libcstdaux_vars = {
|
||||
'cflags': ' '.join(cflags),
|
||||
'version-scripts': use_version_scripts,
|
||||
}
|
||||
|
||||
libcstdaux_dep = declare_dependency(
|
||||
include_directories: include_directories('.'),
|
||||
variables: { 'cflags': ' '.join(cflags) },
|
||||
variables: libcstdaux_vars,
|
||||
version: meson.project_version(),
|
||||
)
|
||||
|
||||
|
@ -17,6 +22,7 @@ if not meson.is_subproject()
|
|||
description: project_description,
|
||||
filebase: 'libcstdaux-'+major,
|
||||
name: 'libcstdaux',
|
||||
unescaped_variables: libcstdaux_vars,
|
||||
version: meson.project_version(),
|
||||
)
|
||||
endif
|
||||
|
|
|
@ -189,6 +189,9 @@ static void test_api_macros(void) {
|
|||
static void test_api_functions(void) {
|
||||
void *fns[] = {
|
||||
(void *)c_errno,
|
||||
(void *)c_memset,
|
||||
(void *)c_memzero,
|
||||
(void *)c_memcpy,
|
||||
(void *)c_free,
|
||||
(void *)c_close,
|
||||
(void *)c_fclose,
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
#undef NDEBUG
|
||||
#include <stdlib.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include "c-stdaux.h"
|
||||
|
||||
/*
|
||||
|
@ -138,6 +137,8 @@ static void test_misc(int non_constant_expr) {
|
|||
c_assert(&sub == c_container_of(&sub.a, struct foobar, a));
|
||||
c_assert(&sub == c_container_of(&sub.b, struct foobar, b));
|
||||
c_assert(&sub == c_container_of((const char *)&sub.b, struct foobar, b));
|
||||
|
||||
c_assert(!c_container_of(NULL, struct foobar, b));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -304,6 +305,58 @@ static void test_misc(int non_constant_expr) {
|
|||
errno = 0;
|
||||
c_assert(c_errno() != errno);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test c_memset(). Simply verify its most basic behavior, as well as
|
||||
* calling it on empty regions.
|
||||
*/
|
||||
{
|
||||
uint64_t v = (uint64_t)-1;
|
||||
size_t n;
|
||||
void *p;
|
||||
|
||||
/* try filling with 0 and 0xff */
|
||||
c_assert(v == (uint64_t)-1);
|
||||
c_memset(&v, 0, sizeof(v));
|
||||
c_assert(v == (uint64_t)0);
|
||||
c_memset(&v, 0xff, sizeof(v));
|
||||
c_assert(v == (uint64_t)-1);
|
||||
|
||||
/*
|
||||
* Try tricking the optimizer into thinking @p cannot be NULL,
|
||||
* as normal `memset(3)` would allow.
|
||||
*/
|
||||
p = NULL;
|
||||
n = 0;
|
||||
c_memset(p, 0, n);
|
||||
if (p)
|
||||
abort();
|
||||
c_assert(p == NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test c_memzero(). Simply verify it can clear a trivial area to 0.
|
||||
*/
|
||||
{
|
||||
uint64_t v = (uint64_t)-1;
|
||||
|
||||
c_assert(v == (uint64_t)-1);
|
||||
c_memzero(&v, sizeof(v));
|
||||
c_assert(v == (uint64_t)0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test c_memcpy() with a simple 8-byte copy.
|
||||
*/
|
||||
{
|
||||
uint64_t v1 = (uint64_t)-1, v2 = (uint64_t)0;
|
||||
|
||||
c_assert(v1 == (uint64_t)-1);
|
||||
c_memcpy(&v1, &v2, sizeof(v1));
|
||||
c_assert(v1 == (uint64_t)0);
|
||||
|
||||
c_memcpy(NULL, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -345,13 +398,16 @@ static void test_destructors(void) {
|
|||
* helpers actually close the fd, and cope fine with negative numbers.
|
||||
*/
|
||||
{
|
||||
int fd;
|
||||
int r, fd1, fd2, tmp[2];
|
||||
|
||||
fd = eventfd(0, EFD_CLOEXEC);
|
||||
c_assert(fd >= 0);
|
||||
r = pipe(tmp);
|
||||
c_assert(r >= 0);
|
||||
fd1 = tmp[0];
|
||||
fd2 = tmp[1];
|
||||
|
||||
/* verify c_close() returns -1 */
|
||||
c_assert(c_close(fd) == -1);
|
||||
c_assert(c_close(fd1) == -1);
|
||||
c_assert(c_close(fd2) == -1);
|
||||
|
||||
/* verify c_close() deals fine with negative fds */
|
||||
c_assert(c_close(-1) == -1);
|
||||
|
@ -370,11 +426,15 @@ static void test_destructors(void) {
|
|||
* path works as well.
|
||||
*/
|
||||
for (i = 0; i < 2; ++i) {
|
||||
_c_cleanup_(c_closep) _c_unused_ int t = -1;
|
||||
_c_cleanup_(c_closep) _c_unused_ int t1 = -1, t2 = -1;
|
||||
|
||||
t = eventfd(0, EFD_CLOEXEC);
|
||||
c_assert(t >= 0);
|
||||
c_assert(t == fd);
|
||||
r = pipe(tmp);
|
||||
c_assert(r >= 0);
|
||||
t1 = tmp[0];
|
||||
t2 = tmp[1];
|
||||
|
||||
c_assert(t1 == fd1);
|
||||
c_assert(t2 == fd2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -383,11 +443,13 @@ static void test_destructors(void) {
|
|||
* tests for c_close() (i.e., sparse FD allocation).
|
||||
*/
|
||||
{
|
||||
int r, fd, tmp[2];
|
||||
FILE *f;
|
||||
int fd;
|
||||
|
||||
fd = eventfd(0, EFD_CLOEXEC);
|
||||
c_assert(fd >= 0);
|
||||
r = pipe(tmp);
|
||||
c_assert(r >= 0);
|
||||
fd = tmp[0];
|
||||
c_close(tmp[1]);
|
||||
|
||||
f = fdopen(fd, "r");
|
||||
c_assert(f);
|
||||
|
@ -415,10 +477,12 @@ static void test_destructors(void) {
|
|||
_c_cleanup_(c_fclosep) _c_unused_ FILE *t = NULL;
|
||||
int tfd;
|
||||
|
||||
tfd = eventfd(0, EFD_CLOEXEC);
|
||||
c_assert(tfd >= 0);
|
||||
c_assert(tfd == fd); /* the same as before */
|
||||
r = pipe(tmp);
|
||||
c_assert(r >= 0);
|
||||
tfd = tmp[0];
|
||||
c_close(tmp[1]);
|
||||
|
||||
c_assert(tfd == fd); /* the same as before */
|
||||
t = fdopen(tfd, "r");
|
||||
c_assert(t);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue