You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
naka/include/version.h

64 lines
2.9 KiB

#ifndef _VERSION_H
#define _VERSION_H
#include "macros.h"
#include "ints.h"
typedef union {
uint32_t raw;
// XXX: Punning through this union is unsafe, it may work (on little endian machines), but it is not intended to be punned. Use `v_rawtoc` and `v_ctoraw` instead.
struct v_comp {
u8 revision, bugfix, minor, major;
} comp;
} version_t;
// Convert a native `u32` representation of a version (the output of `VERSION()` macro) to a `version_t`.
#define v_rawtoc_unsafe(raw) ((version_t){ .raw = (raw) })
_mixin version_t v_rawtoc(uint32_t raw)
{
register version_t out = {
.comp = {
.major = VERSION_MAJ(raw),
.minor = VERSION_MIN(raw),
.bugfix = VERSION_BF(raw),
.revision = VERSION_REV(raw),
},
};
return out;
}
/// Convert a `version_t` to its native `u32` representation.
#define v_ctoraw_unsafe(ver) ((ver).raw)
_mixin uint32_t v_ctoraw(version_t ver)
{
return VERSION(ver.comp.major,
ver.comp.minor,
ver.comp.bugfix,
ver.comp.revision);
}
#define VERSION_C(ma,mi,bf,re) v_rawtoc(VERSION((ma),(mi),(bf),(re)))
#define VERSION_STRING_MAX AS(3 + 3 + 3 + 3 + 3, usize) // maj + min + bf + rev + (..r)
/// Print a version to a string buffer `out`. Return the number of bytes written.
///
/// Has the same semantics as `snprintf`; to calculate the length of the string needed to allocate, invoke like: `size_t sz = v_ctosn(vers, 0, NULL)`. The buffer should be allocated as `sz + 1`, and then the next call to `v_ctosn` should be like: `v_ctosn(vers, sz+1, buffer);
//XXX: Specifying `str[static ...` tells the compiler this function expects a non-null pointer. When in reality, a `NULL` pointer is used here as a sentinel value to not print... The mixin below is a hack around this, but this might introduce invalid optimisations. We should either: split the size getting function into its own thing (`v_ctosn_sz` would become a real function) that does the exact same thing as `v_ctosn(_,0,NULL)`, and not pass `NULL` to str here ever. OR, change str to regular `char *pOUT str`. The latter would be easier, but we might potentially lose out on some obscure non-NULL snprintf optimisation? For now, just use the `v_ctosn_sz` hack below. If we go with the latter, we can #define it to be just `v_ctosn(v, 0, NULL)`, otherwise move it to version.c and implement it with `snprintf(NULL, 0, ...)`.
usize v_ctosn(version_t ver, usize max, char str[static pOUT max]);
_mixin usize v_ctosn_sz(version_t ver)
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnonnull"
return v_ctosn(ver, 0, NULL);
#pragma GCC diagnostic pop
}
/// Print a version to a static string buffer. The string buffer is thread local. The next call to this function on the same thread will overwrite the returned buffer.
const char* v_ctoss(version_t ver);
/// Print a version to a `malloc()`d string buffer. The buffer is unique and owned by the callee. The buffer must be `free()`d.
char* v_ctos(version_t ver);
#endif /* _VERSION_H */