ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
time_compat.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file time_compat.h
6 * @brief Reentrant UTC broken-down time, portable across the host and target toolchains.
7 *
8 * Responses are formatted from worker threads, so every conversion must write into caller storage -
9 * never the shared static `tm` that `gmtime()` returns. The toolchains disagree on how to spell
10 * that: newlib and glibc have `gmtime_r`, the Windows CRT has only `gmtime_s`, with the arguments
11 * reversed. This is the one seam that hides the difference, so callers write it once.
12 *
13 * @author Douglas Quigg (dstroy0)
14 * @date 2026
15 */
16
17#ifndef PROTOCORE_TIME_COMPAT_H
18#define PROTOCORE_TIME_COMPAT_H
19
20#include <time.h> // struct tm and the gmtime_r / gmtime_s the seam picks between
21
22#include "protocore_config.h" // the entry point
23
24/** @brief The instant a conversion reads, and the storage it fills. */
25typedef struct
26{
27 time_t epoch; ///< seconds since the Unix epoch
28 struct tm *out; ///< the caller's destination; must be non-null
30
31/**
32 * @brief Broken-down UTC in caller storage, whichever runtime is underneath.
33 *
34 * @var TimeCompatNs::args the instant a conversion reads, and the storage it fills
35 * @var TimeCompatNs::tm_out @c args.out on success, or NULL when the instant cannot be represented
36 * @var TimeCompatNs::gmtime convert to broken-down UTC
37 *
38 * Reentrant: the destination is the caller's. One runtime takes (tm, time) and reports an errno_t,
39 * the other takes (time, tm) and reports the destination; both are reduced to @ref tm_out here.
40 *
41 * No storage member: nothing is held between calls.
42 */
43typedef struct
44{
46 struct tm *tm_out;
48
49/** @brief The operands and the outcome. */
51
52/** @brief The entries. */
53typedef struct
54{
55 void (*const gmtime)(uint8_t *work);
57
58// What the table binds, defined once in the .c and taking one parameter each: everything
59// else an entry needs is an operand in TimeCompatV or a region of the borrow at a fixed offset.
60void protocore_time_compat_gmtime(uint8_t *work);
61
62// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
63// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
64// `TimeCompat.gmtime(work)` resolves to a named function and becomes a DIRECT call. An extern table
65// leaves the call indirect and the symbol live at every level, -O2 -flto included.
66static const TimeCompatNs TimeCompat __attribute__((unused)) = {
68};
69
70#endif // PROTOCORE_TIME_COMPAT_H
The instant a conversion reads, and the storage it fills.
Definition time_compat.h:26
time_t epoch
seconds since the Unix epoch
Definition time_compat.h:27
struct tm * out
the caller's destination; must be non-null
Definition time_compat.h:28
The entries.
Definition time_compat.h:54
void(*const gmtime)(uint8_t *work)
Definition time_compat.h:55
struct tm * tm_out
Definition time_compat.h:46
TimeCompatArgs args
Definition time_compat.h:45
void protocore_time_compat_gmtime(uint8_t *work)
TimeCompatVars TimeCompatV
The operands and the outcome.