#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`, however, the compiler assumes `str` to be non-NULL. To get the buffer size required, use `v_ctosn_sz()` instead. usize v_ctosn(version_t ver, usize max, char str[static pOUT max]); /// Get the buffer size required for `v_ctosn().` /// /// Same as calling `v_ctosn(ver, 0, NULL)` but won't warn about non-NULL parameter `str`. usize v_ctosn_sz(version_t ver); /// 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 */