#include <libgen.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mavka/prystriy.h"
КористувацькийПристрійМавкиЧитатиКД користувацький_пристрій_мавки_читати_кд;
extern void змінити_користувацький_пристрій_мавки_читати_кд(
КористувацькийПристрійМавкиЧитатиКД нова_функція) {
користувацький_пристрій_мавки_читати_кд = нова_функція;
}
extern логічне пристрій_мавки_отримати_версію(природне* вихід_розміру,
п8** вихід_даних) {
char* версія_ю8 = MAVKA_VERSION;
природне позиція_помилки;
if (пристрій_мавки_перекодувати_ю8_в_кд(strlen(версія_ю8), (п8*)версія_ю8,
вихід_розміру, вихід_даних,
&позиція_помилки)) {
return true;
}
return false;
}
extern void пристрій_мавки_вивести_формат(природне значення) {
if (значення == ФОчистити) {
printf("\033[0m");
}
if (значення == ФКолірТекстуЧервоний) {
printf("\033[0;31m");
}
if (значення == ФКолірТекстуЗелений) {
printf("\033[0;32m");
}
if (значення == ФКолірТекстуСиній) {
printf("\033[0;34m");
}
if (значення == ФКолірТекстуЖовтий) {
printf("\033[0;33m");
}
}
extern void пристрій_мавки_вивести_сирі_дані(природне розмір, п8* дані) {
fwrite(дані, 1, розмір, stdout);
}
extern void пристрій_мавки_вивести_кд(природне розмір, п8* дані) {
природне розмір_ю8;
п8* дані_ю8;
природне позиція_помилки;
if (пристрій_мавки_перекодувати_кд_в_ю8(розмір, дані, &розмір_ю8, &дані_ю8,
&позиція_помилки)) {
fwrite(дані_ю8, 1, розмір_ю8, stdout);
free(дані_ю8);
} else {
printf("помилка виводу кд\n");
}
}
extern void пристрій_мавки_надрукувати_кд(природне розмір, п8* дані) {
природне розмір_ю8;
п8* дані_ю8;
природне позиція_помилки;
if (пристрій_мавки_перекодувати_кд_в_ю8(розмір, дані, &розмір_ю8, &дані_ю8,
&позиція_помилки)) {
fwrite(дані_ю8, 1, розмір_ю8, stdout);
putchar('\n');
free(дані_ю8);
} else {
printf("помилка друку кд\n");
}
}
extern void пристрій_мавки_вивести_шлях(природне розмір, п8* дані) {
fwrite(дані, 1, розмір, stdout);
}
extern void пристрій_мавки_надрукувати_шлях(природне розмір, п8* дані) {
fwrite(дані, 1, розмір, stdout);
putchar('\n');
}
extern void пристрій_мавки_вивести_ю8(природне розмір, п8* дані) {
fwrite(дані, 1, розмір, stdout);
}
extern void пристрій_мавки_надрукувати_ю8(природне розмір, п8* дані) {
fwrite(дані, 1, розмір, stdout);
putchar('\n');
}
extern адреса пристрій_мавки_виділити_сиру_памʼять(природне розмір) {
return (адреса)malloc(розмір);
}
extern адреса пристрій_мавки_перевиділити_сиру_памʼять(адреса значення,
природне новий_розмір) {
return (адреса)realloc(значення, новий_розмір);
}
extern void пристрій_мавки_звільнити_сиру_памʼять(адреса значення) {
free(значення);
}
extern void пристрій_мавки_вийти(ц32 код_виходу) {
exit(код_виходу);
}
extern логічне пристрій_мавки_прочитати_файл(природне розмір_шляху,
п8* дані_шляху,
природне* вихід_розміру,
п8** вихід_даних) {
char* шлях_рядок = (char*)malloc(розмір_шляху + 1);
for (природне і = 0; і < розмір_шляху; і++) {
шлях_рядок[і] = (char)дані_шляху[і];
}
шлях_рядок[розмір_шляху] = '\0';
FILE* файл = fopen(шлях_рядок, "rb");
free(шлях_рядок);
if (!файл) {
return false;
}
fseek(файл, 0, SEEK_END);
*вихід_розміру = ftell(файл);
fseek(файл, 0, SEEK_SET);
*вихід_даних = (п8*)malloc(*вихід_розміру);
if (!*вихід_даних) {
fclose(файл);
return false;
}
fread(*вихід_даних, 1, *вихід_розміру, файл);
fclose(файл);
return true;
}
логічне перетворити_п64_в_ю8(п64 значення,
природне* вихід_розміру,
п8** вихід_даних) {
char буфер[32];
int довжина =
snprintf(буфер, sizeof(буфер), "%llu", (unsigned long long)значення);
if (довжина < 0) {
return false;
}
*вихід_розміру = (природне)довжина;
*вихід_даних = (п8*)malloc(*вихід_розміру);
if (!*вихід_даних) {
return false;
}
for (природне і = 0; і < *вихід_розміру; і++) {
(*вихід_даних)[і] = (п8)буфер[і];
}
return true;
}
логічне перетворити_ц64_в_ю8(ц64 значення,
природне* вихід_розміру,
п8** вихід_даних) {
char буфер[32];
int довжина = snprintf(буфер, sizeof(буфер), "%lld", (long long)значення);
if (довжина < 0) {
return false;
}
*вихід_розміру = (природне)довжина;
*вихід_даних = (п8*)malloc(*вихід_розміру);
if (!*вихід_даних) {
return false;
}
for (природне і = 0; і < *вихід_розміру; і++) {
(*вихід_даних)[і] = (п8)буфер[і];
}
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
логічне перетворити_р64_в_ю8(р64 значення,
природне* вихід_розміру,
п8** вихід_даних,
ціле* вихід_розміру_експоненти) {
char буфер[64];
int довжина;
if (isnan(значення)) {
char nan_str[] = "невизначеність";
*вихід_розміру = sizeof(nan_str) - 1;
*вихід_даних = (п8*)malloc(*вихід_розміру);
if (!*вихід_даних)
return false;
memcpy(*вихід_даних, nan_str, *вихід_розміру);
*вихід_розміру_експоненти = 0;
return true;
}
if (isinf(значення)) {
char* inf_str = значення > 0 ? "нескінченність" : "-нескінченність";
*вихід_розміру = значення > 0 ? sizeof("нескінченність") - 1
: sizeof("-нескінченність") - 1;
*вихід_даних = (п8*)malloc(*вихід_розміру);
if (!*вихід_даних)
return false;
memcpy(*вихід_даних, inf_str, *вихід_розміру);
*вихід_розміру_експоненти = 0;
return true;
}
// Знаходимо найкоротше представлення, яке round-trips
// Пробуємо від 15 до 17 цифр точності
for (int precision = 15; precision <= 17; precision++) {
довжина = snprintf(буфер, sizeof(буфер), "%.*g", precision, значення);
if (довжина < 0 || довжина >= (int)sizeof(буфер)) {
continue;
}
// Перевіряємо чи round-trip працює
р64 parsed = strtod(буфер, NULL);
if (parsed == значення) {
break;
}
}
if (довжина < 0 || довжина >= (int)sizeof(буфер)) {
return false;
}
char* e_pos = strchr(буфер, 'e');
if (e_pos != NULL) {
*вихід_розміру_експоненти = (ціле)strtol(e_pos + 1, NULL, 10);
природне довжина_мантиси = (природне)(e_pos - буфер);
*вихід_розміру = довжина_мантиси;
*вихід_даних = (п8*)malloc(*вихід_розміру);
if (!*вихід_даних)
return false;
for (природне і = 0; і < довжина_мантиси; і++) {
(*вихід_даних)[і] = (п8)буфер[і];
}
} else {
*вихід_розміру_експоненти = 0;
*вихід_розміру = (природне)довжина;
*вихід_даних = (п8*)malloc(*вихід_розміру);
if (!*вихід_даних)
return false;
for (природне і = 0; і < *вихід_розміру; і++) {
(*вихід_даних)[і] = (п8)буфер[і];
}
}
return true;
}
extern логічне пристрій_мавки_перетворити_п64_в_кд(п64 значення,
природне* вихід_розміру,
п8** вихід_даних) {
природне розмір_ю8;
п8* дані_ю8;
ціле* розмір_експоненти;
природне позиція_помилки;
if (перетворити_п64_в_ю8(значення, &розмір_ю8, &дані_ю8)) {
if (пристрій_мавки_перекодувати_ю8_в_кд(розмір_ю8, дані_ю8, вихід_розміру,
вихід_даних, &позиція_помилки)) {
free(дані_ю8);
return true;
}
free(дані_ю8);
}
return false;
}
extern логічне пристрій_мавки_перетворити_ц64_в_кд(ц64 значення,
природне* вихід_розміру,
п8** вихід_даних) {
природне розмір_ю8;
п8* дані_ю8;
природне позиція_помилки;
if (перетворити_ц64_в_ю8(значення, &розмір_ю8, &дані_ю8)) {
if (пристрій_мавки_перекодувати_ю8_в_кд(розмір_ю8, дані_ю8, вихід_розміру,
вихід_даних, &позиція_помилки)) {
free(дані_ю8);
return true;
}
free(дані_ю8);
}
return false;
}
extern логічне пристрій_мавки_перетворити_р64_в_кд(
р64 значення,
природне* вихід_розміру,
п8** вихід_даних,
ціле* вихід_розміру_експоненти) {
природне розмір_ю8;
п8* дані_ю8;
природне позиція_помилки;
if (перетворити_р64_в_ю8(значення, &розмір_ю8, &дані_ю8,
вихід_розміру_експоненти)) {
if (пристрій_мавки_перекодувати_ю8_в_кд(розмір_ю8, дані_ю8, вихід_розміру,
вихід_даних, &позиція_помилки)) {
free(дані_ю8);
return true;
}
free(дані_ю8);
}
return false;
}
extern п64 пристрій_мавки_піднести_до_степеня_п64(п64 значення, п64 степінь) {
п64 результат = 1;
for (п64 і = 0; і < степінь; і++) {
результат *= значення;
}
return результат;
}
extern ц64 пристрій_мавки_піднести_до_степеня_ц64(ц64 значення, ц64 степінь) {
ц64 результат = 1;
for (ц64 і = 0; і < степінь; і++) {
результат *= значення;
}
return результат;
}
extern р64 пристрій_мавки_піднести_до_степеня_р64(р64 значення, р64 степінь) {
return pow(значення, степінь);
}
extern логічне пристрій_мавки_перевірити_чи_шлях_існує_і_є_файлом(
природне розмір_шляху,
п8* дані_шляху) {
char* шлях_рядок = (char*)malloc(розмір_шляху + 1);
for (природне і = 0; і < розмір_шляху; і++) {
шлях_рядок[і] = (char)дані_шляху[і];
}
шлях_рядок[розмір_шляху] = '\0';
struct stat буфер_статистики;
логічне результат = false;
if (stat(шлях_рядок, &буфер_статистики) == 0) {
if (S_ISREG(буфер_статистики.st_mode)) {
результат = true;
}
}
free(шлях_рядок);
return результат;
}
extern логічне пристрій_мавки_перевірити_чи_шлях_закінчується_як_модуль_мавки(
природне розмір_шляху,
п8* дані_шляху) {
const char* суфікс = ".м";
природне довжина_суфікса = strlen(суфікс);
if (розмір_шляху < довжина_суфікса) {
return false;
}
for (природне і = 0; і < довжина_суфікса; і++) {
if (дані_шляху[розмір_шляху - довжина_суфікса + і] != (п8)суфікс[і]) {
return false;
}
}
return true;
}
extern логічне пристрій_мавки_отримати_абсолютний_шлях(природне розмір_шляху,
п8* дані_шляху,
природне* вихід_розміру,
п8** вихід_даних) {
char* шлях_рядок = (char*)malloc(розмір_шляху + 1);
for (природне і = 0; і < розмір_шляху; і++) {
шлях_рядок[і] = (char)дані_шляху[і];
}
шлях_рядок[розмір_шляху] = '\0';
char* абсолютний_шлях = realpath(шлях_рядок, NULL);
free(шлях_рядок);
if (абсолютний_шлях == NULL) {
return false;
}
природне довжина = strlen(абсолютний_шлях);
*вихід_розміру = довжина;
*вихід_даних = (п8*)malloc(довжина);
if (!*вихід_даних) {
free(абсолютний_шлях);
return false;
}
for (природне і = 0; і < довжина; і++) {
(*вихід_даних)[і] = (п8)абсолютний_шлях[і];
}
free(абсолютний_шлях);
return true;
}
extern логічне пристрій_мавки_отримати_теку_шляху(природне розмір_шляху,
п8* дані_шляху,
природне* вихід_розміру,
п8** вихід_даних,
природне рівень) {
char* шлях_рядок = (char*)malloc(розмір_шляху + 1);
for (природне і = 0; і < розмір_шляху; і++) {
шлях_рядок[і] = (char)дані_шляху[і];
}
шлях_рядок[розмір_шляху] = '\0';
char* шлях_копія = strdup(шлях_рядок);
char* тека = dirname(шлях_копія);
for (природне і = 1; і < рівень; і++) {
char* нова_копія = strdup(тека);
free(шлях_копія);
шлях_копія = нова_копія;
тека = dirname(шлях_копія);
}
природне довжина = strlen(тека);
*вихід_розміру = довжина;
*вихід_даних = (п8*)malloc(довжина);
if (!*вихід_даних) {
free(шлях_рядок);
free(шлях_копія);
return false;
}
for (природне і = 0; і < довжина; і++) {
(*вихід_даних)[і] = (п8)тека[і];
}
free(шлях_рядок);
free(шлях_копія);
return true;
}
extern логічне пристрій_мавки_отримати_теку_до_паків(природне розмір_шляху,
п8* дані_шляху,
природне* вихід_розміру,
п8** вихід_даних) {
const char* паки_суфікс = "/паки";
природне довжина_суфікса = strlen(паки_суфікс);
*вихід_розміру = розмір_шляху + довжина_суфікса;
*вихід_даних = (п8*)malloc(*вихід_розміру);
if (!*вихід_даних) {
return false;
}
for (природне і = 0; і < розмір_шляху; і++) {
(*вихід_даних)[і] = дані_шляху[і];
}
for (природне і = 0; і < довжина_суфікса; і++) {
(*вихід_даних)[розмір_шляху + і] = (п8)паки_суфікс[і];
}
return true;
}
extern логічне пристрій_мавки_отримати_назву_модуля_з_шляху(
природне розмір_шляху,
п8* дані_шляху,
природне* вихід_розміру,
п8** вихід_даних) {
char* шлях_рядок = (char*)malloc(розмір_шляху + 1);
for (природне і = 0; і < розмір_шляху; і++) {
шлях_рядок[і] = (char)дані_шляху[і];
}
шлях_рядок[розмір_шляху] = '\0';
char* шлях_копія = strdup(шлях_рядок);
char* назва = basename(шлях_копія);
const char* суфікс = ".м";
природне довжина_суфікса = strlen(суфікс);
природне довжина = strlen(назва);
if (довжина >= довжина_суфікса) {
логічне має_суфікс = true;
for (природне і = 0; і < довжина_суфікса; і++) {
if (назва[довжина - довжина_суфікса + і] != суфікс[і]) {
має_суфікс = false;
break;
}
}
if (має_суфікс) {
довжина -= довжина_суфікса;
}
}
// Convert UTF-8 to КД encoding
п8* назва_ю8 = (п8*)malloc(довжина);
for (природне і = 0; і < довжина; і++) {
назва_ю8[і] = (п8)назва[і];
}
природне позиція_помилки;
логічне результат = пристрій_мавки_перекодувати_ю8_в_кд(
довжина, назва_ю8, вихід_розміру, вихід_даних, &позиція_помилки);
free(назва_ю8);
free(шлях_рядок);
free(шлях_копія);
return результат;
}
extern логічне пристрій_мавки_збити_шлях_до_модуля(
природне кількість_елементів,
ЕлементШляхуПристроюМавки* елементи,
природне* вихід_розміру,
п8** вихід_даних) {
const char* суфікс = ".м";
природне загальний_розмір = кількість_елементів - 1 + strlen(суфікс);
for (природне і = 0; і < кількість_елементів; і++) {
загальний_розмір += елементи[і].розмір;
}
*вихід_розміру = загальний_розмір;
*вихід_даних = (п8*)malloc(загальний_розмір);
if (!*вихід_даних) {
return false;
}
природне позиція = 0;
for (природне і = 0; і < кількість_елементів; і++) {
memcpy(*вихід_даних + позиція, елементи[і].дані, елементи[і].розмір);
позиція += елементи[і].розмір;
if (і < кількість_елементів - 1) {
(*вихід_даних)[позиція++] = '/';
}
}
for (природне і = 0; і < strlen(суфікс); і++) {
(*вихід_даних)[позиція++] = (п8)суфікс[і];
}
return true;
}
extern логічне пристрій_мавки_отримати_відносний_шлях(природне розмір_шляху,
п8* дані_шляху,
природне* вихід_розміру,
п8** вихід_даних) {
// Convert input path to C string
char* шлях_рядок = (char*)malloc(розмір_шляху + 1);
for (природне і = 0; і < розмір_шляху; і++) {
шлях_рядок[і] = (char)дані_шляху[і];
}
шлях_рядок[розмір_шляху] = '\0';
// Get current working directory
char* поточна_тека = getcwd(NULL, 0);
if (поточна_тека == NULL) {
free(шлях_рядок);
return false;
}
// Get absolute path of the input
char* абсолютний_шлях = realpath(шлях_рядок, NULL);
if (абсолютний_шлях == NULL) {
// If realpath fails, use the original path as-is
абсолютний_шлях = strdup(шлях_рядок);
}
free(шлях_рядок);
// Find common prefix
природне довжина_поточної = strlen(поточна_тека);
природне довжина_абсолютного = strlen(абсолютний_шлях);
природне спільна_довжина = 0;
for (природне і = 0; і < довжина_поточної && і < довжина_абсолютного; і++) {
if (поточна_тека[і] == абсолютний_шлях[і]) {
if (поточна_тека[і] == '/') {
спільна_довжина = і + 1;
}
} else {
break;
}
}
// Count how many directories we need to go up
природне рівнів_вгору = 0;
for (природне і = спільна_довжина; і < довжина_поточної; і++) {
if (поточна_тека[і] == '/') {
рівнів_вгору++;
}
}
if (спільна_довжина < довжина_поточної &&
поточна_тека[довжина_поточної - 1] != '/') {
рівнів_вгору++;
}
// Build relative path
природне розмір_відносного = рівнів_вгору * 3; // "../" for each level up
if (довжина_абсолютного > спільна_довжина) {
розмір_відносного += довжина_абсолютного - спільна_довжина;
} else {
розмір_відносного = 1; // Just "."
}
char* відносний_шлях = (char*)malloc(розмір_відносного + 1);
природне позиція = 0;
// Add "../" for each level up
for (природне і = 0; і < рівнів_вгору; і++) {
відносний_шлях[позиція++] = '.';
відносний_шлях[позиція++] = '.';
відносний_шлях[позиція++] = '/';
}
// Add remaining path
if (довжина_абсолютного > спільна_довжина) {
strcpy(відносний_шлях + позиція, абсолютний_шлях + спільна_довжина);
позиція += довжина_абсолютного - спільна_довжина;
} else if (позиція == 0) {
відносний_шлях[позиція++] = '.';
} else if (позиція > 0 && відносний_шлях[позиція - 1] == '/') {
позиція--; // Remove trailing slash
}
відносний_шлях[позиція] = '\0';
// Convert to output format
*вихід_розміру = позиція;
*вихід_даних = (п8*)malloc(*вихід_розміру);
if (!*вихід_даних) {
free(відносний_шлях);
free(поточна_тека);
free(абсолютний_шлях);
return false;
}
for (природне і = 0; і < позиція; і++) {
(*вихід_даних)[і] = (п8)відносний_шлях[і];
}
free(відносний_шлях);
free(поточна_тека);
free(абсолютний_шлях);
return true;
}
extern логічне пристрій_мавки_перевірити_чи_шлях_починається_на(
природне розмір_шляху,
п8* дані_шляху,
природне розмір_початку,
п8* дані_початку) {
if (розмір_початку > розмір_шляху) {
return false;
}
for (природне і = 0; і < розмір_початку; і++) {
if (дані_шляху[і] != дані_початку[і]) {
return false;
}
}
return true;
}
extern логічне пристрій_мавки_отримати_шлях_до_паку_з_шляху_теки_модулів(
природне розмір_шляху,
п8* дані_шляху,
природне розмір_шляху_до_паків,
п8* дані_шляху_до_паків,
природне* вихід_розміру,
п8** вихід_даних) {
// Check if the module path starts with the packages path
if (розмір_шляху <= розмір_шляху_до_паків) {
return false;
}
// Verify that the module path starts with the packages path
for (природне і = 0; і < розмір_шляху_до_паків; і++) {
if (дані_шляху[і] != дані_шляху_до_паків[і]) {
return false;
}
}
// Find the next '/' after the packages path to get the package directory
природне позиція_наступного_слешу = 0;
логічне знайдено = false;
// Skip the packages path and any immediate '/'
природне початок = розмір_шляху_до_паків;
if (початок < розмір_шляху && дані_шляху[початок] == '/') {
початок++;
}
// Find the next '/' which marks the end of the package name
for (природне і = початок; і < розмір_шляху; і++) {
if (дані_шляху[і] == '/') {
позиція_наступного_слешу = і; // Don't include the trailing slash
знайдено = true;
break;
}
}
if (!знайдено) {
позиція_наступного_слешу = розмір_шляху;
}
// Return the path up to but not including the trailing slash
*вихід_розміру = позиція_наступного_слешу;
*вихід_даних = (п8*)malloc(*вихід_розміру);
if (!*вихід_даних) {
return false;
}
for (природне і = 0; і < позиція_наступного_слешу; і++) {
(*вихід_даних)[і] = дані_шляху[і];
}
return true;
}
char* read_line_no_newline(size_t* out_len) {
size_t cap = 128;
size_t len = 0;
char* buf = 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 = realloc(buf, cap);
if (!tmp) {
free(buf);
return NULL;
}
buf = tmp;
}
buf[len++] = c;
}
// If nothing read and EOF, return NULL
if (len == 0 && c == EOF) {
free(buf);
return NULL;
}
buf[len] = '\0';
if (out_len)
*out_len = len;
return buf;
}
extern логічне пристрій_мавки_читати_кд(природне розмір_перед,
п8* дані_перед,
природне* вихід_розміру,
п8** вихід_даних,
природне дозволити_історію,
природне* кінець_файлу) {
if (користувацький_пристрій_мавки_читати_кд != NULL) {
return користувацький_пристрій_мавки_читати_кд(
розмір_перед, дані_перед, вихід_розміру, вихід_даних, дозволити_історію,
кінець_файлу);
}
пристрій_мавки_вивести_кд(розмір_перед, дані_перед);
size_t len;
char* data = read_line_no_newline(&len);
if (!data) {
*кінець_файлу = true;
return true;
}
*кінець_файлу = false;
return пристрій_мавки_перекодувати_ю8_в_кд((природне)len, (п8*)data,
вихід_розміру, вихід_даних, NULL);
}
extern логічне пристрій_мавки_отримати_поточний_шлях_процесу(
природне* вихід_розміру,
п8** вихід_даних) {
char* поточна_тека = getcwd(NULL, 0);
if (поточна_тека == NULL) {
return false;
}
*вихід_розміру = strlen(поточна_тека);
*вихід_даних = (п8*)malloc(*вихід_розміру);
if (!*вихід_даних) {
free(поточна_тека);
return false;
}
memcpy(*вихід_даних, поточна_тека, *вихід_розміру);
free(поточна_тека);
return true;
}