#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "../include/mavka/prystriy.h"
#ifndef MAVKA_MALLOC_FN
#define MAVKA_MALLOC_FN malloc
#endif
#ifndef MAVKA_REALLOC_FN
#define MAVKA_REALLOC_FN realloc
#endif
#ifndef MAVKA_FREE_FN
#define MAVKA_FREE_FN free
#endif
static void print_color(PristriyMavkyWriteToStdoutColor color);
static char* do_readline(char* prefix, size_t prefix_size, size_t* out_len);
// ----------------------------
void* pristriy_mavky_malloc(size_t size) {
return MAVKA_MALLOC_FN(size);
}
void* pristriy_mavky_realloc(void* value, size_t new_size) {
return MAVKA_REALLOC_FN(value, new_size);
}
void pristriy_mavky_free(void* value) {
MAVKA_FREE_FN(value);
}
void pristriy_mavky_write_to_stdout(char* data, size_t size) {
fwrite(data, 1, size, stdout);
}
void pristriy_mavky_write_utf8_to_stdout(PristriyMavkyWriteToStdoutColor color,
char* data,
size_t size) {
print_color(color);
fwrite(data, 1, size, stdout);
print_color(PristriyMavkyColorReset);
}
double pristriy_mavky_double_pow(double value, double exp) {
return pow(value, exp);
}
double pristriy_mavky_double_sin(double value) {
return sin(value);
}
double pristriy_mavky_double_cos(double value) {
return cos(value);
}
double pristriy_mavky_double_tan(double value) {
return tan(value);
}
double pristriy_mavky_double_asin(double value) {
return asin(value);
}
double pristriy_mavky_double_acos(double value) {
return acos(value);
}
double pristriy_mavky_double_atan(double value) {
return atan(value);
}
double pristriy_mavky_double_abs(double value) {
return fabs(value);
}
double pristriy_mavky_double_exp(double value) {
return exp(value);
}
double pristriy_mavky_double_sqrt(double value) {
return sqrt(value);
}
double pristriy_mavky_double_ceil(double value) {
return ceil(value);
}
double pristriy_mavky_double_floor(double value) {
return floor(value);
}
double pristriy_mavky_double_round(double value) {
return round(value);
}
bool pristriy_mavky_uint64_to_str(size_t value,
char** data_out,
size_t* size_out) {
char buf[32];
int len = snprintf(buf, sizeof(buf), "%llu", (unsigned long long)value);
if (len < 0) {
return false;
}
*size_out = (size_t)len;
*data_out = (char*)pristriy_mavky_malloc(*size_out);
if (!*data_out) {
return false;
}
for (size_t і = 0; і < *size_out; і++) {
(*data_out)[і] = buf[і];
}
return true;
}
bool pristriy_mavky_int64_to_str(ssize_t value,
char** data_out,
size_t* size_out) {
char buf[32];
int len = snprintf(buf, sizeof(buf), "%lld", (long long)value);
if (len < 0) {
return false;
}
*size_out = (size_t)len;
*data_out = (char*)pristriy_mavky_malloc(*size_out);
if (!*data_out) {
return false;
}
for (size_t і = 0; і < *size_out; і++) {
(*data_out)[і] = buf[і];
}
return true;
}
// 123.0 => "123"
// 123.456 => "123.456"
// -0.00123 => "-0.00123"
// 1.2e+30 => "1.2" 30
// 1.2e-30 => "1.2" -30
bool pristriy_mavky_double_to_str(double value,
char** data_out,
size_t* size_out,
ssize_t* exp_size_out) {
char buf[64];
int len;
if (isnan(value)) {
char nan_str[] = "невизначеність";
*size_out = sizeof(nan_str) - 1;
*data_out = (char*)pristriy_mavky_malloc(*size_out);
if (!*data_out)
return false;
memcpy(*data_out, nan_str, *size_out);
*exp_size_out = 0;
return true;
}
if (isinf(value)) {
char* inf_str = value > 0 ? "нескінченність" : "-нескінченність";
*size_out = value > 0 ? sizeof("нескінченність") - 1
: sizeof("-нескінченність") - 1;
*data_out = (char*)pristriy_mavky_malloc(*size_out);
if (!*data_out)
return false;
memcpy(*data_out, inf_str, *size_out);
*exp_size_out = 0;
return true;
}
// Знаходимо найкоротше представлення, яке round-trips
// Пробуємо від 15 до 17 цифр точності
for (int precision = 15; precision <= 17; precision++) {
len = snprintf(buf, sizeof(buf), "%.*g", precision, value);
if (len < 0 || len >= (int)sizeof(buf)) {
continue;
}
// Перевіряємо чи round-trip працює
double parsed = strtod(buf, NULL);
if (parsed == value) {
break;
}
}
if (len < 0 || len >= (int)sizeof(buf)) {
return false;
}
char* e_pos = strchr(buf, 'e');
if (e_pos != NULL) {
*exp_size_out = (ssize_t)strtol(e_pos + 1, NULL, 10);
size_t mantissa_len = (size_t)(e_pos - buf);
*size_out = mantissa_len;
*data_out = (char*)pristriy_mavky_malloc(*size_out);
if (!*data_out)
return false;
for (size_t і = 0; і < mantissa_len; і++) {
(*data_out)[і] = buf[і];
}
} else {
*exp_size_out = 0;
*size_out = (size_t)len;
*data_out = (char*)pristriy_mavky_malloc(*size_out);
if (!*data_out)
return false;
for (size_t і = 0; і < *size_out; і++) {
(*data_out)[і] = buf[і];
}
}
return true;
}
bool pristriy_mavky_str_to_double(char* data, size_t size, double* out) {
char* str = (char*)pristriy_mavky_malloc(size + 1);
size_t len = 0;
for (size_t і = 0; і < size; і++) {
unsigned char c = (unsigned char)data[і];
if (c == 0xD0 || c == 0xD1) {
if (і + 1 < size) {
unsigned char c2 = (unsigned char)data[і + 1];
if (c == 0xD0 && c2 == 0xB5) {
str[len++] = 'e';
і++;
continue;
}
if (c == 0xD0 && c2 == 0x95) {
str[len++] = 'E';
і++;
continue;
}
}
}
str[len++] = (char)c;
}
str[len] = '\0';
char* endptr;
*out = strtod(str, &endptr);
if (str == endptr) {
pristriy_mavky_free(str);
return false;
} else if (errno == ERANGE) {
pristriy_mavky_free(str);
return false;
} else if (*endptr != '\0') {
pristriy_mavky_free(str);
return false;
}
pristriy_mavky_free(str);
return true;
}
bool pristriy_mavky_get_cwd(char** data_out, size_t* size_out) {
char* cwd = getcwd(NULL, 0);
if (cwd == NULL) {
return false;
}
*size_out = strlen(cwd);
*data_out = (char*)pristriy_mavky_malloc(*size_out);
if (!*data_out) {
pristriy_mavky_free(cwd);
return false;
}
memcpy(*data_out, cwd, *size_out);
pristriy_mavky_free(cwd);
return true;
}
bool pristriy_mavky_get_absolute_path(char* path_data,
size_t path_size,
char** data_out,
size_t* size_out) {
char* pathstr = (char*)pristriy_mavky_malloc(path_size + 1);
for (size_t і = 0; і < path_size; і++) {
pathstr[і] = (char)path_data[і];
}
pathstr[path_size] = '\0';
char* abspath = realpath(pathstr, NULL);
pristriy_mavky_free(pathstr);
if (abspath == NULL) {
return false;
}
size_t len = strlen(abspath);
*size_out = len;
*data_out = (char*)pristriy_mavky_malloc(len);
if (!*data_out) {
pristriy_mavky_free(abspath);
return false;
}
for (size_t і = 0; і < len; і++) {
(*data_out)[і] = abspath[і];
}
pristriy_mavky_free(abspath);
return true;
}
bool pristriy_mavky_check_if_file_exists(char* path_data, size_t path_size) {
char* pathstr = (char*)pristriy_mavky_malloc(path_size + 1);
for (size_t і = 0; і < path_size; і++) {
pathstr[і] = (char)path_data[і];
}
pathstr[path_size] = '\0';
struct stat statbuf;
bool res = false;
if (stat(pathstr, &statbuf) == 0) {
if (S_ISREG(statbuf.st_mode)) {
res = true;
}
}
pristriy_mavky_free(pathstr);
return res;
}
bool pristriy_mavky_read_file(char* path_data,
size_t path_size,
char** data_out,
size_t* size_out) {
char* pathstr = (char*)pristriy_mavky_malloc(path_size + 1);
for (size_t і = 0; і < path_size; і++) {
pathstr[і] = (char)path_data[і];
}
pathstr[path_size] = '\0';
FILE* f = fopen(pathstr, "rb");
pristriy_mavky_free(pathstr);
if (!f) {
return false;
}
fseek(f, 0, SEEK_END);
*size_out = ftell(f);
fseek(f, 0, SEEK_SET);
*data_out = (char*)pristriy_mavky_malloc(*size_out);
if (!*data_out) {
fclose(f);
return false;
}
fread(*data_out, 1, *size_out, f);
fclose(f);
return true;
}
bool pristriy_mavky_read_input_async(
char* prefix_data,
size_t prefix_size,
void (*callback)(char* data, size_t data_size, bool eof, void* arg),
void* arg,
bool allow_history) {
size_t len;
char* data = do_readline(prefix_data, prefix_size, &len);
if (!data) {
callback(data, len, true, arg);
return true;
}
callback(data, len, false, arg);
return true;
}
#ifndef MAVKA_NO_DLFCN
#include <dlfcn.h>
void* pristriy_mavky_dlopen(char* path_data, size_t path_size, int* err_out) {
(void)path_size;
dlerror();
void* dl = dlopen(path_data, RTLD_LAZY);
if (!dl) {
*err_out = -1;
}
return dl;
}
void* pristriy_mavky_dlsym(void* dl,
char* name_data,
size_t name_size,
int* err_out) {
(void)name_size;
dlerror();
void* dls = dlsym(dl, name_data);
const char* err = dlerror();
if (err) {
*err_out = -1;
return NULL;
}
return dls;
}
int pristriy_mavky_dlclose(void* dl) {
return dlclose(dl);
}
#endif
void pristriy_mavky_exit(int code) {
exit(code);
}
// ----------------------------
static void print_color(PristriyMavkyWriteToStdoutColor color) {
if (color == PristriyMavkyColorReset) {
printf("\033[0m");
}
if (color == PristriyMavkyColorRed) {
printf("\033[0;31m");
}
if (color == PristriyMavkyColorGreen) {
printf("\033[0;32m");
}
if (color == PristriyMavkyColorBlue) {
printf("\033[0;34m");
}
if (color == PristriyMavkyColorYellow) {
printf("\033[0;33m");
}
}
#ifdef PROGRAM_USE_READLINE
#include <readline/readline.h>
static char* do_readline(char* prefix, size_t prefix_size, size_t* out_len) {
char* data = readline(prefix);
if (!data) {
return NULL;
}
*out_len = strlen(data);
return data;
}
#else
static char* do_readline(char* prefix, size_t prefix_size, size_t* out_len) {
pristriy_mavky_write_utf8_to_stdout(PristriyMavkyColorReset, prefix,
prefix_size);
size_t cap = 128;
size_t len = 0;
char* buf = (char*)pristriy_mavky_malloc(cap);
if (!buf)
return NULL;
int c;
while ((c = getchar()) != EOF) {
if (c == '\n')
break; // stop, but DON'T store '\n'
if (len + 1 >= cap) {
cap *= 2;
char* tmp = pristriy_mavky_realloc(buf, cap);
if (!tmp) {
pristriy_mavky_free(buf);
return NULL;
}
buf = tmp;
}
buf[len++] = c;
}
// If nothing read and EOF, return NULL
if (len == 0 && c == EOF) {
pristriy_mavky_free(buf);
return NULL;
}
buf[len] = '\0';
if (out_len)
*out_len = len;
return buf;
}
#endif