|
|
#include <stdio.h>
|
|
|
#include <stdlib.h>
|
|
|
#include <string.h>
|
|
|
#include <ctype.h>
|
|
|
|
|
|
int is_valid_filename(char *name) {
|
|
|
// 1) Запрещённые символы
|
|
|
const char *forbidden = "*\"<>?|?";
|
|
|
for (const char *p = forbidden; *p; ++p) {
|
|
|
if (strchr(name, *p) != NULL)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
// 2) Двоеточие: только вторым символом, перед ним буква, после "\"
|
|
|
char *colon = strchr(name, ':');
|
|
|
if (colon) {
|
|
|
if (colon != name + 1) return 0; // не вторым
|
|
|
if (!isalpha((unsigned char)name[0])) return 0; // не буква
|
|
|
if (colon[1] != '\\') return 0; // нет '\'
|
|
|
}
|
|
|
|
|
|
// 3) Расширение: либо нет, либо .txt (в любом регистре)
|
|
|
char *dot = strrchr(name, '.');
|
|
|
if (dot) {
|
|
|
char ext[5] = {0};
|
|
|
strncpy(ext, dot, 4); // ".txt" + '\0'
|
|
|
for (int i = 0; ext[i]; ++i)
|
|
|
ext[i] = (char)tolower((unsigned char)ext[i]);
|
|
|
if (strcmp(ext, ".txt") != 0)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
int main(void) {
|
|
|
char filename[260]; // 4.1: имя файла на стеке
|
|
|
char pattern[256]; // 4.5: строка поиска на стеке
|
|
|
|
|
|
printf("Enter the file name: ");
|
|
|
if (!fgets(filename, sizeof filename, stdin)) {
|
|
|
printf("Input error\n");
|
|
|
return 1;
|
|
|
}
|
|
|
// убрать '\n'
|
|
|
filename[strcspn(filename, "\n")] = '\0';
|
|
|
|
|
|
// 4.2: проверка имени
|
|
|
if (!is_valid_filename(filename)) {
|
|
|
printf("Incorrect file name\n");
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
// 4.3: если нет расширения — добавить .txt
|
|
|
if (!strrchr(filename, '.')) {
|
|
|
if (strlen(filename) + 4 >= sizeof filename) {
|
|
|
printf("The file name is too long\n");
|
|
|
return 1;
|
|
|
}
|
|
|
strcat(filename, ".txt");
|
|
|
}
|
|
|
|
|
|
// 4.4: загрузка файла целиком
|
|
|
FILE *f = fopen(filename, "rb");
|
|
|
if (!f) {
|
|
|
printf("Failed to open file\n");
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
if (fseek(f, 0, SEEK_END) != 0) { // в конец
|
|
|
printf("Error fseek\n");
|
|
|
fclose(f);
|
|
|
return 1;
|
|
|
}
|
|
|
long size = ftell(f); // размер файла в байтах
|
|
|
if (size < 0) {
|
|
|
printf("Error ftell\n");
|
|
|
fclose(f);
|
|
|
return 1;
|
|
|
}
|
|
|
rewind(f); // обратно в начало
|
|
|
|
|
|
char *text = (char*)malloc((size_t)size + 1); // +1 для '\0'
|
|
|
if (!text) {
|
|
|
printf("Out of memory\n");
|
|
|
fclose(f);
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
size_t read_bytes = fread(text, 1, (size_t)size, f);
|
|
|
fclose(f);
|
|
|
text[read_bytes] = '\0'; // делаем C‑строку
|
|
|
|
|
|
// 4.5: строка для поиска
|
|
|
printf("Enter a search string: ");
|
|
|
if (!fgets(pattern, sizeof pattern, stdin)) {
|
|
|
printf("Input error\n");
|
|
|
free(text); // 4.7
|
|
|
return 1;
|
|
|
}
|
|
|
pattern[strcspn(pattern, "\n")] = '\0';
|
|
|
|
|
|
// 4.6: подсчёт вхождений pattern в text
|
|
|
int count = 0;
|
|
|
size_t pat_len = strlen(pattern);
|
|
|
if (pat_len > 0) {
|
|
|
char *pos = text;
|
|
|
while ((pos = strstr(pos, pattern)) != NULL) { // ищем подстроку
|
|
|
++count;
|
|
|
pos += pat_len; // идти дальше, можно pos+1, если нужны пересечения
|
|
|
}
|
|
|
}
|
|
|
|
|
|
printf("Number of occurrences: %d\n", count);
|
|
|
|
|
|
// 4.7: освобождение
|
|
|
free(text);
|
|
|
|
|
|
return 0;
|
|
|
} |