#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* дані) {
  пристрій_мавки_вивести_колір(колір);

  fwrite(дані, 1, розмір, stdout);

  пристрій_мавки_вивести_колір(КолірВиводуСтандартний);
}

extern void пристрій_мавки_вивести_ю8(природне колір,
                                      природне розмір,
                                      п8* дані) {
  пристрій_мавки_вивести_колір(колір);

  fwrite(дані, 1, розмір, stdout);

  пристрій_мавки_вивести_колір(КолірВиводуСтандартний);
}

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;
}