Работа со сторонними исходными текстами

Рассмотрим ситуацию, когда сторонние исходники используются, но нужно их немного поправить:

Patch / diff

Цикл обновления / внесения изменений:

  1. Первоначальный импорт исходников
    1. Адаптация к вашим нуждам
    2. Оформление серии патчей (см. ниже)

    3. Релиз
  2. Отныне и навеки
    1. Обновление апстримной версии
    2. Применение патчей к обновлённой версии
    3. Адаптация отвалившихся патчей
    4. Релиз

Утилита diffпострочное сравнение и демонстрация изменений двух текстов

   1 #include <stdio.h>
   2 #include <sys/types.h>
   3 #include <sys/stat.h>
   4 #include <fcntl.h>
   5 #include <ctype.h>
   6 
   7 /* open()->fopen() wrapper */
   8 static FILE *ffopen(const char *pathname, const char *mode, int flags)
   9 {
  10   int m;
  11 
  12   switch(tolower(mode[0])+(mode[1]=='+')) {
  13     case 'b': /* "a+" */
  14     case 'a': m = O_WRONLY | O_CREAT | O_APPEND; break;
  15     case 'r': m = O_RDONLY; break;
  16     case 's': m = O_RDWR; break; /* "r+" */
  17     case 'x': /* "w+" */
  18     case 'w': m = O_WRONLY | O_CREAT | O_TRUNC; break;
  19     default: m = O_RDONLY; break;
  20   }
  21 
  22   int fd = open(pathname, flags, m);
  23   return fd<0? NULL: fdopen(fd, mode);
  24 }
  25 
  26 int main(int argc, char *argv[]) {
  27         FILE *fp;
  28 
  29         fp = ffopen(argv[1], "r", O_NOFOLLOW);
  30         if(fp == NULL) {
  31           perror(argv[1]);
  32           return 1;
  33         }
  34 
  35         return 0;
  36 }

   1 #include <stdio.h>
   2 #include <sys/types.h>
   3 #include <sys/stat.h>
   4 #include <fcntl.h>
   5 #include <ctype.h>
   6 
   7 /* open()->fopen() wrapper */
   8 static FILE *ffopen(const char *pathname, const char *mode, int flags)
   9 {
  10   int m;
  11 
  12   /* Simulate fopen flags */
  13   switch(tolower(mode[0])+(mode[1]=='+')) {
  14     case 'a': m = O_WRONLY | O_CREAT | O_APPEND; break;
  15     case 'b': /* "a+" */
  16     case 'r': m = O_RDONLY; break;
  17     case 's': m = O_RDWR; break; /* "r+" */
  18     case 'x': /* "w+" */
  19     case 'w': m = O_WRONLY | O_CREAT | O_TRUNC; break;
  20     default: m = O_RDONLY; break;
  21   }
  22 
  23   int fd = open(pathname, flags, m);
  24   return fd<0? NULL: fdopen(fd, mode);
  25 }
  26 
  27 int main(int argc, char *argv[]) {
  28         FILE *fp;
  29 
  30         fp = ffopen(argv[1], "r", O_NOFOLLOW);
  31         if(fp == NULL) {
  32           perror(argv[1]);
  33           return 1;
  34         }
  35 
  36         return 0;
  37 }

Утилита patch умеет применять результат diff к исходному файлу, при этом получается целевой файл

Что гораздо важнее, patch умеет находить перемещение контекста и даже определять приблизительное совпадение контекста:

В случае, когда какие-то блоки применяются, а какие-то — нет, patch создаёт reject-файл — патч, содержащий только неприложившиеся блоки.

Ручное преобразование патчей

Patchutils

/!\ Примеров нет ⇒ буду тупить в эфире!

Использование git

Сочетание git и patch

Если никакого git-репозитория нет, всё равно удобно использовать git:

Д/З

  1. Прочитать про diff и patch

  2. Написать на Си программу, которая генерирует случайный лабиринт размера 6×6
    • Минимальные требования:
      • Лабиринт — это последовательность строк из «.» и «#».

      • Длина строки — 13 символов, количество строк также 13. Таким образом, он состоит из «комнат» 3×3 с общими «стенами». Пример полностью непроходимого лабиринта 6×6:
        #############
        #.#.#.#.#.#.#
        #############
        #.#.#.#.#.#.#
        #############
        #.#.#.#.#.#.#
        #############
        #.#.#.#.#.#.#
        #############
        #.#.#.#.#.#.#
        #############
        #.#.#.#.#.#.#
        #############
    • Лабиринт, генерируемый программой, должен быть проходимым из любой комнаты в любую
      • <!> (необязательно) Путь между комнатами должен быть единственным. Пример:

        #############
        #.......#...#
        #######.#.#.#
        #...#...#.#.#
        #.###.###.#.#
        #...#.....#.#
        ###.#######.#
        #.......#...#
        #.#######.###
        #...#.....#.#
        #.#.#.#####.#
        #.#.........#
        #############
    • Приложить к файлу набор из минимум трёх unified-патчей, которые модифицируют программу следующим образом:
      1. Размер лабиринта задаётся из командной строки первым параметром
      2. Первый параметр — это строка из двух символов, «проход» и «стена» выводимого лабиринта, а второй — его размер
      3. Первый параметр — начальное значение генератора псевдослучайных чисел (для воспроизведения лабиринта), второй и третий — «проход»-«стена» и размер соответственно.
    • Написать Makefile (или аналог), который будет

      • генерировать три дополнительных исходника, соответствующх добавлению очередного патча
      • генерировать, соответственно, четыре бинарника
      • иметь цель run, которая запускает все четыре бинарника с заданными параметрами

      • иметь цель clean, уничтожающую все генераты

  3. Создать в репозитории с домашними заданиями подкаталог 09_PatchDiff и поместить туда решение.

Получилось примерно так:

LecturesCMC/LinuxApplicationDevelopment2023/09_PatchDiff (последним исправлял пользователь FrBrGeorge 2023-11-18 18:34:29)