[*] Initial commit

This commit is contained in:
Lorenzo Cogotti
2021-06-07 16:55:13 +02:00
commit b0ef4dd774
117 changed files with 29737 additions and 0 deletions

104
lonetix/include/df/sys/con.h Executable file
View File

@ -0,0 +1,104 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
/**
* \file sys/con.h
*
* System console interface.
*
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
* \author Lorenzo Cogotti
*
* Provides basic functionality to print to system console and
* test for supported capabilities.
*/
#ifndef DF_SYS_CON_H_
#define DF_SYS_CON_H_
#include "stm.h"
#include <stdarg.h>
/**
* \typedef ConHn
* \brief Platform console handle descriptor.
*
* \def STDIN
* \brief Platform Standard Input (`stdin`) handle.
* \def STDOUT
* \brief Platform Standard Output (`stdout`) handle.
* \def STDERR
* \brief Platform Standard Error (`stderr`) handle.
*
* \fn Fildes CON_FILDES(ConHn)
*
* \brief Convert a `ConHn` to a `Fildes`, making the console handle usable with
* regular platform file API.
*/
#ifdef _WIN32
typedef Uint32 /*DWORD*/ ConHn;
#define STDIN ((ConHn) -10) // STD_INPUT_HANDLE
#define STDOUT ((ConHn) -11) // STD_OUTPUT_HANDLE
#define STDERR ((ConHn) -12) // STD_ERROR_HANDLE
Fildes CON_FILDES(ConHn hn);
#else
typedef int ConHn;
#define STDIN ((ConHn) 0)
#define STDOUT ((ConHn) 1)
#define STDERR ((ConHn) 2)
FORCE_INLINE Fildes CON_FILDES(ConHn hn)
{
return (Fildes) hn; // trivial on Unix
}
#endif
/**
* \brief Convert a `ConHn` to a `streamp` pointer for `StmOps`.
*
* \see `Stm_ConOps`
*/
FORCE_INLINE void *STM_CONHN(ConHn hn)
{
STATIC_ASSERT(sizeof(Sintptr) >= sizeof(void *), "ConHn ill formed on this platform");
return (void *) ((Sintptr) hn);
}
/**
* \brief `StmOps` interface operating on console output.
*
* There is no `Close()` function for consoles.
*/
extern const StmOps *const Stm_ConOps;
/**
* Print string to console.
*
* \note No newline is appended.
*/
void Sys_Print(ConHn hn, const char *s);
/// Formatted print to console handle.
CHECK_PRINTF(2, 3) void Sys_Printf(ConHn hn, const char *fmt, ...);
/// `Sys_Printf()` variant using `va_list`.
CHECK_PRINTF(2, 0) void Sys_VPrintf(ConHn hn, const char *fmt, va_list va);
/**
* \brief Read at most `nbytes` characters from `hn` to `buf`, input is *not* `\0` terminated.
*
* \return Count of `char`s written to `buf`.
*/
size_t Sys_Read(ConHn hn, char *buf, size_t nbytes);
/// Non-Blocking variant of `Sys_Read()`.
size_t Sys_NbRead(ConHn hn, char *buf, size_t nbytes); // NON-BLOCKING
/// Test whether `hn` supports VT100 commands.
Boolean Sys_IsVt100Console(ConHn hn);
#endif

59
lonetix/include/df/sys/dbg.h Executable file
View File

@ -0,0 +1,59 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
/**
* \file sys/dbg.h
*
* Debugging utilities to retrieve stack trace and symbol names.
*
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
* \author Lorenzo Cogotti
*/
#ifndef DF_SYS_DBG_H_
#define DF_SYS_DBG_H_
#include "sys/con.h"
/// Helper union to cast `void *` to function pointer - be sad if you use it.
typedef union {
void *sym; ///< Function as a `void *`
void (*func)(void); ///< Function pointer.
} Funsym;
STATIC_ASSERT(sizeof(void *) == sizeof(void (*)(void)), "Ill-formed Funsym for target platform");
/// Test whether the current process is being executed under a debugger.
Boolean Sys_IsDebuggerPresent(void);
/**
* \brief Get a symbol's name, if available.
*
* \param [in] sym Symbol whose name is needed.
*
* \return A pointer to a statically allocated thread-local buffer containing
* a `\0` terminated symbol name on success, `NULL` if no name could be
* retrieved.
*/
char *Sys_GetSymbolName(void *sym);
/**
* \brief Dump at most `n` backtrace entries to `dest`.
*
* Returned backtrace does not include `Sys_GetBacktrace()`
* itself, and has the caller as the topmost symbol.
*
* \return Number of entries actually returned to `dest` on success,
* 0 when no backtrace information is available.
*/
size_t Sys_GetBacktrace(void **dest, size_t n);
/**
* \brief Get the caller's caller.
*
* Useful for quick debugging:
* ```c
* printf("Called by: %s\n", Sys_GetSymbolName(Sys_GetCaller()));
* ```
*/
void *Sys_GetCaller(void);
/// Dump backtrace to console (typically `STDERR`).
void Sys_DumpBacktrace(ConHn hn, void **trace, size_t n);
#endif

132
lonetix/include/df/sys/endian.h Executable file
View File

