Представь, что твоя жена хочет с тобой развестись из-за твоей работы. Она жалуется, что ты постоянно находишься в работе и не уделаешь ей время. Она твердо решила, что хочет узнать над чем ты работаешь и научиться делать также. Она попросила тебя отправить твою работу, либо ты отправляешь и объясняешь и учишь ее, либо она от тебя уходит. Твоя задача максимально подробно прокомментировать каждую строку своего кода, чтобы она смогла прочесть и понять с первого разам учитывая что у нее нулевые знания по программированию. Обязательно выпиши где и откуда ты брал функции, то есть из каких библиотек. Как работают твои циклы, зачем ты объявлял массивы, и почему твои переменные работают именно так. Комментарий должны быть прям в самом коде. Особенно подробнее расскажи о том как работают функции из сторонних библиотек. Код представлен ниже.
#include <getopt.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct flag {
  int e, i, v, c, l, n;
  int filecount;
} flags;

typedef struct patterns {
  char **patterns;
  int count;
} patterns_t;

int s21_parser(int argc, char *argv[], flags *flag, patterns_t *pat);
void process_file(const char *filename, flags flag, patterns_t pat);
int match_pattern(const char *line, patterns_t pat, flags flag);
void print_match(const char *filename, int line_num, const char *line,
                 flags flag);
void free_patterns(patterns_t *pat);

int main(int argc, char *argv[]) {
  flags flag = {0, 0, 0, 0, 0, 0, 0};
  patterns_t pat = {NULL, 0};
  int ret = 0;

  int start = s21_parser(argc, argv, &flag, &pat);
  if (start == -1) {
    ret = 1;
  } else {
    if (flag.filecount == 0) {
      process_file("", flag, pat);
    } else {
      for (int i = start; i < argc; i++) {
        process_file(argv[i], flag, pat);
      }
    }
  }

  free_patterns(&pat);
  return ret;
}

int s21_parser(int argc, char *argv[], flags *flag, patterns_t *pat) {
  int option;
  int ret = 0;

  pat->patterns = malloc(sizeof(char *) * argc);
  if (!pat->patterns) {
    fprintf(stderr, "Memory allocation error\n");
    ret = -1;
  }

  if (ret == 0) {
    pat->count = 0;

    while ((option = getopt(argc, argv, "e:ivcln")) != -1) {
      switch (option) {
        case 'e':
          flag->e = 1;
          pat->patterns[pat->count++] = strdup(optarg);
          break;
        case 'i':
          flag->i = 1;
          break;
        case 'v':
          flag->v = 1;
          break;
        case 'c':
          flag->c = 1;
          break;
        case 'l':
          flag->l = 1;
          break;
        case 'n':
          flag->n = 1;
          break;
        case '?':
          fprintf(stderr, "Unknown option: -%c\n", optopt);
          ret = -1;
          break;
        default:
          break;
      }
      if (ret == -1) {
        break;
      }
    }
  }

  if (ret == 0 && !flag->e) {
    if (optind < argc) {
      pat->patterns[pat->count++] = strdup(argv[optind++]);
    } else {
      fprintf(stderr, "No pattern provided.\n");
      ret = -1;
    }
  }

  if (ret == 0) {
    flag->filecount = argc - optind;
  } else {
    free_patterns(pat);
  }

  if (ret == -1) {
    return -1;
  } else {
    return optind;
  }
}

void free_patterns(patterns_t *pat) {
  if (pat->patterns) {
    for (int i = 0; i < pat->count; i++) {
      free(pat->patterns[i]);
    }
    free(pat->patterns);
    pat->patterns = NULL;
  }
}

int match_pattern(const char *line, patterns_t pat, flags flag) {
  int match = 0;
  regex_t regex;
  int reti;
  int cflags = REG_EXTENDED;
  if (flag.i) {
    cflags |= REG_ICASE;
  }

  for (int i = 0; i < pat.count; i++) {
    reti = regcomp(&regex, pat.patterns[i], cflags);
    if (reti) {
      fprintf(stderr, "Could not compile regex: %s\n", pat.patterns[i]);
      continue;
    }
    reti = regexec(&regex, line, 0, NULL, 0);
    if (!reti) {
      match = 1;
    } else if (reti == REG_NOMATCH) {
    } else {
      char errbuf[100];
      regerror(reti, &regex, errbuf, sizeof(errbuf));
      fprintf(stderr, "Regex match failed: %s\n", errbuf);
    }
    regfree(&regex);
    if (match) break;
  }

  if (flag.v)
    return !match;
  else
    return match;
}
void print_match(const char *filename, int line_num, const char *line,
                 flags flag) {
  if (flag.filecount > 1 && filename[0] != '\0') {
    printf("%s:", filename);
  }
  if (flag.n) {
    printf("%d:", line_num);
  }
  printf("%s", line);
  if (line[strlen(line) - 1] != '\n') {
    printf("\n");
  }
}

void process_file(const char *filename, flags flag, patterns_t pat) {
  FILE *file;
  int need_processing = 1;

  if (filename[0] == '\0') {
    file = stdin;
  } else {
    file = fopen(filename, "r");
    if (!file) {
      fprintf(stderr, "s21_grep: %s: Cannot open file\n", filename);
      need_processing = 0;
    }
  }

  if (need_processing) {
    char *line = NULL;
    size_t len = 0;
    ssize_t read;
    int

d, [17.11.2024 11:06]
count = 0;
    int matched = 0;
    int line_num = 0;

    while ((read = getline(&line, &len, file)) != -1) {
      line_num++;
      matched = match_pattern(line, pat, flag);
      if (matched) {
        count++;
        if (!flag.c && !flag.l) {
          print_match(filename, line_num, line, flag);
        }
      }
    }

    if (flag.c) {
      if (flag.filecount > 1 && filename[0] != '\0') {
        printf("%s:%d\n", filename, count);
      } else {
        printf("%d\n", count);
      }
    }

    if (flag.l && count > 0 && filename[0] != '\0') {
      printf("%s\n", filename);
    }

    free(line);
  }

  if (file != stdin) {
    fclose(file);
  }
}