From 4bda70d4658bb706a5f88a4e2c7094e0fabce233 Mon Sep 17 00:00:00 2001 From: Dennis Park Date: Mon, 3 Aug 2026 13:14:18 +0900 Subject: [PATCH] docs: review the header's doc comments and publish an API reference The doc comments in libcmutils.h were nearly complete but had three kinds of problem, and there was nowhere for the result to be read. Fixed 21 gaps. The whole CMUTIL_HttpClient interface was undocumented - the typedef, all seven methods and the constructor - which is the type the REST client was just built on. Socket::SetSilent and ServerSocket::SetSilent had no comment and the matching `silent` argument of both listener constructors was undocumented; Thread::GetId, Thread::GetName and XmlNode::GetName were missing a @param; CMUTIL_GetMem and CMUTIL_RWLockCreate were missing a @return; the private and public key typedefs and the four platform shims had nothing at all. Fixed 58 markup errors. "@typedef Name Description" appeared 57 times, but Doxygen's @typedef takes a declaration, not a name and a description: each one created a phantom symbol and left the real type undocumented, which is why nine enums - CMMemOper, CMLogLevel, CMSocketResult among them - had no documentation at all. They are plain @brief now, since a comment sitting on the entity already names it. Three @struct commands had the same problem, and one tag was never closed. Grouped the API. 6,300 lines of header rendered as one flat list; it is now eighteen subjects, keeping the header's declaration order so a type is followed by its methods and then its constructor. Added @file and a @mainpage covering the two things to know first - that an object is a struct of function pointers reached through CMCall, and the CMUTIL_Init/CMUTIL_Clear lifecycle - plus a group for the CMCall macros, which the main page points at and which belonged to no group. doc/ holds the Doxyfile, a README describing the topics and the pitfall above, and a CMake "docs" target that appears only when doxygen is installed and is never part of "all". EXTRACT_ALL stays off with every documentation warning on, so a gap is reported in doc/doxygen.log rather than published as a blank page. The log is empty. The Docs workflow publishes both halves of the Pages site on every push that touches them: the README landing page at / and the reference at /api/. Nothing generated is committed. It fails if doxygen writes anything to the log. _config.yml now excludes the source tree, which Jekyll had been mirroring onto the site. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/docs.yml | 86 ++++++ .gitignore | 4 + CMakeLists.txt | 3 + README.md | 18 +- _config.yml | 22 +- doc/CMakeLists.txt | 25 ++ doc/Doxyfile | 100 +++++++ doc/README.md | 82 ++++++ src/libcmutils.h | 569 ++++++++++++++++++++++++++++++++----- 9 files changed, 834 insertions(+), 75 deletions(-) create mode 100644 .github/workflows/docs.yml create mode 100644 doc/CMakeLists.txt create mode 100644 doc/Doxyfile create mode 100644 doc/README.md diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..a5f5d73 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,86 @@ +name: Docs + +# Publishes the GitHub Pages site: the README landing page at / and the +# generated API reference at /api/. Nothing generated is committed - both +# halves are built here on every push to the default branch. +# +# This requires the repository's Pages source to be "GitHub Actions" +# (Settings -> Pages -> Build and deployment -> Source). + +on: + push: + branches: [ main, master ] + # A doc comment change lands in the header, so watch that too. + paths: + - 'src/libcmutils.h' + - 'doc/**' + - 'README.md' + - '_config.yml' + - '.github/workflows/docs.yml' + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +# One deployment at a time, and never cancel one halfway - a cancelled +# deploy leaves the site in whatever state it reached. +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + name: Build the site + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install doxygen + run: | + sudo apt-get update + sudo apt-get install -y doxygen + + # Runs first, because it creates _site from scratch. + - name: Build the landing page + uses: actions/jekyll-build-pages@v1 + with: + source: ./ + destination: ./_site + + - name: Build the API reference + working-directory: doc + run: LIBCMUTILS_VERSION=$(cat ../VERSION) doxygen Doxyfile + + # The Doxyfile turns every documentation warning on and writes them + # here, so an empty log is the contract. Publishing a reference with + # known gaps in it defeats the point of the setting. + - name: Fail on documentation warnings + run: | + if [ -s doc/doxygen.log ]; then + echo "::error::doxygen reported documentation problems:" + cat doc/doxygen.log + exit 1 + fi + echo "doxygen reported no documentation problems" + + - name: Place the reference under /api + run: | + mkdir -p _site/api + cp -r doc/html/. _site/api/ + + - uses: actions/upload-pages-artifact@v3 + with: + path: ./_site + + deploy: + name: Deploy to Pages + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index bbce3c4..8d33de7 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,7 @@ build* # CLion .idea + +# Generated API reference (cmake --build build --target docs) +doc/html/ +doc/doxygen.log diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a4b1e6..df9ed5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -146,3 +146,6 @@ IF ( BUILD_SAMPLES ) MESSAGE ( STATUS "Samples enabled building samples..." ) ADD_SUBDIRECTORY ( samples ) ENDIF ( BUILD_SAMPLES ) + +# Adds the "docs" target when doxygen is present. It is not part of "all". +ADD_SUBDIRECTORY ( doc ) diff --git a/README.md b/README.md index c1ec852..5a3a610 100644 --- a/README.md +++ b/README.md @@ -1114,6 +1114,17 @@ Like the tests, every sample returns a failure status when `CMUTIL_Clear()` repo [`samples/README.md`](samples/README.md) for the full list, the data files each one reads, and which of them bind ports or reach the network. +## API reference + +The sections above are prose. The generated reference is the same API organized for lookup — grouped +by subject, built from the doc comments in `src/libcmutils.h`: + +```bash +cd doc && doxygen # or: cmake --build build --target docs +``` + +Open `doc/html/index.html`. See [doc/README.md](doc/README.md) for what the topics contain. + ## Project structure ``` @@ -1147,6 +1158,9 @@ samples/ One annotated program per feature area sample_plugin.c Tiny shared library, loaded by sample_15_library conf/ Configurations, documents and keys the samples read cmutil_log.jsonc Annotated reference logging configuration +doc/ API reference generated from the header's doc comments + Doxyfile Doxygen configuration + README.md What the reference contains and how to build it CMakeLists.txt Build definition vcpkg.json Dependency manifest VERSION Version string, read at configure time @@ -1164,7 +1178,9 @@ Issues and pull requests are welcome at 3. Follow the surrounding style: object types are structs of function pointers, constructors are `CMUTIL_XxxCreate[Ex]`, and every allocation goes through the `CMAlloc`/`CMFree` family. 4. Keep the public surface in `src/libcmutils.h`, documented with the same doxygen comment style as - its neighbours. Internal helpers belong in `src/functions.h`. + its neighbours — a `@brief`, a `@param` per argument and a `@return` unless it returns `void`. + Internal helpers belong in `src/functions.h`. `cd doc && doxygen` must leave `doc/doxygen.log` + empty; see [doc/README.md](doc/README.md). Participation is governed by the [Code of Conduct](CODE_OF_CONDUCT.md). diff --git a/_config.yml b/_config.yml index c419263..0d95e41 100644 --- a/_config.yml +++ b/_config.yml @@ -1 +1,21 @@ -theme: jekyll-theme-cayman \ No newline at end of file +theme: jekyll-theme-cayman + +title: libcmutils +description: Multi-platform C99 utility library + +# Jekyll copies everything it is not told to skip, which otherwise mirrors +# the whole source tree onto the site. Only README.md needs rendering; the +# API reference is generated separately and dropped into /api by the Docs +# workflow. +exclude: + - src + - test + - samples + - doc + - build + - CMakeLists.txt + - vcpkg.json + - VERSION + - AUTHORS + - ChangeLog + - NEWS diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt new file mode 100644 index 0000000..e58cecc --- /dev/null +++ b/doc/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# API reference for libcmutils. +# +# Adds a "docs" target when doxygen is available. It is never part of "all": +# the reference is built on request, not on every compile. +# + +FIND_PACKAGE ( Doxygen ) + +IF ( NOT DOXYGEN_FOUND ) + MESSAGE ( STATUS "Doxygen not found, the docs target is unavailable" ) + RETURN () +ENDIF () + +# The Doxyfile reads the version out of the environment so that a bare +# "doxygen" run in this directory works too. +ADD_CUSTOM_TARGET ( docs + COMMAND ${CMAKE_COMMAND} -E env + LIBCMUTILS_VERSION=${LIB_VERSION_STRING} + ${DOXYGEN_EXECUTABLE} Doxyfile + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Generating the API reference into doc/html" + VERBATIM ) + +MESSAGE ( STATUS "Doxygen found, \"docs\" target available" ) diff --git a/doc/Doxyfile b/doc/Doxyfile new file mode 100644 index 0000000..a70d92c --- /dev/null +++ b/doc/Doxyfile @@ -0,0 +1,100 @@ +# Doxygen configuration for the libcmutils API reference. +# +# Run it from this directory: +# +# cd doc && doxygen +# +# or through the build: +# +# cmake -S . -B build -DBUILD_DOCS=ON && cmake --build build --target docs +# +# Only the settings that matter are listed; everything else keeps its +# default. See doc/README.md for what the output contains. + +#--------------------------------------------------------------------------- +# Project +#--------------------------------------------------------------------------- +PROJECT_NAME = libcmutils +PROJECT_BRIEF = "Multi-platform C99 utility library" +# The build passes the contents of VERSION in through this variable; a bare +# "doxygen" run simply leaves the version blank. +PROJECT_NUMBER = $(LIBCMUTILS_VERSION) + +OUTPUT_DIRECTORY = +HTML_OUTPUT = html +GENERATE_LATEX = NO +GENERATE_HTML = YES + +#--------------------------------------------------------------------------- +# Input +#--------------------------------------------------------------------------- +# libcmutils.h is the whole public API - the .c files are implementation and +# are deliberately left out. +INPUT = ../src/libcmutils.h +FILE_PATTERNS = *.h +RECURSIVE = NO +EXAMPLE_PATH = ../samples +EXAMPLE_PATTERNS = *.c +EXAMPLE_RECURSIVE = NO + +#--------------------------------------------------------------------------- +# What to extract +#--------------------------------------------------------------------------- +# This is a C API: no classes, no namespaces, and "typedef struct X X;" +# should read as X rather than as an anonymous struct. +OPTIMIZE_OUTPUT_FOR_C = YES +TYPEDEF_HIDES_STRUCT = YES + +# Undocumented entities are left out rather than listed empty, and the +# warnings below say which they were - so the reference never silently +# grows a blank page. +EXTRACT_ALL = NO +EXTRACT_STATIC = NO +HIDE_UNDOC_MEMBERS = YES +HIDE_UNDOC_CLASSES = YES + +# Declaration order carries meaning in this header: related methods sit +# together and the constructor follows its type. +SORT_MEMBER_DOCS = NO +SORT_BRIEF_DOCS = NO +SORT_GROUP_NAMES = NO +ALPHABETICAL_INDEX = YES + +#--------------------------------------------------------------------------- +# Preprocessing +#--------------------------------------------------------------------------- +# CMUTIL_API is an export decoration and would otherwise show up in every +# signature. The platform macros are all defined so that the shims each one +# guards are documented too, whichever platform the docs are built on. +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +SKIP_FUNCTION_MACROS = NO +PREDEFINED = CMUTIL_API= \ + CMUTIL_STATIC=static \ + DOXYGEN=1 + +#--------------------------------------------------------------------------- +# Warnings - these are how documentation gaps get noticed +#--------------------------------------------------------------------------- +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_IF_INCOMPLETE_DOC = YES +WARN_NO_PARAMDOC = YES +WARN_AS_ERROR = NO +WARN_LOGFILE = doxygen.log + +#--------------------------------------------------------------------------- +# HTML output +#--------------------------------------------------------------------------- +GENERATE_TREEVIEW = YES +DISABLE_INDEX = NO +FULL_SIDEBAR = NO +HTML_COLORSTYLE = TOGGLE +SEARCHENGINE = YES +HTML_DYNAMIC_SECTIONS = NO + +# graphviz is not required to build these docs. +HAVE_DOT = NO diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 0000000..8deabcf --- /dev/null +++ b/doc/README.md @@ -0,0 +1,82 @@ +# API reference + +The reference is generated from the doc comments in +[`src/libcmutils.h`](../src/libcmutils.h), which is the whole public API — the +`.c` files are implementation and are deliberately left out. + +## Building it + +```bash +cd doc && doxygen +``` + +or through the build, which also fills in the version number: + +```bash +cmake -S . -B build +cmake --build build --target docs +``` + +The `docs` target appears only when doxygen is installed, and it is never part +of `all` — the reference is built on request. Output lands in `doc/html`; open +`doc/html/index.html`. Neither the output nor `doxygen.log` is committed. + +Graphviz is not needed. Doxygen 1.9 or newer is expected; older versions still +work but ignore some of the HTML settings. + +## What it contains + +The front page covers the two things to know before reading anything else: that +an object is a struct of function pointers reached through `CMCall`, and the +`CMUTIL_Init` / `CMUTIL_Clear` lifecycle. + +**Topics** is the way in. The API is grouped by subject rather than listed +alphabetically, and within a group the declaration order of the header is kept, +so a type is followed by its methods and then its constructor: + +| Topic | Covers | +| --- | --- | +| Fixed width integers, CMBool and the platform shims | `CMBool`, the integer limits, the MSVC and macOS shims | +| The CMCall convention | `CMCall`, `CMUTIL_CALL_NESTED`, `CMUTIL_CALL_SINGLE_EVAL` | +| Initialization and memory operations | `CMUTIL_Init`, `CMUTIL_Clear`, `CMUTIL_Mem`, the allocator macros | +| Threads, locks and synchronization primitives | `CMUTIL_Thread`, `CMUTIL_ThreadPool`, `CMUTIL_Mutex`, `CMUTIL_Cond`, `CMUTIL_Semaphore`, `CMUTIL_RWLock` | +| Arrays, maps, lists and their iterator | `CMUTIL_Array`, `CMUTIL_Map`, `CMUTIL_List`, `CMUTIL_Iterator` | +| Strings, string arrays, byte buffers and charset conversion | `CMUTIL_String`, `CMUTIL_StringArray`, `CMUTIL_ByteBuffer`, `CMUTIL_CSConv`, the `CMUTIL_Str*` helpers | +| XML parsing and the document model | `CMUTIL_XmlNode` and the parsers | +| JSON parsing and the document model | `CMUTIL_Json`, `CMUTIL_JsonObject`, `CMUTIL_JsonArray`, `CMUTIL_JsonValue` | +| Scheduled and repeating tasks | `CMUTIL_Timer`, `CMUTIL_TimerTask` | +| Generic resource pool | `CMUTIL_Pool` | +| Dynamic library loading | `CMUTIL_Library` | +| Files, directories and file streams | `CMUTIL_File`, `CMUTIL_FileList`, `CMUTIL_FileStream` | +| Configuration files | `CMUTIL_Config` | +| Log system, loggers and appenders | `CMUTIL_LogSystem`, the appenders, the `CMLog*` macros | +| Call stack capture | `CMUTIL_StackWalker` | +| Sockets, datagrams and the HTTP and REST clients | `CMUTIL_Socket`, `CMUTIL_ServerSocket`, `CMUTIL_DGramSocket`, `CMUTIL_HttpClient`, `CMUTIL_RestClient` | +| Child process creation and control | `CMUTIL_Process` | +| Block ciphers, RSA, Base64 and secure random | `CMUTIL_BlockCrypto`, `CMUTIL_RSACrypto`, the key types | + +For prose rather than a reference, read the [project README](../README.md); for +working code, [`samples/`](../samples) has one annotated program per subject. + +## Keeping it honest + +The configuration leaves `EXTRACT_ALL` off and turns every documentation +warning on, so an undocumented entity is reported rather than published as a +blank page: + +``` +WARN_IF_UNDOCUMENTED = YES +WARN_IF_INCOMPLETE_DOC = YES +WARN_NO_PARAMDOC = YES +``` + +Warnings go to `doc/doxygen.log`. **It should be empty.** If a run leaves +anything in it, that is a doc comment to fix — a missing `@param`, a `@param` +naming an argument that no longer exists, a missing `@return` — not a message +to ignore. + +One thing worth knowing when editing the header: `@typedef` and `@struct` are +Doxygen commands that take a *declaration*, not a name and a description. A +comment sitting directly above the entity already documents it, so a plain +`@brief` is what belongs there; writing `@typedef CMUTIL_Foo Some description` +creates a phantom symbol and leaves the real one undocumented. diff --git a/src/libcmutils.h b/src/libcmutils.h index 8d91119..2575613 100644 --- a/src/libcmutils.h +++ b/src/libcmutils.h @@ -22,17 +22,60 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/* - * File - * libcmutils.h +/** + * @file libcmutils.h + * @brief The entire public API of libcmutils. + * + * This is the only header to include. Everything the library offers - + * collections, strings, concurrency, files, sockets, JSON, XML, logging, + * crypto and child processes - is declared here and grouped by subject in + * the module list. + * + * @author libcmutils: Dennis Soungjin Park + * @author fpattern: David R. Tribble + */ + +/** + * @mainpage libcmutils + * + * A C99 utility library for Linux, macOS and Windows, written so that one + * source tree builds unchanged on all three. * - * Description - * libcmutils is a bunch of commonly used utility functions for - * multi-platform. + * @section mp_object Objects are structs of function pointers * - * Authors - * libcmutils: Dennis Soungjin Park , - * fpattern: David R. Tribble + * An object is a struct whose members are its methods, and every method + * takes the object as its first argument. The @c CMCall macro fills that + * argument in: + * + * @code + * CMUTIL_String *str = CMUTIL_StringCreate(); + * CMCall(str, AddString, "hello"); // str->AddString(str, "hello") + * printf("%s\n", CMCall(str, GetCString)); + * CMCall(str, Destroy); + * @endcode + * + * Two rules come with it. Whether a @c CMCall may appear inside another + * one's argument list depends on the compiler - see #CMUTIL_CALL_NESTED - + * and whether the receiver is evaluated once or twice likewise - see + * #CMUTIL_CALL_SINGLE_EVAL. Both detect what the compiler supports and can + * be overridden before including this header. + * + * @section mp_lifecycle Lifecycle + * + * @code + * CMUTIL_Init(CMMemRecycle); // first library call in the process + * ... + * CMUTIL_Clear(); // returns CMFalse if anything leaked + * @endcode + * + * @c CMUTIL_Clear() reports whether every object allocated through the + * library was released, which makes it a leak check as well as a teardown. + * + * @section mp_where Where to look + * + * The Modules list groups the API by subject. The project README + * covers the same ground in prose, and @c samples/ holds one annotated + * program per subject. */ #ifndef LIBCMUTILS_H__ @@ -123,7 +166,7 @@ extern "C" { /** - * @defgroup CMUTIL Types. + * @defgroup CMUTIL Fixed width integers, CMBool and the platform shims. * @{ * * CMUTIL library uses platform-independent data types for multi-platform @@ -158,6 +201,16 @@ typedef SSIZE_T ssize_t; #endif #if defined(_MSC_VER) +/** + * @brief gettimeofday(2) for MSVC, which does not ship one. + * + * Reached through the gettimeofday macro below; there is no reason + * to call it by this name. + * + * @param tv Receives the current time. + * @param tz Ignored, present only to match the POSIX signature. + * @return 0 on success. + */ CMUTIL_API int __gettimeofday(struct timeval *tv, void *tz); #define gettimeofday(tv, tz) __gettimeofday(tv, tz) @@ -186,8 +239,30 @@ typedef enum CMBool { # define gethostbyname_r CMUTIL_NetworkGetHostByNameR # if !defined(CMUTIL_EXPORT) # define gethostbyname CMUTIL_NetworkGetHostByName +/** + * @brief gethostbyname(3) implemented on top of the reentrant form below. + * + * Reached through the gethostbyname macro above. + * + * @param name Host name to resolve. + * @return The resolved host, or NULL. The storage is reused by the next call. + */ CMUTIL_API struct hostent *CMUTIL_NetworkGetHostByName(const char *name); # endif +/** + * @brief gethostbyname_r(3) for macOS, which does not ship one. + * + * Reached through the gethostbyname_r macro above, so that code + * written against the reentrant resolver builds unchanged on every platform. + * + * @param name Host name to resolve. + * @param ret Receives the resolved host. + * @param buf Scratch buffer the result points into. + * @param buflen Size of @a buf. + * @param result Receives @a ret on success, NULL on failure. + * @param h_errnop Receives the resolver error code on failure. + * @return 0 on success, otherwise an error code. + */ CMUTIL_API int CMUTIL_NetworkGetHostByNameR( const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop); @@ -197,7 +272,25 @@ CMUTIL_API int CMUTIL_NetworkGetHostByNameR( * Unused variable wrapper for avoiding compile warning. */ #define CMUTIL_UNUSED(a,...) CMUTIL_UnusedP((void*)(int64_t)(a), ## __VA_ARGS__) -CMUTIL_API void CMUTIL_UnusedP(void*,...); +/** + * @brief Consumes its arguments so the compiler stops calling them unused. + * + * Use the CMUTIL_UNUSED macro above rather than this function. + * + * @param a First value to consume. + * @param ... Any further values to consume. + */ +CMUTIL_API void CMUTIL_UnusedP(void *a, ...); + +/** + * @defgroup CMUTILS_Calling The CMCall convention. + * @{ + * + * An object in this library is a struct of function pointers, and every + * method takes the object itself as its first argument. CMCall writes that + * argument for you. What the compiler supports decides two details of how + * it expands, and both can be overridden before including this header. + */ /** * @brief Whether CMCall may be nested inside another CMCall's arguments. @@ -374,6 +467,10 @@ CMUTIL_API void CMUTIL_UnusedP(void*,...); // for backward compatibility #define CMUTIL_CALL CMUTIL_CALL__ +/** + * @} + */ + /** * @brief Get a version string of this library. * @return Version string of this library. @@ -381,17 +478,17 @@ CMUTIL_API void CMUTIL_UnusedP(void*,...); CMUTIL_API const char *CMUTIL_GetLibVersion(void); /** - * @typedef CMCompareCB Object comparison callback type. + * @brief Object comparison callback type. */ typedef int (*CMCompareCB)(const void*, const void*); /** - * @typedef CMFreeCB Callback type for memory deallocation. + * @brief Callback type for memory deallocation. */ typedef void (*CMFreeCB)(void*); /** - * @typedef CMProcCB Callback type for execution of some procedure. + * @brief Callback type for execution of some procedure. */ typedef void (*CMProcCB)(void*); @@ -418,7 +515,7 @@ typedef void (*CMProcCB)(void*); */ /** - * @typedef CMMemOper Memory operation types. + * @brief Memory operation types. * Refer CMUTIL_Init function for details. */ typedef enum CMMemOper { @@ -475,7 +572,7 @@ typedef struct CMUTIL_Mem { /** * @brief Allocate memory. * - * Allocates size bytes and returns a pointer to the allocated + * Allocates size bytes and returns a pointer to the allocated * memory. The memory is not initialized. If size is 0, then this function * returns either NULL or a unique pointer value that can later be * successfully passed to Free. @@ -542,6 +639,9 @@ typedef struct CMUTIL_Mem { * @brief Global memory operator structure. * This object will be initialized with appropriate memory operators in * CMUTIL_Init. + * + * @return The allocator every object in the library allocates through. + * It belongs to the library and must not be destroyed. */ CMUTIL_API CMUTIL_Mem *CMUTIL_GetMem(void); @@ -578,7 +678,12 @@ CMUTIL_API CMUTIL_Mem *CMUTIL_GetMem(void); */ /** - * @typedef CMUTIL_Cond Platform independent condition definition for + * @defgroup CMUTILS_Concurrency Threads, locks and synchronization primitives. + * @{ + */ + +/** + * @brief Platform independent condition definition for * concurrency control. * * Condition (or Event) @@ -677,7 +782,7 @@ struct CMUTIL_Cond { CMUTIL_API CMUTIL_Cond *CMUTIL_CondCreate(CMBool manual_reset); /** - * @typedef CMUTIL_Mutex Platform independent mutex implementation. + * @brief Platform independent mutex implementation. */ typedef struct CMUTIL_Mutex CMUTIL_Mutex; struct CMUTIL_Mutex { @@ -756,7 +861,7 @@ CMUTIL_API CMUTIL_Mutex *CMUTIL_MutexCreate(void); } while(0) /** - * @typedef CMUTIL_Thread Platform independent thread object. + * @brief Platform independent thread object. */ typedef struct CMUTIL_Thread CMUTIL_Thread; struct CMUTIL_Thread { @@ -793,15 +898,17 @@ struct CMUTIL_Thread { CMBool (*IsRunning)(const CMUTIL_Thread *thread); /** - * @brief Get the ID fo this thread. Returned ID is not system thread ID. - * just an internal thread index. + * @brief Get the ID of this thread. The returned ID is not the system + * thread ID, just an internal thread index. + * @param thread This thread object. * @return ID of this thread. */ uint32_t (*GetId)(const CMUTIL_Thread *thread); /** * @brief Get the name of this thread. - * @return Name of this thread. + * @param thread This thread object. + * @return Name of this thread. It belongs to the thread object. */ const char *(*GetName)(const CMUTIL_Thread *thread); }; @@ -843,7 +950,7 @@ CMUTIL_API CMUTIL_Thread *CMUTIL_ThreadSelf(void); CMUTIL_API uint64_t CMUTIL_ThreadSystemSelfId(void); /** - * @typedef CMUTIL_ThreadPool A threadpool object. + * @brief A threadpool object. */ typedef struct CMUTIL_ThreadPool CMUTIL_ThreadPool; struct CMUTIL_ThreadPool { @@ -892,7 +999,7 @@ CMUTIL_API CMUTIL_ThreadPool *CMUTIL_ThreadPoolCreate( int pool_size, const char *name); /** - * @typedef CMUTIL_Semaphore Platform independent semaphore object. + * @brief Platform independent semaphore object. */ typedef struct CMUTIL_Semaphore CMUTIL_Semaphore; struct CMUTIL_Semaphore { @@ -941,7 +1048,7 @@ CMUTIL_API CMUTIL_Semaphore *CMUTIL_SemaphoreCreate(int initcnt); /** - * @typedef CMUTIL_RWLock Platform independent read/write lock object. + * @brief Platform independent read/write lock object. */ typedef struct CMUTIL_RWLock CMUTIL_RWLock; struct CMUTIL_RWLock { @@ -999,11 +1106,22 @@ struct CMUTIL_RWLock { /** * @brief Create a read-write lock object. + * + * @return A new read-write lock, which must be destroyed after use. */ CMUTIL_API CMUTIL_RWLock *CMUTIL_RWLockCreate(void); /** - * @typedef CMUTIL_Iterator Iterator of collection members. + * @} + */ + +/** + * @defgroup CMUTILS_Collections Arrays, maps, lists and their iterator. + * @{ + */ + +/** + * @brief Iterator of collection members. */ typedef struct CMUTIL_Iterator CMUTIL_Iterator; struct CMUTIL_Iterator { @@ -1037,7 +1155,7 @@ struct CMUTIL_Iterator { /** - * @typedef CMUTIL_Array Dynamic array of any type element. + * @brief Dynamic array of any type element. */ typedef struct CMUTIL_Array CMUTIL_Array; struct CMUTIL_Array { @@ -1281,7 +1399,16 @@ CMUTIL_API CMUTIL_Array *CMUTIL_ArrayCreateEx( CMFreeCB freecb); /** - * @typedef CMUTIL_String Multifunctional string type. + * @} + */ + +/** + * @defgroup CMUTILS_Strings Strings, string arrays, byte buffers and charset conversion. + * @{ + */ + +/** + * @brief Multifunctional string type. */ typedef struct CMUTIL_String CMUTIL_String; struct CMUTIL_String { @@ -1596,7 +1723,7 @@ CMUTIL_API CMUTIL_String *CMUTIL_StringCreateEx( /** - * @typedef CMUTIL_StringArray Dynamic array of string objects. + * @brief Dynamic array of string objects. */ typedef struct CMUTIL_StringArray CMUTIL_StringArray; struct CMUTIL_StringArray { @@ -1919,7 +2046,7 @@ CMUTIL_API int CMUTIL_StringHexToBytes(uint8_t *dest, const char *src, int len); /** - * @typedef CMUTIL_ByteBuffer Manipulation of bytes. + * @brief Manipulation of bytes. */ typedef struct CMUTIL_ByteBuffer CMUTIL_ByteBuffer; struct CMUTIL_ByteBuffer { @@ -2127,9 +2254,18 @@ struct CMUTIL_ByteBuffer { CMUTIL_API CMUTIL_ByteBuffer *CMUTIL_ByteBufferCreateEx( size_t initcapacity); +/** + * @} + */ + + +/** + * @addtogroup CMUTILS_Collections + * @{ + */ /** - * @typedef CMUTIL_MapPair Key-value pair for CMUTIL_Map. + * @brief Key-value pair for CMUTIL_Map. */ typedef struct CMUTIL_MapPair CMUTIL_MapPair; struct CMUTIL_MapPair { @@ -2164,7 +2300,7 @@ struct CMUTIL_MapPair { /** - * @typedef CMUTIL_Map Hashmap type with item order preserved. + * @brief Hashmap type with item order preserved. */ typedef struct CMUTIL_Map CMUTIL_Map; struct CMUTIL_Map { @@ -2403,7 +2539,7 @@ CMUTIL_API CMUTIL_Map *CMUTIL_MapCreateEx( /** - * @typedef CMUTIL_List A doubly linked list type. + * @brief A doubly linked list type. */ typedef struct CMUTIL_List CMUTIL_List; struct CMUTIL_List { @@ -2551,11 +2687,20 @@ struct CMUTIL_List { */ CMUTIL_API CMUTIL_List *CMUTIL_ListCreateEx(CMFreeCB freecb); +/** + * @} + */ + /** - * @typedef CMXmlNodeKind The kind of XML node. + * @defgroup CMUTILS_Xml XML parsing and the document model. + * @{ + */ + +/** + * @brief The kind of XML node. */ typedef enum CMXmlNodeKind { /** Unknown node type. */ @@ -2568,7 +2713,7 @@ typedef enum CMXmlNodeKind { /** - * @typedef CMUTIL_XmlNode XML node manipulation. + * @brief XML node manipulation. */ typedef struct CMUTIL_XmlNode CMUTIL_XmlNode; struct CMUTIL_XmlNode { @@ -2649,7 +2794,11 @@ struct CMUTIL_XmlNode { /** * @brief Get the name of this node. * - * @return The name of the node as a C-style string. + * For a text node the "name" is the text itself. + * + * @param node This XML node object. + * @return The name of the node as a C-style string. It belongs to the + * node. */ const char *(*GetName)(const CMUTIL_XmlNode *node); @@ -2774,10 +2923,19 @@ CMUTIL_API CMUTIL_XmlNode *CMUTIL_XmlNodeCreate( CMUTIL_API CMUTIL_XmlNode *CMUTIL_XmlNodeCreateWithLen( CMXmlNodeKind type, const char *tagname, size_t len); +/** + * @} + */ + /** - * @typedef CMUTIL_CSConv Character set conversion object. + * @addtogroup CMUTILS_Strings + * @{ + */ + +/** + * @brief Character set conversion object. */ typedef struct CMUTIL_CSConv CMUTIL_CSConv; struct CMUTIL_CSConv { @@ -2830,9 +2988,18 @@ struct CMUTIL_CSConv { CMUTIL_API CMUTIL_CSConv *CMUTIL_CSConvCreate( const char *fromcs, const char *tocs); +/** + * @} + */ + /** - * @typedef CMUTIL_TimerTask Timer task handle. + * @defgroup CMUTILS_Timer Scheduled and repeating tasks. + * @{ + */ + +/** + * @brief Timer task handle. */ typedef struct CMUTIL_TimerTask CMUTIL_TimerTask; struct CMUTIL_TimerTask { @@ -2852,7 +3019,7 @@ struct CMUTIL_TimerTask { }; /** - * @typedef CMUTIL_Timer Timer object for scheduling tasks. + * @brief Timer object for scheduling tasks. */ typedef struct CMUTIL_Timer CMUTIL_Timer; struct CMUTIL_Timer { @@ -2968,9 +3135,18 @@ struct CMUTIL_Timer { */ CMUTIL_API CMUTIL_Timer *CMUTIL_TimerCreateEx(long precision, int threads); +/** + * @} + */ + + +/** + * @defgroup CMUTILS_Pool Generic resource pool. + * @{ + */ /** - * @typedef CMUTIL_Pool Resource pool object. + * @brief Resource pool object. */ typedef struct CMUTIL_Pool CMUTIL_Pool; struct CMUTIL_Pool { @@ -3025,17 +3201,17 @@ struct CMUTIL_Pool { }; /** - * @typedef CMPoolItemCreateCB Callback type for creating a pool item. + * @brief Callback type for creating a pool item. */ typedef void* (*CMPoolItemCreateCB)(void *udata); /** - * @typedef CMPoolItemFreeCB Callback type for freeing a pool item. + * @brief Callback type for freeing a pool item. */ typedef void (*CMPoolItemFreeCB)(void *resource, void *udata); /** - * @typedef CMPoolItemTestCB Callback type for testing a pool item. + * @brief Callback type for testing a pool item. */ typedef CMBool (*CMPoolItemTestCB)(void *resource, void *udata); @@ -3073,10 +3249,19 @@ CMUTIL_API CMUTIL_Pool *CMUTIL_PoolCreate( void *udata, CMUTIL_Timer *timer); +/** + * @} + */ + /** - * @typedef CMUTIL_Library Dynamic library loader. + * @defgroup CMUTILS_Library Dynamic library loading. + * @{ + */ + +/** + * @brief Dynamic library loader. */ typedef struct CMUTIL_Library CMUTIL_Library; struct CMUTIL_Library { @@ -3125,14 +3310,23 @@ struct CMUTIL_Library { */ CMUTIL_API CMUTIL_Library *CMUTIL_LibraryCreate(const char *path); +/** + * @} + */ + /** - * @typedef CMUTIL_FileList A list of files in a directory. + * @defgroup CMUTILS_File Files, directories and file streams. + * @{ + */ + +/** + * @brief A list of files in a directory. */ typedef struct CMUTIL_FileList CMUTIL_FileList; /** - * @typedef CMUTIL_File A file or directory object. + * @brief A file or directory object. */ typedef struct CMUTIL_File CMUTIL_File; struct CMUTIL_FileList { @@ -3167,7 +3361,7 @@ struct CMUTIL_FileList { }; /** - * @typedef CMUTIL_FileOpenMode File open mode enumeration. + * @brief File open mode enumeration. */ typedef enum CMFileOpenMode { /** Open file for reading. */ @@ -3179,7 +3373,7 @@ typedef enum CMFileOpenMode { } CMFileOpenMode; /** - * @typedef CMUTIL_FileStream File stream object for reading and writing files. + * @brief File stream object for reading and writing files. */ typedef struct CMUTIL_FileStream CMUTIL_FileStream; struct CMUTIL_FileStream { @@ -3485,7 +3679,16 @@ CMUTIL_API CMUTIL_File *CMUTIL_FileCreate(const char *path); CMUTIL_API CMBool CMUTIL_PathCreate(const char *path, uint32_t mode); /** - * @typedef CMUTIL_Config Configuration management object. + * @} + */ + +/** + * @defgroup CMUTILS_Config Configuration files. + * @{ + */ + +/** + * @brief Configuration management object. */ typedef struct CMUTIL_Config CMUTIL_Config; struct CMUTIL_Config { @@ -3595,6 +3798,10 @@ CMUTIL_API CMUTIL_Config *CMUTIL_ConfigCreate(void); */ CMUTIL_API CMUTIL_Config *CMUTIL_ConfigLoad(const char *fconf); +/** + * @} + */ + /** * Default log configuration file name. @@ -3602,7 +3809,12 @@ CMUTIL_API CMUTIL_Config *CMUTIL_ConfigLoad(const char *fconf); #define CMUTIL_LOG_CONFIG_DEFAULT "cmutil_log.jsonc" /** - * @typedef CMLogLevel Log severity levels. + * @defgroup CMUTILS_Logging Log system, loggers and appenders. + * @{ + */ + +/** + * @brief Log severity levels. */ typedef enum CMLogLevel { /** Trace level for detailed debugging information. */ @@ -3620,7 +3832,7 @@ typedef enum CMLogLevel { } CMLogLevel; /** - * @typedef CMLogTerm Log rolling terms. + * @brief Log rolling terms. */ typedef enum CMLogTerm { /** Yearly log rolling. */ @@ -3636,12 +3848,12 @@ typedef enum CMLogTerm { } CMLogTerm; /** - * @typedef CMUTIL_LogAppender Log appender object. + * @brief Log appender object. */ typedef struct CMUTIL_LogAppender CMUTIL_LogAppender; /** - * @typedef CMUTIL_ConfLogger Logger configuration object. + * @brief Logger configuration object. */ typedef struct CMUTIL_ConfLogger CMUTIL_ConfLogger; struct CMUTIL_ConfLogger { @@ -3663,7 +3875,7 @@ struct CMUTIL_ConfLogger { }; /** - * @typedef CMUTIL_Logger Logger object. + * @brief Logger object. */ typedef struct CMUTIL_Logger CMUTIL_Logger; struct CMUTIL_Logger { @@ -4097,7 +4309,7 @@ CMUTIL_API CMBool CMUTIL_LogIsEnabled( #define CMLogS(l,f,...) CMUTIL_Log2__(l,True ,f,##__VA_ARGS__) /** - * @typedef CMUTIL_LogSystem Log system object. + * @brief Log system object. */ typedef struct CMUTIL_LogSystem CMUTIL_LogSystem; struct CMUTIL_LogSystem { @@ -4217,7 +4429,16 @@ CMUTIL_API CMUTIL_LogSystem *CMUTIL_LogSystemGet(void); CMUTIL_API void CMUTIL_LogSystemSet(CMUTIL_LogSystem *lsys); /** - * @typedef CMUTIL_StackWalker Stack walker object. + * @} + */ + +/** + * @defgroup CMUTILS_StackWalker Call stack capture. + * @{ + */ + +/** + * @brief Stack walker object. */ typedef struct CMUTIL_StackWalker CMUTIL_StackWalker; struct CMUTIL_StackWalker { @@ -4268,9 +4489,18 @@ struct CMUTIL_StackWalker { */ CMUTIL_API CMUTIL_StackWalker *CMUTIL_StackWalkerCreate(void); +/** + * @} + */ + + +/** + * @defgroup CMUTILS_Network Sockets, datagrams and the HTTP and REST clients. + * @{ + */ /** - * @typedef CMSocketResult Socket operation result codes. + * @brief Socket operation result codes. */ typedef enum CMSocketResult { /** Operation succeeded. */ @@ -4296,7 +4526,7 @@ typedef enum CMSocketResult { } CMSocketResult; /** - * @typedef CMUTIL_SocketAddr Socket address object. + * @brief Socket address object. */ typedef struct sockaddr_storage CMUTIL_SocketAddr; @@ -4326,7 +4556,7 @@ CMUTIL_API CMSocketResult CMUTIL_SocketAddrSet( CMUTIL_SocketAddr *saddr, const char *host, int port); /** - * @typedef CMUTIL_Socket Socket object. + * @brief Socket object. */ typedef struct CMUTIL_Socket CMUTIL_Socket; struct CMUTIL_Socket { @@ -4500,6 +4730,16 @@ struct CMUTIL_Socket { CMSocketResult (*WriteByte)( const CMUTIL_Socket *socket, uint8_t c, long timeout); + /** + * @brief Suppress this library's own error logging on this socket. + * + * A disconnect a server expects - a client that simply went away - is + * not worth an error line. Turning this on demotes those messages to + * trace level; the return codes are unaffected. + * + * @param socket The socket object. + * @param silent CMTrue to stop logging errors for this socket. + */ void (*SetSilent)( CMUTIL_Socket *socket, CMBool silent); }; @@ -4577,7 +4817,7 @@ CMUTIL_API CMUTIL_Socket *CMUTIL_SSLSocketConnectWithAddr( const CMUTIL_SocketAddr *saddr, long timeout); /** - * @typedef CMUTIL_ServerSocket Server socket object. + * @brief Server socket object. */ typedef struct CMUTIL_ServerSocket CMUTIL_ServerSocket; struct CMUTIL_ServerSocket { @@ -4607,6 +4847,15 @@ struct CMUTIL_ServerSocket { */ void (*Close)(CMUTIL_ServerSocket *server); + /** + * @brief Suppress this library's own error logging on this listener. + * + * Behaves like CMUTIL_Socket::SetSilent, and does not affect the + * sockets handed out by Accept. + * + * @param socket The server socket object. + * @param silent CMTrue to stop logging errors for this listener. + */ void (*SetSilent)( CMUTIL_ServerSocket *socket, CMBool silent); @@ -4618,6 +4867,8 @@ struct CMUTIL_ServerSocket { * @param host Host address to listen on.(0.0.0.0 for any address) * @param port Port number to listen on. * @param qcnt The maximum length of the queue of pending connections. + * @param silent CMTrue to suppress this library's own error logging for + * this listener, as CMUTIL_ServerSocket::SetSilent does. * @return A server socket if succeeded it must be closed after use. * NULL if failed. */ @@ -4632,6 +4883,8 @@ CMUTIL_API CMUTIL_ServerSocket *CMUTIL_ServerSocketCreate( * * @param ipc_path unix domain socket path(xnix) or port number(windows) to listen on. * @param qcnt The maximum length of the queue of pending connections. + * @param silent CMTrue to suppress this library's own error logging for + * this listener, as CMUTIL_ServerSocket::SetSilent does. * @return A server socket if succeeded it must be closed after use. * NULL if failed. */ @@ -4665,7 +4918,7 @@ CMUTIL_API CMBool CMUTIL_SocketPair( CMUTIL_Socket **s1, CMUTIL_Socket **s2); /** - * @typedef CMUTIL_DGramSocket Datagram socket object. + * @brief Datagram socket object. */ typedef struct CMUTIL_DGramSocket CMUTIL_DGramSocket; struct CMUTIL_DGramSocket { @@ -4818,20 +5071,98 @@ CMUTIL_API CMUTIL_DGramSocket *CMUTIL_DGramSocketCreateBind( CMUTIL_SocketAddr *addr); +/** + * @brief An HTTP/HTTPS client built on the socket layer. + * + * The client is fixed to one origin: it takes a URL prefix at construction + * and every request names a URI relative to it. Request and response bodies + * are CMUTIL_ByteBuffer objects; see CMUTIL_RestClient for the same client + * speaking CMUTIL_Json. + * + * Connections are kept alive and pooled per host and port, so a series of + * requests to one origin reuses one socket. A pooled connection is dropped + * once it has been idle for 30 seconds. + */ typedef struct CMUTIL_HttpClient CMUTIL_HttpClient; struct CMUTIL_HttpClient { + + /** + * @brief Set TLS verification for this client. + * + * A fresh client verifies the host name and presents no client + * certificate. Turning @a verify_host off reaches a server whose + * certificate does not match its name - including a self-signed one. + * + * @param client This HTTP client object. + * @param verify_host CMTrue to check the server's certificate against + * the host name, and to use the CA file set by SetSSLCert as the + * trust anchor rather than the system trust store. + * @param verify_peer CMTrue to present the client certificate set by + * SetSSLCert. + * @return CMTrue on success. + */ CMBool (*SetVerify)( CMUTIL_HttpClient *client, CMBool verify_host, CMBool verify_peer); + + /** + * @brief Set the TLS certificates this client uses. + * + * Which of them take effect depends on SetVerify: the client + * certificate and key are only sent when @a verify_peer is on, and the + * CA file only becomes the trust anchor when @a verify_host is on. + * + * @param client This HTTP client object. + * @param certfile Client certificate in PEM form, or NULL. + * @param keyfile Private key for @a certfile in PEM form, or NULL. + * @param cafile CA certificate to trust in PEM form, or NULL to use the + * system trust store. + * @return CMTrue on success, CMFalse if a path is too long to store. + */ CMBool (*SetSSLCert)( CMUTIL_HttpClient *client, const char *certfile, const char *keyfile, const char *cafile ); + + /** + * @brief Whether to keep connections open between requests. + * + * On by default. A server that answers with HTTP/1.0, or with + * Connection: close, ends the connection regardless. + * + * @param client This HTTP client object. + * @param keepalive CMFalse to close the connection after each request. + */ void (*SetKeepAlive)( CMUTIL_HttpClient *client, CMBool keepalive); + + /** + * @brief Perform a request with any method. + * + * Get and Post are this function with the method filled in; use it + * directly for PUT, DELETE, HEAD, PATCH and the rest. + * + * Host, Connection and - for a method that carries a + * body - Content-Length are supplied automatically unless + * @a headers already names them. + * + * @param client This HTTP client object. + * @param method Request method, such as "GET". + * @param headers Request headers as a map of C strings, or NULL. The + * map is only read. + * @param uri Request URI, relative to the prefix given at creation. + * @param body Request body, or NULL. It is only sent for POST and PUT. + * @param status Receives the response status code. It is left untouched + * when the request never reaches a response, so initialize it. + * @param timeout Timeout in milliseconds, applied to each socket + * operation the request performs. + * @return The response body, which the caller must destroy, or NULL if + * the request failed. A response with no body yields an empty + * buffer rather than NULL. + */ CMUTIL_ByteBuffer *(*Request)( CMUTIL_HttpClient *client, const char *method, @@ -4840,12 +5171,35 @@ struct CMUTIL_HttpClient { CMUTIL_ByteBuffer *body, int *status, long timeout); + + /** + * @brief Perform a GET request. + * + * @param client This HTTP client object. + * @param headers Request headers as a map of C strings, or NULL. + * @param uri Request URI, relative to the prefix given at creation. + * @param status Receives the response status code. + * @param timeout Timeout in milliseconds. + * @return The response body, which the caller must destroy, or NULL. + */ CMUTIL_ByteBuffer *(*Get)( CMUTIL_HttpClient *client, CMUTIL_Map *headers, const char *uri, int *status, long timeout); + + /** + * @brief Perform a POST request. + * + * @param client This HTTP client object. + * @param headers Request headers as a map of C strings, or NULL. + * @param uri Request URI, relative to the prefix given at creation. + * @param body Request body. Ownership stays with the caller. + * @param status Receives the response status code. + * @param timeout Timeout in milliseconds. + * @return The response body, which the caller must destroy, or NULL. + */ CMUTIL_ByteBuffer *(*Post)( CMUTIL_HttpClient *client, CMUTIL_Map *headers, @@ -4853,14 +5207,41 @@ struct CMUTIL_HttpClient { CMUTIL_ByteBuffer *body, int *status, long timeout); + + /** + * @brief Destroy this client. + * + * Connections this client left in the pool are not closed here; they + * are closed when they expire, or at CMUTIL_Clear(). + * + * @param client This HTTP client object. + */ void (*Destroy)( CMUTIL_HttpClient *client); }; +/** + * @brief Create an HTTP client for the given URL prefix. + * + * @param urlprefix Scheme, host and optional port, like + * "https://example.com:8443". The port defaults to 80 for + * http and 443 for https. + * @return A new HTTP client, or NULL if the prefix could not be parsed. + * Destroy it with its Destroy method. + */ CMUTIL_API CMUTIL_HttpClient *CMUTIL_HttpClientCreate(const char *urlprefix); /** - * @typedef CMJsonType JSON value types. + * @} + */ + +/** + * @defgroup CMUTILS_Json JSON parsing and the document model. + * @{ + */ + +/** + * @brief JSON value types. */ typedef enum CMJsonType { /** JSON value type. */ @@ -4872,7 +5253,7 @@ typedef enum CMJsonType { } CMJsonType; /** - * @typedef CMUTIL_Json JSON base object. + * @brief JSON base object. */ typedef struct CMUTIL_Json CMUTIL_Json; struct CMUTIL_Json { @@ -4935,7 +5316,7 @@ struct CMUTIL_Json { #define CMUTIL_JsonDestroy(a) CMCall((CMUTIL_Json*)(a), Destroy) /** - * @typedef CMJsonValueType JSON value types. + * @brief JSON value types. */ typedef enum CMJsonValueType { /** JSON long integer type. */ @@ -4951,7 +5332,7 @@ typedef enum CMJsonValueType { } CMJsonValueType; /** - * @typedef CMUTIL_JsonValue JSON value object. + * @brief JSON value object. * * Must be destroyed with CMUTIL_JsonDestroy. */ @@ -5091,7 +5472,7 @@ struct CMUTIL_JsonValue { CMUTIL_API CMUTIL_JsonValue *CMUTIL_JsonValueCreate(void); /** - * @typedef CMUTIL_JsonObject JSON object. + * @brief JSON object. * * Must be destroyed with CMUTIL_JsonDestroy. */ @@ -5304,7 +5685,7 @@ struct CMUTIL_JsonObject { CMUTIL_API CMUTIL_JsonObject *CMUTIL_JsonObjectCreate(void); /** - * @typedef CMUTIL_JsonArray JSON array type. + * @brief JSON array type. * * Must be destroyed with CMUTIL_JsonDestroy. */ @@ -5520,11 +5901,20 @@ CMUTIL_API CMUTIL_Json *CMUTIL_JsonParse(CMUTIL_String *jsonstr); */ CMUTIL_API CMUTIL_Json *CMUTIL_XmlToJson(CMUTIL_XmlNode *node); +/** + * @} + */ + /** - * @typedef CMUTIL_RestClient A JSON layer over CMUTIL_HttpClient. + * @addtogroup CMUTILS_Network + * @{ + */ + +/** + * @brief A JSON layer over CMUTIL_HttpClient. * * A REST client serializes the request body from a CMUTIL_Json, parses the * response body back into one, and adds the two JSON content negotiation @@ -5653,7 +6043,16 @@ struct CMUTIL_RestClient { CMUTIL_API CMUTIL_RestClient *CMUTIL_RestClientCreate(const char *urlprefix); /** - * @typedef Enumeration of process stream types. + * @} + */ + +/** + * @defgroup CMUTILS_Process Child process creation and control. + * @{ + */ + +/** + * @brief of process stream types. */ typedef enum CMProcStreamType { /** @@ -5689,7 +6088,7 @@ typedef enum CMProcStreamType { } CMProcStreamType; /** - * @typedef Process structure for managing external processes. + * @brief structure for managing external processes. */ typedef struct CMUTIL_Process CMUTIL_Process; struct CMUTIL_Process { @@ -5906,6 +6305,10 @@ CMUTIL_API CMUTIL_Process *CMUTIL_ProcessCreateEx( const char *command, ...); +/** + * @} + */ + /** * @brief Creates a new process with the specified command and arguments. * @@ -5924,7 +6327,11 @@ CMUTIL_API CMUTIL_Process *CMUTIL_ProcessCreateEx( /** - * @struct CMUTIL_BlockCrypto + * @defgroup CMUTILS_Crypto Block ciphers, RSA, Base64 and secure random. + * @{ + */ + +/** * @brief Block cipher encryption/decryption object. */ typedef struct CMUTIL_BlockCrypto CMUTIL_BlockCrypto; @@ -5977,11 +6384,24 @@ CMUTIL_API CMUTIL_BlockCrypto *CMUTIL_BlockCryptoCreate( /** - * @struct CMUTIL_RSAKey * @brief RSA key object (can be either a private or public key). */ typedef struct CMUTIL_RSAKey CMUTIL_RSAKey; + +/** + * @brief An RSA key that can decrypt and sign. + * + * The same object as CMUTIL_RSAKey; the two names exist to say which half + * of a key pair a function expects. + */ typedef CMUTIL_RSAKey CMUTIL_PrivateKey; + +/** + * @brief An RSA key that can encrypt and verify. + * + * The same object as CMUTIL_RSAKey; the two names exist to say which half + * of a key pair a function expects. + */ typedef CMUTIL_RSAKey CMUTIL_PublicKey; struct CMUTIL_RSAKey { /** @@ -6033,7 +6453,6 @@ CMUTIL_API CMUTIL_PublicKey *CMUTIL_PublicKeyCreateFromFile( const char *file_path); /** - * @struct CMUTIL_RSACrypto * @brief RSA encryption/decryption and signature object. */ typedef struct CMUTIL_RSACrypto CMUTIL_RSACrypto; @@ -6127,6 +6546,10 @@ CMUTIL_API CMUTIL_RSACrypto *CMUTIL_RSACryptoCreate(void); */ CMUTIL_API void CMUTIL_CryptoRandom(uint8_t *buf, size_t len); +/** + * @} + */ + /** * @brief Encodes data to Base64 string. * @param data The data to encode.