@ -0,0 +1,132 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
/**
* \file sys/endian.h
*
* Architecture specific byteswap utilities.
*
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
* \author Lorenzo Cogotti
*/
#ifndef DF_SYS_ENDIAN_H_
#define DF_SYS_ENDIAN_H_
#include "xpt.h"
#ifdef _MSC_VER
#include <stdlib.h> // _byteswap_*()
#endif
/// Helper `union` to access bit representation of `float`.
typedef union {
float f32;
Uint32 bits;
} Floatbits;
/// Helper `union` to access bit representation of `double`.
typedef union {
double f64;
Uint64 bits;
} Doublebits;
STATIC_ASSERT(sizeof(Floatbits) == sizeof(Uint32), "float vs Uint32 size mismatch");
STATIC_ASSERT(sizeof(Doublebits) == sizeof(Uint64), "double vs Uint64 size mismatch");
/// Swap bytes inside 16-bits word.
FORCE_INLINE Uint16 bswap16(Uint16 x)
{
#ifdef _MSC_VER
return _byteswap_ushort(x);
#elif defined(__GNUC__)
return __builtin_bswap16(x);
#else
return BSWAP16(x);
#endif
}
/// Swap bytes inside 32-bits dword.
FORCE_INLINE Uint32 bswap32(Uint32 x)
{
#ifdef _MSC_VER
return _byteswap_ulong(x);
#elif defined(__GNUC__)
return __builtin_bswap32(x);
#else
return BSWAP32(x);
#endif
}
/// Swap bytes inside 64-bits quadword.
FORCE_INLINE Uint64 bswap64(Uint64 x)
{
#ifdef _MSC_VER
return _byteswap_uint64(x);
#elif defined(__GNUC__)
return __builtin_bswap64(x);
#else
return BSWAP64(x);
#endif
}
/// `bswap16()` if target isn't little-endian.
FORCE_INLINE Uint16 leswap16(Uint16 x)
{
#if EDN_NATIVE == EDN_LE
return x;
#else
return bswap16(x);
#endif
}
/// `bswap16()` if target isn't big-endian.
FORCE_INLINE Uint16 beswap16(Uint16 x)
{
#if EDN_NATIVE == EDN_BE
return x;
#else
return bswap16(x);
#endif
}
/// `bswap32()` if target isn't little-endian.
FORCE_INLINE Uint32 leswap32(Uint32 x)
{
#if EDN_NATIVE == EDN_LE
return x;
#else
return bswap32(x);
#endif
}
/// `bswap32()` if target isn't big-endian.
FORCE_INLINE Uint32 beswap32(Uint32 x)
{
#if EDN_NATIVE == EDN_BE
return x;
#else
return bswap32(x);
#endif
}
/// `bswap64()` if target isn't little-endian.
FORCE_INLINE Uint64 leswap64(Uint64 x)
{
#if EDN_NATIVE == EDN_LE
return x;
#else
return bswap64(x);
#endif
}
/// `bswap64()` if target isn't big-endian.
FORCE_INLINE Uint64 beswap64(Uint64 x)
{
#if EDN_NATIVE == EDN_BE
return x;
#else
return bswap64(x);
#endif
}
#endif

253
lonetix/include/df/sys/fs.h Executable file
View File

