Читаем UNIX полностью

$ cat idiff.out Выходной поток направляется в этот файл

This is

not a test of

your skill

and comprehension.

$

Если вместо < или > выдан ответ е, idiff вызывает ed с двумя группами уже прочитанных строк. Если вторым был ответ е, буфер редактора выглядел бы следующим образом:

your

skill

and comprehension.

---

our

ability.

Все, что пишется редактором обратно в файл, идет в окончательный выходной поток.

И, наконец, любая команда может быть выполнена внутри idiff с помощью временного выхода посредством !cmd.

Технически самая трудная часть работы diff, и она уже выполнена. Таким образом, в задачи idiff входит разбор выходного потока diff, открытие, закрытие, чтение и считывание соответствующих файлов в нужное время. Главная функция idiff поддерживает файлы и запускает процесс diff:

/* idiff: interactive diff */

#include

#include

char *progname;

#define HUGE 10000 /* large number of lines */

main(argc, argv)

 int argc;

 char *argv[];

{

 FILE *fin, *fout, *f1, *f2, *efopen();

 char buf[BUFSIZ], *mktemp();

 char *diffout = "idiff.XXXXXX";

 progname = argv[0];

 if (argc != 3) {

  fprintf(stderr, "Usage: idiff file1 file2\n");

  exit(1);

 }

 f1 = efopen(argv[1], "r");

 f2 = efopen(argv[2], "r");

 fout = efopen("idiff.out", "w");

 mktemp(diffout);

 sprintf(buf,"diff %s %s >%s", argv[1], argv[2], diffout);

 system(buf);

 fin = efopen(diffout, "r");

 idiff(f1, f2, fin, fout);

 unlink(diffout);

 printf("%s output in file idiff.out\n", progname);

 exit(0);

}

Функция mktemp(3) создает файл, имя которого гарантированно отличается от имени любого существующего файла. Mktemp переписывает свой аргумент: шесть символов X заменяются идентификатором процесса и буквой. Системный вызов unlink(2) удаляет поименованный файл из файловой системы.

Циклическая обработка изменений, о которых сообщает diff, выполняется функцией idiff. Основная идея достаточно проста: печатать порцию выходного потока diff, пропускать нежелательные данные в одном файле, а затем копировать требуемый вариант из другого файла. В программе есть много утомительных подробностей, так что она оказывается несколько больше, чем нам бы хотелось, но по частям ее довольно легко понять.

idiff(f1, f2, fin, fout) /* process diffs */

 FILE *f1, *f2, *fin, *fout;

{

 char *tempfile = "idiff.XXXXXX";

 char buf[BUFSIZ], buf2[BUFSIZ], *mktemp();

 FILE *ft, *efopen();

 int cmd, n, from1, to1, from2, to2, nf1, nf2;

 mktemp(tempfile);

 nf1 = nf2 = 0;

 while (fgets(buf, sizeof buf, fin) != NULL) {

  parse(buf, &from1, ftto1, &cmd, &from2, &to2);

  n = to1-from1 + to2-from2 + 1; /* #lines from diff */

  if (cmd == 'c')

   n += 2;

  else if (cmd == 'a')

   from1++;

  else if (cmd == 'd')

   from2++;

  printf("%s", buf);

  while (n-- > 0) {

   fgets(buf, sizeof buf, fin);

   printf("%s", buf);

  }

  do {

   printf("? ");

   fflush(stdout);

   fgets(buf, sizeof buf, stdin);

   switch (buf[0]) {

   case '>':

    nskip(f1, to1-nf1);

    ncopy(f2, to2-nf2, fout);

    break;

   case '<':

    nskip(f2, to2-nf2);

    ncopy(f1, to1-nf1, fout);

    break;

   case 'e':

    ncopy(f1, from1-1-nf1, fout);

    nskip(f2, from2-1-nf2);

    ft = efopen(tempfile, "w");

    ncopy(f1, to1+1-from1, ft);

    fprintf (ft, "---\n");

    ncopy(f2, to2+1-from2, ft);

    fclose(ft);

    sprintf(buf2, "ed %s", tempfile);

    system(buf2);

    ft = efopen(tempfile, "r");

    ncopy(ft, HUGE, fout);

    fclose(ft);

    break;

  case '!':

   system(buf+1);

Перейти на страницу:

Похожие книги