vessel/core/def.c
Arija A. 4f0bf80e5f
refact: Remove mem.h
Signed-off-by: Arija A. <ari@ari.lt>
2025-06-21 23:43:31 +03:00

892 lines
18 KiB
C

#include "include/conf.h"
/* TODO: Remove _POSIX_C_SOURCE */
#ifndef _POSIX_C_SOURCE
# define _POSIX_C_SOURCE 199309L
#endif /* _POSIX_C_SOURCE */
#include "include/def.h"
#include <ctype.h>
#include <string.h>
#include <time.h>
#ifdef VS_NO_GETRANDOM
# include "include/file.h"
# include "include/vessel.h"
static File urandom_f;
static bool urandom_initialized = false;
static void get_rand_bytes_close_fd(void) {
if (urandom_initialized) {
flog_info(&vessel_lg, "Closing /dev/urandom file: %ju.", File_identity(&urandom_f));
File_destroy(&urandom_f);
}
}
#else
# include <sys/random.h>
#endif /* VS_NO_GETRANDOM */
bool vs_bool_xor(bool first, bool second) { return first ^ second; }
char *vs_dupnstr(const char *src, size_t len) {
if (!src) {
return NULL;
}
char *dst = VS_MALLOC((len + 1) * sizeof(*dst));
if (dst) {
memcpy(dst, src, len);
dst[len] = '\0';
}
return dst;
}
char *vs_dupstr(const char *src) {
if (!src) {
return NULL;
}
const size_t len = strlen(src);
char *dst = VS_MALLOC((len + 1) * sizeof(*dst));
if (dst) {
memcpy(dst, src, len);
dst[len] = '\0';
}
return dst;
}
void *vs_dupmem(const void *src, size_t len) {
if (!src || 0 == len) {
return NULL;
}
void *dst = VS_MALLOC(len);
if (dst) {
memcpy(dst, src, len);
}
return dst;
}
wchar_t *vs_wdupnstr(const wchar_t *src, size_t len) {
if (!src) {
return NULL;
}
wchar_t *dst = VS_MALLOC((len + 1) * sizeof(*dst));
if (dst) {
memcpy(dst, src, len);
dst[len] = L'\0';
}
return dst;
}
wchar_t *vs_wdupstr(const wchar_t *src) {
if (!src) {
return NULL;
}
size_t len = wcslen(src);
wchar_t *dst = VS_MALLOC((len + 1) * sizeof(*dst));
if (dst) {
memcpy(dst, src, len * sizeof(*dst));
dst[len] = L'\0';
}
return dst;
}
char *vs_lowstr(char *src) {
if (src) {
while (*src) {
*src = (char)tolower((unsigned char)*src);
++src;
}
}
return src;
}
char *vs_lownstr(char *src, size_t len) {
if (src) {
for (size_t idx = 0; idx < len && src[idx] != '\0'; ++idx) {
src[idx] = (char)tolower((unsigned char)src[idx]);
}
}
return src;
}
char *vs_uppstr(char *src) {
if (!src) {
return NULL;
}
while (*src) {
*src = (char)toupper((unsigned char)*src);
++src;
}
return src;
}
char *vs_uppnstr(char *src, size_t len) {
if (src) {
for (size_t idx = 0; idx < len && src[idx] != '\0'; ++idx) {
src[idx] = (char)toupper((unsigned char)src[idx]);
}
}
return src;
}
bool vs_startstr(const char *src, const char *prefix, bool sensitive) {
if (!src || !prefix) {
return false;
}
const size_t prefix_len = strlen(prefix);
if (prefix_len > strlen(src)) {
return false;
}
for (size_t idx = 0; idx < prefix_len; ++idx) {
if (sensitive) {
if (src[idx] != prefix[idx]) {
return false;
}
} else {
if (tolower(src[idx]) != tolower(prefix[idx])) {
return false;
}
}
}
return true;
}
size_t vs_get_rand_bytes(void *buf, size_t buflen) {
#ifdef VS_NO_GETRANDOM
if (!urandom_initialized) {
if (!File_init(&urandom_f, NULL)) {
return false;
}
if (!File_open(&urandom_f, "/dev/urandom", FILEF_RD, FILEM_ALL)) {
File_destroy(&urandom_f);
return false;
}
atexit(get_rand_bytes_close_fd);
urandom_initialized = true;
}
return File_read(&urandom_f, buf, buflen);
#else
const ssize_t count = getrandom(buf, buflen, 0);
return count < 1 ? 0 : (size_t)count;
#endif /* NO_GETRANDOM */
}
uint64_t vs_get_rand(void) {
uint64_t num = (uint64_t)14913935173710576959ULL; /* random prime number as a fallback */
vs_get_rand_bytes(&num, sizeof(num));
return num;
}
void vs_secsleep(double sleep_s) {
struct timespec request;
request.tv_sec = (time_t)sleep_s;
request.tv_nsec = (long)((sleep_s - (double)request.tv_sec) * 1e9);
nanosleep(&request, NULL);
}
uint64_t vs_hex2u64(const char *src) {
if (!src || !*src) {
return 0;
}
uint64_t result = 0;
while (*src) {
uint8_t digit = 0;
if (*src >= '0' && *src <= '9') {
digit = (uint8_t)*src - '0';
} else if (*src >= 'a' && *src <= 'f') {
digit = 10 + (uint8_t)(*src - 'a');
} else if (*src >= 'A' && *src <= 'F') {
digit = 10 + (uint8_t)(*src - 'A');
} else {
break;
}
if (result > (UINT64_MAX >> (uint64_t)4)) {
return UINT64_MAX;
}
result = (result << (uint64_t)4) | digit;
++src;
}
return result;
}
uint64_t vs_hexn2u64(const char *src, size_t len) {
if (!src || !len) {
return 0;
}
uint64_t result = 0;
while (len--) {
uint8_t digit = 0;
if (*src >= '0' && *src <= '9') {
digit = (uint8_t)*src - '0';
} else if (*src >= 'a' && *src <= 'f') {
digit = 10 + (uint8_t)(*src - 'a');
} else if (*src >= 'A' && *src <= 'F') {
digit = 10 + (uint8_t)(*src - 'A');
} else {
break;
}
if (result > (UINT64_MAX >> (uint64_t)4)) {
return UINT64_MAX;
}
result = (result << (uint64_t)4) | digit;
++src;
}
return result;
}
size_t vs_hex2usize(const char *src) {
if (!src || !*src) {
return 0;
}
size_t result = 0;
while (*src) {
uint8_t digit = 0;
if (*src >= '0' && *src <= '9') {
digit = (uint8_t)*src - '0';
} else if (*src >= 'a' && *src <= 'f') {
digit = 10 + (uint8_t)(*src - 'a');
} else if (*src >= 'A' && *src <= 'F') {
digit = 10 + (uint8_t)(*src - 'A');
} else {
break;
}
if (result > (SIZE_MAX >> (size_t)4)) {
return SIZE_MAX;
}
result = (result << (size_t)4) | digit;
++src;
}
return result;
}
size_t vs_hexn2usize(const char *src, size_t len) {
if (!src || !len) {
return 0;
}
size_t result = 0;
while (len--) {
uint8_t digit = 0;
if (*src >= '0' && *src <= '9') {
digit = (uint8_t)*src - '0';
} else if (*src >= 'a' && *src <= 'f') {
digit = 10 + (uint8_t)(*src - 'a');
} else if (*src >= 'A' && *src <= 'F') {
digit = 10 + (uint8_t)(*src - 'A');
} else {
break;
}
if (result > (SIZE_MAX >> (size_t)4)) {
return SIZE_MAX;
}
result = (result << (size_t)4) | digit;
++src;
}
return result;
}
uint64_t vs_str2u64(const char *src) {
if (!src || !*src) {
return 0;
}
uint64_t result = 0;
while (*src >= '0' && *src <= '9') {
uint64_t digit = (uint64_t)(*src - '0');
if (result > (UINT64_MAX - digit) / 10) {
return UINT64_MAX;
}
result = (result * 10) + digit;
++src;
}
return result;
}
uint64_t vs_strn2u64(const char *src, size_t len) {
if (!src || !len) {
return 0;
}
uint64_t result = 0;
while (len-- && *src >= '0' && *src <= '9') {
uint64_t digit = (uint64_t)(*src - '0');
if (result > (UINT64_MAX - digit) / 10) {
return UINT64_MAX;
}
result = (result * 10) + digit;
++src;
}
return result;
}
size_t vs_str2usize(const char *src) {
if (!src || !*src) {
return 0;
}
size_t result = 0;
while (*src >= '0' && *src <= '9') {
size_t digit = (size_t)(*src - '0');
if (result > (SIZE_MAX - digit) / 10) {
return SIZE_MAX;
}
result = (result * 10) + digit;
++src;
}
return result;
}
size_t vs_strn2usize(const char *src, size_t len) {
if (!src || !len) {
return 0;
}
size_t result = 0;
while (len-- && *src >= '0' && *src <= '9') {
size_t digit = (size_t)(*src - '0');
if (result > (SIZE_MAX - digit) / 10) {
return SIZE_MAX;
}
result = (result * 10) + digit;
++src;
}
return result;
}
uint16_t vs_str2u16(const char *src) {
if (!src || !*src) {
return 0;
}
uint16_t result = 0;
while (*src >= '0' && *src <= '9') {
uint16_t digit = (uint16_t)(*src - '0');
if (result > (UINT16_MAX - digit) / 10) {
return UINT16_MAX;
}
result = (uint16_t)((result * 10) + digit);
++src;
}
return result;
}
uint16_t vs_strn2u16(const char *src, size_t len) {
if (!src || !len) {
return 0;
}
uint16_t result = 0;
while (len-- && *src >= '0' && *src <= '9') {
uint16_t digit = (uint16_t)(*src - '0');
if (result > (UINT16_MAX - digit) / 10) {
return UINT16_MAX;
}
result = (uint16_t)((result * 10) + digit);
++src;
}
return result;
}
intmax_t vs_str2max(const char *src) {
if (!src || !*src) {
return 0;
}
int sign = 1;
if (*src == '-') {
sign = -1;
++src;
} else if (*src == '+') {
++src;
}
intmax_t result = 0;
while (*src >= '0' && *src <= '9') {
intmax_t digit = (intmax_t)(*src - '0');
if (sign == 1 && result > (INTMAX_MAX - digit) / 10) {
return INTMAX_MAX;
}
if (sign == -1 && result > (-(INTMAX_MIN + digit)) / 10) {
return INTMAX_MIN;
}
result = (result * 10) + digit;
++src;
}
return result * sign;
}
intmax_t vs_strn2max(const char *src, size_t len) {
if (!src || !len) {
return 0;
}
int sign = 1;
if (*src == '-' && len > 1) {
sign = -1;
++src;
--len;
} else if (*src == '+' && len > 1) {
++src;
--len;
}
intmax_t result = 0;
while (len-- && *src >= '0' && *src <= '9') {
intmax_t digit = *src - '0';
if (sign == 1 && result > (INTMAX_MAX - digit) / 10) {
return INTMAX_MAX;
}
if (sign == -1 && result > (-(INTMAX_MIN + digit)) / 10) {
return INTMAX_MIN;
}
result = (result * 10) + digit;
++src;
}
return result * sign;
}
char *vs_escstrncpy(char *dest, const char *src, size_t len) {
if (!dest || !src || 0 == len) {
return NULL;
}
size_t idx = 0;
bool literal_next = false;
while (idx < len && *src) {
if (literal_next) {
dest[idx++] = *src;
literal_next = false;
} else if (*src == '\\') {
literal_next = true;
} else {
dest[idx++] = *src;
}
++src;
}
if (idx < len) {
dest[idx] = '\0';
}
return dest;
}
char *vs_escstrcpy(char *dest, const char *src) {
if (!dest || !src) {
return NULL;
}
size_t idx = 0;
bool literal_next = false;
while (*src) {
if (literal_next) {
dest[idx++] = *src;
literal_next = false;
} else if (*src == '\\') {
literal_next = true;
} else {
dest[idx++] = *src;
}
++src;
}
dest[idx] = '\0';
return dest;
}
char *vs_strsafe(char *str, const char *allowlist, size_t allowlist_size, bool allow_uppercase) {
if (!str) {
return NULL;
}
char *write_ptr = str;
for (char *read_ptr = str; *read_ptr; ++read_ptr) {
if (!allow_uppercase && isupper(*read_ptr)) {
++read_ptr;
continue;
}
if (isalnum(*read_ptr)) {
*write_ptr++ = *read_ptr;
} else {
if (!allowlist || allowlist_size == 0) {
continue;
}
for (uint64_t idx = 0; idx < allowlist_size; ++idx) {
if (*read_ptr == allowlist[idx]) {
*write_ptr++ = *read_ptr;
break;
}
}
}
}
*write_ptr = '\0';
return str;
}
bool vs_strissafe(const char *str,
const char *allowlist,
size_t allowlist_size,
bool allow_uppercase) {
if (!str) {
return false;
}
for (const char *ptr = str; *ptr; ++ptr) {
if (!allow_uppercase && isupper(*ptr)) {
return false;
}
if (isalnum(*ptr)) {
continue;
}
bool found_in_allowlist = false;
for (size_t idx = 0; idx < allowlist_size; ++idx) {
if (*ptr == allowlist[idx]) {
found_in_allowlist = true;
break;
}
}
if (!found_in_allowlist) {
return false;
}
}
return true;
}
char *vs_strnsafe(char *str, size_t len, const char *allowlist, size_t allowlist_size) {
if (!str || len == 0) {
return NULL;
}
char *write_ptr = str;
size_t chars_written = 0;
for (const char *read_ptr = str; *read_ptr && chars_written < len - 1; ++read_ptr) {
if (isalnum(*read_ptr)) {
*write_ptr++ = *read_ptr;
chars_written++;
} else {
if (!allowlist || allowlist_size == 0) {
continue;
}
for (uint64_t idx = 0; idx < allowlist_size; ++idx) {
if (*read_ptr == allowlist[idx]) {
*write_ptr++ = *read_ptr;
chars_written++;
break;
}
}
}
}
*write_ptr = '\0';
return str;
}
bool vs_strnissafe(const char *str, size_t len, const char *allowlist, size_t allowlist_size) {
if (!str || len == 0) {
return false;
}
size_t chars_checked = 0;
for (const char *ptr = str; *ptr && chars_checked < len; ++ptr, ++chars_checked) {
if (isalnum(*ptr)) {
continue;
}
bool found_in_allowlist = false;
for (size_t idx = 0; idx < allowlist_size; ++idx) {
if (*ptr == allowlist[idx]) {
found_in_allowlist = true;
break;
}
}
if (!found_in_allowlist) {
return false;
}
}
return true;
}
bool vs_strnintonly(const char *str, size_t len) {
if (!str || len == 0) {
return false;
}
const char *end = str + len;
while (str < end && *str == ' ') {
++str;
}
if (str < end && (*str == '+' || *str == '-')) {
++str;
}
const char *start_digits = str;
while (str < end && *str >= '0' && *str <= '9') {
++str;
}
if (str == start_digits) {
return false;
}
while (str < end && *str == ' ') {
++str;
}
return str == end;
}
bool vs_strintonly(const char *str) {
if (!str || !*str) {
return false;
}
while (*str == ' ') {
++str;
}
if (*str == '+' || *str == '-') {
++str;
}
const char *start_digits = str;
while (*str >= '0' && *str <= '9') {
++str;
}
if (str == start_digits) {
return false;
}
while (*str == ' ') {
++str;
}
return *str == '\0';
}
double vs_strn2double(const char *str, size_t len, bool frac_required) {
if (!str || len == 0) {
return 0.0;
}
double sign = 1.0;
double result = 0.0;
double fraction = 1.0;
const char *ptr = str;
const char *end = str + len;
bool has_frac = false;
if (*ptr == '-') {
sign = -1.0;
++ptr;
} else if (*ptr == '+') {
++ptr;
}
while (*ptr >= '0' && *ptr <= '9' && ptr < end) {
result = (result * 10) + (*ptr - '0');
++ptr;
}
if (*ptr == '.' && ptr < end) {
++ptr;
has_frac = true;
} else if (!has_frac && frac_required) {
return 0.0;
}
while (has_frac && *ptr >= '0' && *ptr <= '9' && ptr < end) {
fraction /= 10.0;
result += (*ptr - '0') * fraction;
++ptr;
}
return ptr == end ? result * sign : 0.0;
}
double vs_str2double(const char *str, bool frac_required) {
if (!str || !*str) {
return 0.0;
}
double sign = 1.0;
double result = 0.0;
double fraction = 1.0;
const char *ptr = str;
bool has_frac = false;
if (*ptr == '-') {
sign = -1.0;
++ptr;
} else if (*ptr == '+') {
++ptr;
}
while (*ptr >= '0' && *ptr <= '9') {
result = (result * 10) + (*ptr - '0');
++ptr;
}
if (*ptr == '.') {
++ptr;
has_frac = true;
} else if (frac_required) {
return 0.0;
}
while (has_frac && *ptr >= '0' && *ptr <= '9') {
fraction /= 10.0;
result += (*ptr - '0') * fraction;
++ptr;
}
while (*ptr == ' ') {
++ptr;
}
return *ptr == '\0' ? result * sign : 0.0;
}
unsigned long vs_double_mod(double divident, double divisor) {
if (divisor < VS_DNULL) {
abort();
}
return (unsigned long)divident -
(((unsigned long)(divident / divisor)) * (unsigned long)divisor);
}
bool vs_strip_spaces(const char **start, const char **end) {
if (!start || !*start || !end || !*end) {
return false;
}
if (*start > *end) {
return false;
}
while (*start <= *end && **start == ' ') {
++*start;
}
while (*end >= *start && *(*end - 1) == ' ') {
--*end;
}
return *end >= *start;
}