@ -0,0 +1,253 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
/**
* \file sys/fs.h
*
* Portable low-level filesystem layer
*
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
* \author Lorenzo Cogotti
*
* Achieves portable low-level, close to operating system, filesystem
* functionality. Functionality includes:
* - file I/O
* - file usage hints
* - file creation and removal
* - directory listing, creation and removal
* - path utilities.
*
* No library file buffering is attempted, nor any kind of text-based I/O.
* Paths are UTF-8.
*/
#ifndef DF_SYS_FS_H_
#define DF_SYS_FS_H_
#include "sys/fsdef.h" // platform-specific defs, including `Fildes`
/// File access mode for `Sys_Fopen()`.
typedef enum {
FM_READ, ///< Read-only access
FM_WRITE, ///< Write-only access
FM_APPEND, ///< File-append access
FM_EXCL, ///< Exclusive creation access
FM_TEMP ///< Temporary scratch file creation
} FopenMode;
/// Access pattern is sequential.
#define FH_SEQ BIT(0)
/// Access pattern is random.
#define FH_RAND BIT(1)
/// Avoid filesystem cache buffers with this file.
#define FH_UNBUF BIT(2)
/// File data is accessed once and never reused.
#define FH_NOREUSE BIT(3)
/**
* \brief Open a descriptor handle to a regular or special file.
*
* Every successfully opened file descriptor must be closed using
* `Sys_Fclose()` when no longer necessary.
*
* \param [in] filename Path to file, must not be `NULL`
* \param [in] mode File access mode
* \param [in] hints File access hints (`FH_*` bit mask)
*
* \return Opened file descriptor on success, `FILDES_BAD` on failure.
*/
Fildes Sys_Fopen(const char *filename, FopenMode mode, unsigned hints);
/**
* \brief Move file's cursor to the specified offset.
*
* \param [in] fd Opened file descriptor
* \param [in] offset Offset to move the cursor to, according to `whence`, in bytes
* \param [in] whence Seek mode
*
* \return New cursor position on success, -1 on failure or non-seekable file.
*/
Sint64 Sys_Fseek(Fildes fd, Sint64 offset, SeekMode whence);
/// Retrieve current file cursor position, returns -1 on failure or non-seekable file.
Sint64 Sys_Ftell(Fildes fd);
/// Get current file size, in bytes, -1 on error.
Sint64 Sys_FileSize(Fildes fd);
/**
* \brief Write raw bytes to file.
*
* \param [in] fd Opened, writable, file descriptor
* \param [in] buf Containing at least `nbytes` bytes of data
* \param [in] nbytes Bytes count in `buf` to be written to `fd`
*
* \return Number of bytes actually written on `fd`, possibly less
* than `nbytes` on short-write. -1 on failure.
*/
Sint64 Sys_Fwrite(Fildes fd, const void *buf, size_t nbytes);
/**
* \brief Read raw bytes from file.
*
* \param [in] fd Opened, readable, file descriptor
* \param [out] buf Destination buffer for the read operation
* \param [in] nbytes Bytes count to read from `fd` inside `buf`
*
* \return Number of bytes actually read from `fd`, possibly less than `nbytes`,
* 0 is returned on `EOF` condition. -1 on failure.
*/
Sint64 Sys_Fread(Fildes fd, void *buf, size_t nbytes);
/**
* \brief Truncate or grow file size to its current cursor position.
*
* \return `OK` on success, and file is altered as follows,
* - if file size has been truncated excess data is lost;
* - if file has grown in size (file cursor was beyond the original size),
* new content is unspecified.
* On failure returns `NG` and file is unaltered.
*/
Judgement Sys_SetEof(Fildes fd);
/**
* \brief Synchronize file data to disk, flushing buffers.
*
* Some systems require `fd` to be writable, whether `Sys_Fsync()` supports
* a read-only descriptor is system specific.
* Some systems allow optimized syncs that only guarantee read operations
* consistency afterwards, this optimization is used on such systems when
* `fullSync` is `FALSE`. otherwise `fullSync` is ignored (as if always `TRUE`).
* A call to `Sys_Fsync()` with `fullSync` to `TRUE` causes the system
* to sync disk data with `fd` in its entirety.
*
* \param [in] fd Opened file descriptor
* \param [in] fullSync Whether a full sync should occur
*
* \return `OK` on success, `NG` on failure or on systems where
* there is no mean to force file data sync with disk.
*/
Judgement Sys_Fsync(Fildes fd, Boolean fullSync);
/// Close opened file descriptor.
void Sys_Fclose(Fildes fd);
/**
* \brief List directory contents.
*
* `pat` | Meaning
* ---------|------------------------------------------
* __NULL__ | Equivalent to `""`
* "" | No filtering
* / | Only return subdirectories
* .* | Only return files whose extension matches
*
* \param [in] path Path to directory, must not be `NULL`
* \param [out] nfiles Location to store returned file count, may be `NULL` if unimportant
* \param [in] pat Optional pattern to filter directory files, may be `NULL`
*
* \return `malloc()`ed string list containing matching files,
* must be `free()`d by the caller when no longer necessary.
* A single `free()` on the returned list is sufficient to
* release it entirely.
*/
char **Sys_ListFiles(const char *path, unsigned *nfiles, const char *pat);
/**
* \brief Create directory.
*
* \param [in] path Directory creation path, must not be `NULL`
*
* \return `OK` on success, and directory is created.
* Creating already existing directories is a success.
* `NG` on failure.
*/
Judgement Sys_Mkdir(const char *path);
/**
* \brief Rename a file.
*
* Different systems may impose different restrictions on
* rename operations, in particular when the operation crosses
* different devices in the filesystem.
* The only portable and safe way to rename a file (or, in this
* specific scenario, *move* it) is copying it over `newPath`,
* and remove `path` on success, but the basic `rename` operation is
* usually safe, unexpensive and atomic under the same device.
* `Sys_Rename()` works on directories as well.
*
* \param [in] path Path to the file to be renamed, must not be `NULL`
* \param [in] newPath New name for the file, destination directory must exist
*
* \return `OK` on success, `NG` otherwise.
*/
Judgement Sys_Rename(const char *path, const char *newPath);
/**
* \brief Remove a file or empty directory.
*
* \param [in] path Path to file or directory to be removed, must not be `NULL`
*
* \return `OK` on success, `NG` otherwise.
*/
Judgement Sys_Remove(const char *path);
// Path utilities
/// Retrieve the absolute file extension (leftmost not leading dot in basename).
char *Sys_GetAbsoluteFileExtension(const char *path);
/// Retrieve the file extension (rightmost not leading dot in basename).
char *Sys_GetFileExtension(const char *path);
/**
* \brief Set `path` file extension to `ext`.
*
* \param [in,out] path UTF-8 path, must not be `NULL`
* \param [in] ext File extension, including dot, must not be `NULL`
*
* \return Pointer to the extension inside `path`.
*
* \note Assumes `path` is is large enough to hold the result.
*/
char *Sys_SetFileExtension(char *path, const char *ext);
/**
* \brief Removes extension from `path` if it matches `ext`.
*
* \param [in,out] path UTF-8 path, must not be `NULL`
* \param [in] ext File extension, including dot, leave to `""` or `NULL`
* to remove any extension
*
* \return Length of the resulting path, in chars.
*/
size_t Sys_StripFileExtension(char *path, const char *ext);
/**
* \brief If file in `path` has no extension yet, set it to `ext`.
*
* \param [in,out] path UTF-8 path, must not be `NULL`
* \param [in] ext Default extension to be set, including dot, must not be `NULL`
*
* \return Pointer to the extension inside `path`
*
* \note Assums `path` is large enough to hold the result.
*/
char *Sys_DefaultFileExtension(char *path, const char *ext);
/**
* Strip initial portion of `path` if it matches `basePath`.
*
* \param [in,out] path UTF-8 path, must not be `NULL`
* \param [in] basePath Initial path to be removed, use `""` or `NULL` to strip the entire path and leave only file (Unix `basename()`)
*
* \return Length of the resulting path, in chars.
*/
size_t Sys_StripPath(char *path, const char *basePath);
/// Return `path` depth (number of path components).
size_t Sys_PathDepth(const char *path);
/**
* \brief Strip leading slashes and change any path separator to `/`.
*
* \return Resulting path length, in chars.
*/
size_t Sys_ConvertPath(char *path);
/**
* \brief Change any path separator to a single `PATH_SEP`.
*
* \return Resulting path length, in chars.
*/
size_t Sys_ReplaceSeps(char *path);
/// Case-sensitive UTF-8 path comparison, regardless of separators.
int Sys_PathCompare(const char *a, const char *b);
// XXX int Sys_PathCompareNoCase(const char *a, const char *b);
// XXX int Sys_PathCompareNoCaseAscii(const char *a, const char *b);
#endif

58
lonetix/include/df/sys/fsdef.h Executable file
View File

@ -0,0 +1,58 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
/**
* \file sys/fsdef.h
*
* Platform-specific filesystem types and definitions.
*
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
* \author Lorenzo Cogotti
*/
#ifndef DF_SYS_FSDEF_H_
#define DF_SYS_FSDEF_H_
#include "xpt.h"
/**
* \typedef Fildes
* \brief Platform specific file handle (`HANDLE` on Windows, `int` elsewhere).
*
* \def FILDES_BAD
* \brief Bad file descriptor.
*
* \def PATH_SEP
* \brief Path separator character (`\` on Windows, `/` elsewhere).
*
* \def EOLN
* \brief Text file newline sequence (`\r\n` on Windows, `\n` elsewhere).
*/
#ifdef _WIN32
typedef void *Fildes;
#define FILDES_BAD 0
#define PATH_SEP '\\'
#define EOLN "\r\n"
#else
typedef int Fildes;
#define FILDES_BAD -1
#define PATH_SEP '/'
#define EOLN "\n"
#endif
/// I/O stream seek modes.
typedef enum {
SK_SET, ///< Seek from beginning of stream
SK_CUR, ///< Seek from current position
SK_END ///< Seek from stream end
} SeekMode;
#endif

View File

