TODO: Move them out of header and into seperate TU "version.c" version_t holds version components. `v_rawtoc()`, `v_ctoraw()` to create from/convert to the format used by `VERSION()` macro and friends. Punning this union between the raw (u32, used by the macros) and the componant struct (`v_comp`) is possible on little endian machines but discouraged. Fortune for naka's current commit: Half blessing − 半吉generic-project-skeleton
parent
d9ccfa0d89
commit
fb2fa5801e
@ -0,0 +1,79 @@
|
||||
#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)
|
||||
|
||||
//TODO: Move the below functions to `version.c` and have them prototyped, not mixins.
|
||||
|
||||
/// 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);
|
||||
_mixin usize v_ctosn(version_t ver, usize max, char out[static pOUT max])
|
||||
{
|
||||
struct v_comp comp = ver.comp;
|
||||
const char* const fmt = comp.revision ? "%hhu.%hhu.%hhur%hhu" : "%hhu.%hhu.%hhu";
|
||||
|
||||
|
||||
return snprintf(out, max, fmt,
|
||||
comp.major,
|
||||
comp.minor,
|
||||
comp.bugfix,
|
||||
comp.revision);
|
||||
}
|
||||
|
||||
/// 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.
|
||||
_mixin const char* v_ctoss(version_t ver)
|
||||
{
|
||||
_Thread_local static char buffer[VERSION_STRING_MAX+1];
|
||||
buffer[v_ctosn(ver, VERSION_STRING_MAX+1, buffer)] = 0;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// Print a version to a `malloc()`d string buffer. The buffer is unique and owned by the callee. The buffer must be `free()`d.
|
||||
_mixin char* v_ctos(version_t ver)
|
||||
{
|
||||
usize sz = v_ctosn(ver, 0, NULL);
|
||||
char* buf = malloc(sz+1);
|
||||
v_ctosn(ver, sz+1, buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
#endif /* _VERSION_H */
|
Loading…
Reference in new issue