#include <iostream>
#include <cstdio>      // Для функций работы с файлами и C-строками
#include <cstring>     // Для функций работы со строками
#include <cctype>      // Для функций проверки символов
#include <cstdlib>     // Для функций выделения памяти

using namespace std;

// Максимальная длина имени файла (предположим 260 символов, типичная максимальная длина пути в Windows)
const size_t MAX_FILENAME_LENGTH = 260;

// Максимальная длина строки для поиска (предположим 256 символов)
const size_t MAX_SEARCH_STRING_LENGTH = 256;

// Запрещенные символы в имени файла
const char* forbidden_chars = "*\"<>?|";

// Функция для проверки корректности имени файла
bool isValidFilename(const char* filename) {
    // Проверка на наличие запрещенных символов
    for (size_t i = 0; i < strlen(forbidden_chars); ++i) {
        if (strchr(filename, forbidden_chars[i]) != nullptr) {
            return false;
        }
    }

    // Проверка на двоеточие
    const char* colon = strchr(filename, ':');
    if (colon != nullptr) {
        // Двоеточие должно быть вторым символом
        if (colon - filename != 1) {
            return false;
        }
        // Первый символ должен быть буквой
        if (!isalpha(filename[0])) {
            return false;
        }
        // После двоеточия должна идти обратная косая черта
        if (*(colon + 1) != '\\') {
            return false;
        }
    }

    // Проверка расширения файла
    const char* dot = strrchr(filename, '.');
    if (dot != nullptr) {
        // Проверяем, что расширение .txt (без учета регистра)
        if (strlen(dot) != 4) { // Длина должна быть 4 символа: '.' + 'txt'
            return false;
        }
        // Преобразуем расширение к нижнему регистру для сравнения
        char ext[5];
        strncpy(ext, dot, 4);
        ext[4] = '\0';
        for (int i = 0; i < 4; ++i) {
            ext[i] = tolower(ext[i]);
        }
        if (strcmp(ext, ".txt") != 0) {
            return false;
        }
    }

    return true;
}

// Функция для добавления расширения .txt, если его нет
void addTxtExtension(char* filename) {
    if (strrchr(filename, '.') == nullptr) {
        // Добавляем .txt
        strcat(filename, ".txt");
    }
}

int main() {
    // 4.1. Запросить у пользователя имя файла, сохранив его в массиве символов на стеке
    char filename[MAX_FILENAME_LENGTH];
    cout << "Введите имя файла: ";
    cin.getline(filename, MAX_FILENAME_LENGTH);

    // 4.2. Проверка корректности имени файла
    if (!isValidFilename(filename)) {
        cout << "Некорректное имя файла." << endl;
        return 1; // Завершаем программу с ошибкой
    }

    // 4.3. Добавить расширение .txt, если его нет
    addTxtExtension(filename);

    // Повторная проверка после добавления расширения
    if (!isValidFilename(filename)) {
        cout << "Некорректное имя файла после добавления расширения." << endl;
        return 1;
    }

    // 4.4. Загрузка содержимого файла в память
    // Открываем файл в бинарном режиме для точного определения размера
    FILE* file = fopen(filename, "rb");
    if (file == nullptr) {
        cout << "Не удалось открыть файл: " << filename << endl;
        return 1;
    }

    // Перемещаемся в конец файла
    if (fseek(file, 0, SEEK_END) != 0) {
        cout << "Ошибка при перемещении в конец файла." << endl;
        fclose(file);
        return 1;
    }

    // Определяем размер файла
    long file_size = ftell(file);
    if (file_size == -1L) {
        cout << "Не удалось определить размер файла." << endl;
        fclose(file);
        return 1;
    }

    // Возвращаемся в начало файла
    rewind(file);

    // Выделяем динамическую память для содержимого файла (+1 для завершающего нуля)
    char* file_content = (char*)malloc(file_size + 1);
    if (file_content == nullptr) {
        cout << "Не удалось выделить память для содержимого файла." << endl;
        fclose(file);
        return 1;
    }

    // Читаем содержимое файла
    size_t read_size = fread(file_content, sizeof(char), file_size, file);
    if (read_size != (size_t)file_size) {
        cout << "Ошибка при чтении файла." << endl;
        free(file_content);
        fclose(file);
        return 1;
    }

    // Добавляем завершающий ноль для безопасной работы со строками
    file_content[file_size] = '\0';

    // Закрываем файл
    fclose(file);

    // 4.5. Запросить у пользователя строку для поиска, сохранив её в массиве на стеке
    char search_string[MAX_SEARCH_STRING_LENGTH];
    cout << "Введите строку для поиска: ";
    cin.getline(search_string, MAX_SEARCH_STRING_LENGTH);

    // 4.6. Подсчитать и вывести число вхождений введенной строки в текст файла
    int count = 0;
    char* pos = file_content;

    // Длина строки для поиска
    size_t search_len = strlen(search_string);
    if (search_len == 0) {
        cout << "Пустая строка для поиска." << endl;
        free(file_content);
        return 1;
    }

    // Поиск всех вхождений
    while ((pos = strstr(pos, search_string)) != nullptr) {
        count++;
        pos += search_len; // Продвигаемся вперед, чтобы избежать бесконечного цикла
    }

    cout << "Число вхождений строки \"" << search_string << "\": " << count << endl;

    // 4.7. Освободить выделенную память
    free(file_content);

    return 0;
}