@ -0,0 +1,136 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
/**
* \file sys/interlocked.h
*
* Lock-free atomic operations on integers and pointers.
*
* \copyright The DoubleFourteen Code Forge (c) All Rights Reserved
* \author Lorenzo Cogotti
*/
#ifndef DF_SYS_INTERLOCKED_H_
#define DF_SYS_INTERLOCKED_H_
#include "xpt.h"
/**
* \fn void Smp_AtomicStore(long *p, long v)
* \fn void Smp_AtomicStoreRx(long *p, long v)
* \fn void Smp_AtomicStoreRel(long *p, long v)
* \fn void Smp_AtomicStorePtr(void **p, void *v)
* \fn void Smp_AtomicStorePtrRx(void **p, void *v)
* \fn void Smp_AtomicStorePtrRel(void **p, void *v)
* \fn void Smp_AtomicStore8(Sint8 *p, Sint8 v)
* \fn void Smp_AtomicStore8Rx(Sint8 *p, Sint8 v)
* \fn void Smp_AtomicStore8Rel(Sint8 *p, Sint8 v)
* \fn void Smp_AtomicStore16(Sint16 *p, Sint16 v)
* \fn void Smp_AtomicStore16Rx(Sint16 *p, Sint16 v)
* \fn void Smp_AtomicStore16Rel(Sint16 *p, Sint16 v)
* \fn void Smp_AtomicStore32(Sint32 *p, Sint32 v)
* \fn void Smp_AtomicStore32Rx(Sint32 *p, Sint32 v)
* \fn void Smp_AtomicStore32Rel(Sint32 *p, Sint32 v)
* \fn void Smp_AtomicStore64(Sint64 *p, Sint64 v)
* \fn void Smp_AtomicStore64Rx(Sint64 *p, Sint64 v)
* \fn void Smp_AtomicStore64Rel(Sint64 *p, Sint64 v)
*
* Atomic store operation to a variable or pointer.
*
* \note Only a subset of the fixed-size variants may be available on
* specific architectures.
*/
#ifdef _MSC_VER
#include "interlocked_intrin_msvc.h"
#include "interlocked_ops_msvc.h"
#else
#if __GCC_ATOMIC_LONG_LOCK_FREE != 2
#error "interlocked.h requires lock-free atomics on long!"
#endif
#if __GCC_ATOMIC_POINTER_LOCK_FREE != 2
#error "interlocked.h requires lock-free atomics on void *!"
#endif
/******************************************************************************
* ATOMICS ON FIXED SIZE INTEGERS *
******************************************************************************/
#if __GCC_ATOMIC_CHAR_LOCK_FREE == 2
#define INTERLOCKED_INT8
#define INTERLOCKED_TYPE Sint8
#define INTERLOCKED_SUFFIX 8
#include "interlocked_ops_gcc.h"
#undef INTERLOCKED_TYPE
#undef INTERLOCKED_SUFFIX
#endif /* INTERLOCKED_INT8 */
#if (__SIZEOF_SHORT__ == 2 && __GCC_ATOMIC_SHORT_LOCK_FREE == 2) || \
(__SIZEOF_INT__ == 2 && __GCC_ATOMIC_INT_LOCK_FREE == 2)
#define INTERLOCKED_INT16
#define INTERLOCKED_TYPE Sint16
#define INTERLOCKED_SUFFIX 16
#include "interlocked_ops_gcc.h"
#undef INTERLOCKED_TYPE
#undef INTERLOCKED_SUFFIX
#endif /* INTERLOCKED_INT16 */
#if (__SIZEOF_INT__ == 4 && __GCC_ATOMIC_INT_LOCK_FREE == 2) || \
(__SIZEOF_LONG__ == 4)
#define INTERLOCKED_INT32
#define INTERLOCKED_TYPE Sint32
#define INTERLOCKED_SUFFIX 32
#include "interlocked_ops_gcc.h"
#undef INTERLOCKED_TYPE
#undef INTERLOCKED_SUFFIX
#endif /* INTERLOCKED_INT32 */
#if (__SIZEOF_LONG_LONG__ == 8 && __GCC_ATOMIC_LONG_LONG_LOCK_FREE == 2) || \
(__SIZEOF_LONG__ == 8)
#define INTERLOCKED_INT64
#define INTERLOCKED_TYPE Sint64
#define INTERLOCKED_SUFFIX 64
#include "interlocked_ops_gcc.h"
#undef INTERLOCKED_TYPE
#undef INTERLOCKED_SUFFIX
#endif /* INTERLOCKED_INT64 */
/******************************************************************************
* ATOMICS ON LONG INTEGERS *
******************************************************************************/
#define INTERLOCKED_TYPE long
#define INTERLOCKED_SUFFIX
#include "interlocked_ops_gcc.h"
#undef INTERLOCKED_TYPE
#undef INTERLOCKED_SUFFIX
/******************************************************************************
* ATOMICS ON POINTERS *
******************************************************************************/
#define INTERLOCKED_TYPE void *
#define INTERLOCKED_SUFFIX Ptr
#define INTERLOCKED_NO_ARIT
#include "interlocked_ops_gcc.h"
#undef INTERLOCKED_TYPE
#undef INTERLOCKED_SUFFIX
#undef INTERLOCKED_NO_ARIT
#endif
#endif

View File

@ -0,0 +1,63 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
/**
* \file sys/interlocked_intrin_msvc.h
*
* MSVC-specific intrinsics for interlocked operations.
*
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
* \author Lorenzo Cogotti
*/
#ifndef DF_SYS_INTERLOCKED_H_
#error "use interlocked.h, do not include interlocked_intrin_msvc.h directly"
#endif
#pragma intrinsic(_InterlockedCompareExchange)
#pragma intrinsic(_InterlockedExchangeAdd)
#pragma intrinsic(_InterlockedExchange)
#pragma intrinsic(_InterlockedCompareExchangePointer)
#pragma intrinsic(_InterlockedExchangePointer)
#pragma intrinsic(_InterlockedCompareExchange8)
#pragma intrinsic(_InterlockedExchangeAdd8)
#pragma intrinsic(_InterlockedExchange8)
#pragma intrinsic(_InterlockedCompareExchange16)
#pragma intrinsic(_InterlockedExchangeAdd16)
#pragma intrinsic(_InterlockedExchange16)
#pragma intrinsic(_InterlockedAnd16)
#pragma intrinsic(_InterlockedOr16)
#pragma intrinsic(_InterlockedXor16)
#if (defined(_M_IX86) && _M_IX86 >= 500) || defined(_M_AMD64) || defined(_M_IA64) || defined(_M_ARM)
#pragma intrinsic(_InterlockedCompareExchange64)
#pragma intrinsic(_InterlockedExchangeAdd64)
#pragma intrinsic(_InterlockedExchange64)
#endif
#ifdef _M_ARM
#pragma intrinsic(_InterlockedCompareExchange_nf)
#pragma intrinsic(_InterlockedCompareExchange_acq)
#pragma intrinsic(_InterlockedCompareExchange_rel)
#pragma intrinsic(_InterlockedCompareExchangePointer_nf)
#pragma intrinsic(_InterlockedCompareExchangePointer_acq)
#pragma intrinsic(_InterlockedCompareExchangePointer_rel)
#pragma intrinsic(_InterlockedCompareExchange8_nf)
#pragma intrinsic(_InterlockedCompareExchange8_acq)
#pragma intrinsic(_InterlockedCompareExchange8_rel)
#pragma intrinsic(_InterlockedCompareExchange16_nf)
#pragma intrinsic(_InterlockedCompareExchange16_acq)
#pragma intrinsic(_InterlockedCompareExchange16_rel)
#pragma intrinsic(_InterlockedCompareExchange64_nf)
#pragma intrinsic(_InterlockedCompareExchange64_acq)
#pragma intrinsic(_InterlockedCompareExchange64_rel)
#endif /* _M_ARM */
#include <intrin.h>
#error "Sorry, not implemented yet"

View File

@ -0,0 +1,191 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
/**
* \file sys/interlocked_ops_gcc.h
*
* Generates interlocked functions from GCC intrinsics, based on some macros.
*
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
* \author Lorenzo Cogotti
*
* This file should be `#include`d from `interlocked.h`, on GNUC compilers.
* It generated interlocked primitives based on `INTERLOCKED_TYPE`,
* `INTERLOCKED_SUFFIX` macros.
* `#define`ing `INTERLOCKED_NO_ARIT` disables arithmetic functions
* generation.
* File may be `#include`d multiple times.
*/
#ifndef DF_SYS_INTERLOCKED_H_
#error "Use interlocked.h, do not include interlocked_gcc_ops.h directly"
#endif
#ifndef INTERLOCKED_TYPE
#error "Please define INTERLOCKED_TYPE for atomic operation target type"
#endif
#ifndef INTERLOCKED_SUFFIX
#error "Please define INTERLOCKED_SUFFIX for atomic operation suffix"
#endif
#define _PASTE(a, b) a ## b
#define _XPASTE(a, b) _PASTE(a, b)
#define _FNAME(wk, name, memory_order) \
_XPASTE(_XPASTE(Smp_ ## wk ## Atomic ## name, INTERLOCKED_SUFFIX), memory_order)
#define _FOP(op, memory_order, ...) \
__atomic_ ## op (__VA_ARGS__, __ATOMIC_ ## memory_order)
#define _FCAS(wkflag, succ_memory_order, fail_memory_order, ...) \
__atomic_compare_exchange_n(__VA_ARGS__, wkflag, __ATOMIC_ ## succ_memory_order, __ATOMIC_ ## fail_memory_order)
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Load,) (INTERLOCKED_TYPE *_p)
{
return _FOP(load_n, SEQ_CST, _p);
}
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Load,Rx) (INTERLOCKED_TYPE *_p)
{
return _FOP(load_n, RELAXED, _p);
}
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Load,Acq) (INTERLOCKED_TYPE *_p)
{
return _FOP(load_n, ACQUIRE, _p);
}
FORCE_INLINE void _FNAME(,Store,) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _v)
{
_FOP(store_n, SEQ_CST, _p, _v);
}
FORCE_INLINE void _FNAME(,Store,Rx) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _v)
{
_FOP(store_n, RELAXED, _p, _v);
}
FORCE_INLINE void _FNAME(,Store,Rel) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _v)
{
_FOP(store_n, RELEASE, _p, _v);
}
#ifndef INTERLOCKED_NO_ARIT
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Add,) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _v)
{
return _FOP(add_fetch, ACQ_REL, _p, _v);
}
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Add,Rx) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _v)
{
return _FOP(add_fetch, RELAXED, _p, _v);
}
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Add,Acq) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _v)
{
return _FOP(add_fetch, ACQUIRE, _p, _v);
}
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Add,Rel) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _v)
{
return _FOP(add_fetch, RELEASE, _p, _v);
}
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Sub,) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _v)
{
return _FOP(sub_fetch, ACQ_REL, _p, _v);
}
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Sub,Rx) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _v)
{
return _FOP(sub_fetch, RELAXED, _p, _v);
}
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Sub,Acq) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _v)
{
return _FOP(sub_fetch, ACQUIRE, _p, _v);
}
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Sub,Rel) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _v)
{
return _FOP(sub_fetch, RELEASE, _p, _v);
}
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Incr,) (INTERLOCKED_TYPE *_p)
{
return _FOP(fetch_add, ACQ_REL, _p, 1);
}
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Incr,Rx) (INTERLOCKED_TYPE *_p)
{
return _FOP(fetch_add, RELAXED, _p, 1);
}
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Incr,Acq) (INTERLOCKED_TYPE *_p)
{
return _FOP(fetch_add, ACQUIRE, _p, 1);
}
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Incr,Rel) (INTERLOCKED_TYPE *_p)
{
return _FOP(fetch_add, RELEASE, _p, 1);
}
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Decr,) (INTERLOCKED_TYPE *_p)
{
return _FOP(fetch_sub, ACQ_REL, _p, 1);
}
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Decr,Rx) (INTERLOCKED_TYPE *_p)
{
return _FOP(fetch_sub, RELAXED, _p, 1);
}
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Decr,Acq) (INTERLOCKED_TYPE *_p)
{
return _FOP(fetch_sub, ACQUIRE, _p, 1);
}
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Decr,Rel) (INTERLOCKED_TYPE *_p)
{
return _FOP(fetch_sub, RELEASE, _p, 1);
}
#endif /* INTERLOCKED_NO_ARIT */
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Xchng,) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _v)
{
return _FOP(exchange_n, ACQ_REL, _p, _v);
}
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Xchng,Rx) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _v)
{
return _FOP(exchange_n, RELAXED, _p, _v);
}
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Xchng,Acq) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _v)
{
return _FOP(exchange_n, ACQUIRE, _p, _v);
}
FORCE_INLINE INTERLOCKED_TYPE _FNAME(,Xchng,Rel) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _v)
{
return _FOP(exchange_n, RELEASE, _p, _v);
}
FORCE_INLINE Boolean _FNAME(,Cas,) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _e, INTERLOCKED_TYPE _v)
{
return _FCAS(FALSE, ACQ_REL, ACQUIRE, _p, &_e, _v);
}
FORCE_INLINE Boolean _FNAME(,Cas,Rx) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _e, INTERLOCKED_TYPE _v)
{
return _FCAS(FALSE, RELAXED, RELAXED, _p, &_e, _v);
}
FORCE_INLINE Boolean _FNAME(,Cas,Acq) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _e, INTERLOCKED_TYPE _v)
{
return _FCAS(FALSE, ACQUIRE, ACQUIRE, _p, &_e, _v);
}
FORCE_INLINE Boolean _FNAME(,Cas,Rel) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _e, INTERLOCKED_TYPE _v)
{
return _FCAS(FALSE, RELEASE, RELAXED, _p, &_e, _v);
}
FORCE_INLINE Boolean _FNAME(Wk,Cas,) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _e, INTERLOCKED_TYPE _v)
{
return _FCAS(TRUE, ACQ_REL, ACQUIRE, _p, &_e, _v);
}
FORCE_INLINE Boolean _FNAME(Wk,Cas,Rx) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _e, INTERLOCKED_TYPE _v)
{
return _FCAS(TRUE, RELAXED, RELAXED, _p, &_e, _v);
}
FORCE_INLINE Boolean _FNAME(Wk,Cas,Acq) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _e, INTERLOCKED_TYPE _v)
{
return _FCAS(TRUE, ACQUIRE, ACQUIRE, _p, &_e, _v);
}
FORCE_INLINE Boolean _FNAME(Wk,Xchng,Rel) (INTERLOCKED_TYPE *_p, INTERLOCKED_TYPE _e, INTERLOCKED_TYPE _v)
{
return _FCAS(TRUE, RELEASE, RELAXED, _p, &_e, _v);
}
#undef _PASTE
#undef _XPASTE
#undef _FNAME
#undef _FOP
#undef _FCAS

View File

178
lonetix/include/df/sys/ip.h Executable file
View File

@ -0,0 +1,178 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
/**
* \file sys/ip.h
*
* Internet Protocol (IP) definitions and types.
*
* \copyright The DoubleFourteen Code Forge (C) All Right Reserved
* \author Lorenzo Cogotti
*/
#ifndef DF_SYS_IP_H_
#define DF_SYS_IP_H_
#include "xpt.h"
/// Known Internet Protocol address family types enumeration.
typedef enum {
IP4, ///< Internet Protocol version 4
IP6 ///< Internet Protocol version 6
} IpType;
/// Internet Protocol version 4 (IPv4) address, big endian order.
typedef union {
Uint8 bytes[4]; ///< Address bytes representation
Uint16 words[2]; ///< Address as a pair of 16-bits words
Uint32 dword; ///< Address as a single 32-bits dword (big endian)
} Ipv4adr;
/// Size of an IPv4 address in bytes.
#define IPV4_SIZE 4
/// Bits inside an IPv4 address.
#define IPV4_WIDTH (IPV4_SIZE * 8)
STATIC_ASSERT(sizeof(Ipv4adr) == IPV4_SIZE, "Bad Ipv4adr size");
/// Size of a string to make an IPv4 address, **excluding** trailing `\0`.
#define IPV4_STRLEN 16
/// IPv4 wildcard address static initializer: `0.0.0.0`.
#define IPV4_ANY_INIT { { 0x00, 0x00, 0x00, 0x00 } }
/// IPv4 loopback address static initializer: `127.0.0.1`.
#define IPV4_LOOPBACK_INIT { { 0x7f, 0x00, 0x00, 0x01 } }
/// IPv4 broadcast address static initializer: `255.255.255.255`.
#define IPV4_BROADCAST_INIT { { 0xff, 0xff, 0xff, 0xff } }
/**
* \brief Convert `Ipv4adr` to its string representation.
*
* The destination buffer **is assumed to be large enough to store
* the resulting string**, a buffer of `IPV4_STRLEN + 1`
* chars is safe to use as the `dest` argument.
*
* \param [in] adr Address to be converted, must not be `NULL`
* \param [out] dest Destination storage for string representation, must not be `NULL`
*
* \return Pointer to the trailing `\0` `char` inside `dest`, useful
* for further string concatenation.
*/
char *Ipv4_AdrToString(const Ipv4adr *adr, char *dest);
/**
* \brief Convert an address from its string representation to `Ipv4adr`.
*
* \return `OK` if conversion was successful, `NG` if address string
* does not represent a valid IP.
*/
Judgement Ipv4_StringToAdr(const char *address, Ipv4adr *dest);
/// Compare IPv4 addresses for equality.
FORCE_INLINE Boolean Ipv4_Equal(const Ipv4adr *a, const Ipv4adr *b)
{
return a->dword == b->dword;
}
/// Internet Protocol version 6 address.
typedef union {
Uint8 bytes[16]; ///< Address as raw bytes
Uint16 words[8]; ///< Address as short words sequence
Uint32 dwords[4]; ///< Address as dwords sequence
} Ipv6adr;
/// Size of an IPv6 address in bytes.
#define IPV6_SIZE 16
/// Bits inside an IPv6 address.
#define IPV6_WIDTH (IPV6_SIZE * 8)
STATIC_ASSERT(sizeof(Ipv6adr) == IPV6_SIZE, "Bad Ipv6adr size");
/// Size of a string to make an IPv6 address, **excluding** trailing `\0`.
#define IPV6_STRLEN 46
/// Static initializer for an UNSPECIFIED Ipv6 address.
#define IPV6_UNSPEC_INIT { { \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 \
} }
/// Static initializer for a LOOPBACK Ipv6 address.
#define IPV6_LOOPBACK_INIT { { \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 \
} }
/// Test whether an IPv6 address represents a mapped IPv4 address.
#define IS_IPV6_V4MAPPED(v6) \
((v6)->dwords[0] == 0 && \
(v6)->dwords[1] == 0 && \
(v6)->dwords[2] == BE32(0xffff))
/// Test whether an IPv6 address is multicast.
#define IS_IPV6_MULTICAST(v6) ((v6)->bytes[0] == 0xff)
/**
* \brief Convert an IPv6 address to its string representation, destination
* storage should be `[IPV6_STRLEN + 1]`.
*
* \return Pointer to the trailing `\0` inside `dest`.
*/
char *Ipv6_AdrToString(const Ipv6adr *adr, char *dest);
/**
* \brief Convert IPv6 address string to `Ipv6adr`.
*
* \return `OK` on success, `NG` if `address` does not represent a valid IPv6 address.
*/
Judgement Ipv6_StringToAdr(const char *address, Ipv6adr *dest);
/// Compare two IPv6 addresses for equality.
FORCE_INLINE Boolean Ipv6_Equal(const Ipv6adr *a, const Ipv6adr *b)
{
return a->dwords[0] == b->dwords[0] && a->dwords[1] == b->dwords[1] &&
a->dwords[2] == b->dwords[2] && a->dwords[3] == b->dwords[3];
}
/// Generic IP address.
typedef struct {
IpType family; ///< Currently stored address family
union {
Uint8 bytes[IPV6_SIZE]; ///< Address as raw bytes, for convenient initialization
Ipv4adr v4; ///< IPv4 address, if `family == IP4`
Ipv6adr v6; ///< IPv6 address, if `family == IP6`
Uint32 dword; ///< As IPv4 single dword, for macro compat
Uint16 words[8]; ///< As IPv4/IPv6 word sequence, for macro compat
Uint32 dwords[4]; ///< As IPv6 dwords sequence, for macro compat
};
} Ipadr;
/**
* \brief Convert a generic IP address to its string representation.
*
* \note A destination string of length `IPV6_STRLEN + 1`
* is capable of storing an address string for any address family.
*/
char *Ip_AdrToString(const Ipadr *adr, char *dest);
/**
* \brief Convert IP string representation to `Ipadr`.
*
* \return `OK` on success, `NG` if `address` is not a valid IP address.
*/
Judgement Ip_StringToAdr(const char *address, Ipadr *dest);
/// Compare generic addresses for equality.
FORCE_INLINE Boolean Ip_Equal(const Ipadr *a, const Ipadr *b)
{
if (a->family != b->family)
return FALSE;
switch (a->family) {
case IP4: return Ipv4_Equal(&a->v4, &b->v4);
case IP6: return Ipv6_Equal(&a->v6, &b->v6);
default: UNREACHABLE; return FALSE;
}
}
#endif

154
lonetix/include/df/sys/sys.h Executable file
View File

@ -0,0 +1,154 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
/**
* \file sys/sys.h
*
* Miscellaneous system functionality.
*
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
* \author Lorenzo Cogotti
*/
#ifndef DF_SYS_ERR_H_
#define DF_SYS_ERR_H_
#include "srcloc.h"
#include <stdarg.h>
#ifdef _MSC_VER
// for Sys_WipeMemory()
#include <intrin.h>
#pragma intrinsic(_ReadWriteBarrier)
#endif
/**
* \typedef SysRet
* \brief Platform-specific error code for system operations.
*/
typedef int SysRet; // errno type
/**
* \brief Error status structure.
*
* Stores latest operation result and current error handling callback.
*/
typedef struct {
/// Latest operation result status.
SysRet code;
/**
* \brief Error handler callback.
*
* \param [in] code System error code
* \param [in] reason Human readable concise message providing context to error, never `NULL`
* \param [in] loc Source location where error occurred, `NULL` if unavailable
* \param [in] obj User defined additional data forwarded to callback unaltered
*/
void (*func)(SysRet code, const char *reason, Srcloc *loc, void *obj);
/// Additional user data to be forwarded to `func`.
void *obj;
} SysErrStat;
/**
* \brief Abort error handler callback.
*
* This error handler terminates execution abnormally,
* attempting to log an error message as accurate as possible using system
* specific facilities.
*
* If this handler is registered, execution shall terminate as soon as an
* exceptional error condition is encountered in the system layer.
*/
#define SYS_ERR_ABORT ((void (*)(SysRet, const char *, Srcloc *, void *)) -1)
/**
* \brief Ignoring error handler callback.
*
* If this handler is registered any system error is ignored.
*/
#define SYS_ERR_IGN ((void (*)(SysRet, const char *, Srcloc *, void *)) 0)
/**
* \brief Terminating error handler callback.
*
* Terminates execution providing sensible error message, it differs
* from `SYS_ERR_ABORT` in that no exceptional termination semantics is
* implied, but rather an unsuccessful event that caused immediate exit
* (no core dump or stack traces are left behind).
*/
#define SYS_ERR_QUIT ((void (*)(SysRet, const char *, Srcloc *, void *)) 1)
/**
* \brief Install a system error handler callback.
*
* Initially installed handler is `SYS_ERR_IGN`,
* thus any error is effectively ignored unless a new handler is installed.
*
* Once installed, the error callback is called immediately for every
* exceptional error condition encountered inside system layer.
*
* Error handlers are thread-local, thus different threads may implement
* appropriate error handling policy without interfering with each other.
*
* \param [in] func Error handler function
* \param [in] obj Custom user-provided object passed unaltered upon callback
*
* \see `SysErrStat` for callback documentation
*/
void Sys_SetErrFunc(void (*func)(SysRet, const char *, Srcloc *, void *), void *obj);
/**
* Retrieve the system error status.
*
* \param [out] stat Storage for returned error status, may be `NULL`
*
* \return Last operation result status.
*/
SysRet Sys_GetErrStat(SysErrStat *stat);
/**
* Trigger an out of memory error.
*
* @note Depending on the current error policy, execution may
* very well continue after call returns.
*/
#define Sys_OutOfMemory() _Sys_OutOfMemory(__FILE__, __func__, __LINE__, 0)
// NOTE: implementation detail, should always be called through `Sys_OutOfMemory()`.
NOINLINE void _Sys_OutOfMemory(const char *,
const char *,
unsigned long long,
unsigned);
/**
* \brief Zero-out `nbytes` bytes inside `data`, preventing compiler optimization.
*
* A compiler might optimize-out `memset()` or similar operations if `data`
* is never read again.
* This function ensures such operation is never optimized away, which
* may be useful to zero-out sensitive data.
*/
FORCE_INLINE void Sys_WipeMemory(volatile void *data, size_t nbytes)
{
#if defined(_MSC_VER) || defined(__GNUC__)
EXTERNC void *memset(void *, int, size_t);
memset((void *) data, 0, nbytes);
// Compiler fence
#ifdef _MSC_VER
_ReadWriteBarrier();
#else
__asm__ __volatile__ ("" : : : "memory");
#endif
#else
// Slow but portable
volatile Uint8 *p = (volatile Uint8 *) data;
while (nbytes--)
*p++ = 0x00;
#endif
}
/// Sleep *at least* for the specified amount of **milliseconds**.
void Sys_SleepMillis(Uint32 millis);
#endif

157
lonetix/include/df/sys/vt100.h Executable file
View File

@ -0,0 +1,157 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
/**
* \file sys/vt100.h
*
* VT100 compliant control code sequences.
*
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
* \author Lorenzo Cogotti
*/
#ifndef DF_SYS_VT100_H_
#define DF_SYS_VT100_H_
#ifndef STR
#define STR(x) #x
#endif
#ifndef XSTR
#define XSTR(x) STR(x)
#endif
/// VT100 escape character constant, prefixed to any command
#define VTESC "\x1b"
/// Operating System Command marker, immediately following ESC
#define VTOSC "]"
/// CSI marker, immediately following ESC
#define VTCSI "["
/// Enabling command suffix
#define VTENB "h"
/// Disabling command suffix
#define VTDIS "l"
/// Designate Character Set - DEC Line mode drawing
#define VTDCSLIN VTESC "(0"
/// Designate Character Set - US ASCII (default) mode
#define VTDCSCHR VTESC "(B"
/// Soft Terminal Reset (reset terminal to default state)
#define VTSRST VTESC VTCSI "!p"
/// Cursor blink command mnemonic
#define ATT160 "?12"
/// Text Cursor Enable Mode command mnemonic
#define DECTCEM "?25"
/// Start cursor blinking
#define VTBLKENB VTESC VTCSI ATT160 VTENB
/// Stop cursor blinking
#define VTBLKDIS VTESC VTCSI ATT160 VTDIS
/// Show cursor inside console
#define VTCURSHW VTESC VTCSI DECTCEM VTENB
/// Hide console cursor
#define VTCURHID VTESC VTCSI DECTCEM VTDIS
/// Console Screen Buffer command mnemonic
#define DECSCRB "?1049"
/// Switch to Alternate Screen buffer
#define VTALTSCR VTESC VTCSI DECSCRB VTENB
/// Switch to Main Screen buffer
#define VTMAINSCR VTESC VTCSI DECSCRB VTDIS
/// Set Graphic Rendition command mnemonic
#define SGR "m"
/// Set Graphics Rendition to `N` (N is any of the SGR constants)
#define VTSGR(n) VTESC VTCSI XSTR(n) SGR
/// Obtain the corresponding background color code from a foreground color
#define VT_TOBG(c) ((c) + 10)
/// Obtain the corresponding bold/emphasized variant from a foreground or background color
#define VT_TOBLD(c) ((c) + 60)
/// Reset graphics rendition to its default mode (both foreground and background)
#define VTDFLT 0
/// Enable bold text/emphasis
#define VTBLD 1
/// Disable bold text/emphasis
#define VTNOBLD 22
/// Enable text underline
#define VTUND 4
/// Disable text underline
#define VTNOUND 24
/// Invert foreground and background color
#define VTINV 7
/// Restore foreground and background to their normal value
#define VTNOINV 27
/// Black color code (foreground)
#define VTBLK 30
/// Red color code (foreground)
#define VTRED 31
/// Green color code (foreground)
#define VTGRN 32
/// Yellow color code (foreground)
#define VTYEL 33
/// Blue color code (foreground)
#define VTBLUE 34
/// Magenta color code (foreground)
#define VTMAGN 35
/// Cyan color code (foreground)
#define VTCYAN 36
/// White color code (foreground)
#define VTWHIT 37
/// Code to restore foreground color to its default value
#define VTFGDFLT 39
#define VTBGBLK 40
#define VTBGRED 41
#define VTBGGRN 42
#define VTBGYEL 43
#define VTBGBLUE 44
#define VTBGMAGN 45
#define VTBGCYAN 46
#define VTBGWHIT 47
#define VTBGDFLT 49
#define VTBLK_BLD 90
#define VTRED_BLD 91
#define VTGRN_BLD 92
#define VTYEL_BLD 93
#define VTBLUE_BLD 94
#define VTMAGN_BLD 95
#define VTCYAN_BLD 96
#define VTWHIT_BLD 97
#define VTBGBLK_BLD 100
#define VTBGRED_BLD 101
#define VTBGGRN_BLD 102
#define VTBGYEL_BLD 103
#define VTBGBLUE_BLD 104
#define VTBGMAGN_BLD 105
#define VTBGCYAN_BLD 106
#define VTBGWHIT_BLD 107
/// Erase in Display command mnemonic
#define ED "J"
/// Erase in Line command mnemonic
#define EL "K"
/// Erase in Display with command parameter `n`
#define VTED(n) VTESC VTCSI XSTR(n) ED
/// Erase in Line with command parameter `n`
#define VTEL(n) VTESC VTCSI XSTR(n) EL
/// Erase from cursor (inclusive) to end of display/line
#define VTCUR 0
/// Erase from the beginning of the line/display to end
#define VTSET 1
/// Erase everything in line/display
#define VTALL 2
#endif