Брайан Керниган - UNIX — универсальная среда программирования Страница 54

Тут можно читать бесплатно Брайан Керниган - UNIX — универсальная среда программирования. Жанр: Компьютеры и Интернет / Программное обеспечение, год -. Так же Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте «WorldBooks (МирКниг)» или прочесть краткое содержание, предисловие (аннотацию), описание и ознакомиться с отзывами (комментариями) о произведении.
Брайан Керниган - UNIX — универсальная среда программирования

Брайан Керниган - UNIX — универсальная среда программирования краткое содержание

Прочтите описание перед тем, как прочитать онлайн книгу «Брайан Керниган - UNIX — универсальная среда программирования» бесплатно полную версию:
В книге американских авторов — разработчиков операционной системы UNIX — блестяще решена проблема автоматизации деятельности программиста, системной поддержки его творчества, выходящей за рамки языков программирования. Профессионалам открыт богатый "встроенный" арсенал системы UNIX. Многочисленными примерами иллюстрировано использование языка управления заданиями shell.Для программистов-пользователей операционной системы UNIX.

Брайан Керниган - UNIX — универсальная среда программирования читать онлайн бесплатно

Брайан Керниган - UNIX — универсальная среда программирования - читать книгу онлайн бесплатно, автор Брайан Керниган

Таблица 6.4: Полезные стандартные функции ввода-вывода

Упражнение 6.11

Модифицируйте zap так, чтобы можно было применять любое число аргументов. В настоящем виде zap высвечивает на экране строку, соответствующую выбранному варианту. Будет она делать это? Если нет, модифицируйте программу соответствующим образом. Подсказка: getpid(2).

Упражнение 6.12

Постройте fgrep(1) на основе strindex. Сравните время работы при сложных поисках, например 10 слов на документ. Почему fgrep выполняется быстрее?

6.8 Диалоговая программа сравнения файлов: idiff

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

В этом разделе мы напишем программу idiff (диалоговая diff), которая предоставляет пользователю каждую порцию выходного потока diff и предлагает ему возможность выбора фрагментов "от и до" или их редактирования. Программа idiff помещает выбранные фрагменты в соответствующем порядке в файл idiff.out. Допустим, даны такие два файла:

file1:            file2:

This is           This is

a test            not a test

of                of

your              our

skill             ability.

and comprehension.

diff вырабатывает следующее:

$ diff file1 file2

2c2

< a test

---

> not a test

4,6c4,5

< your

< skill

< and comprehension.

---

> our

> ability.

$

Диалог с idiff может выглядеть так:

$ idiff file1 file2

2c2 Первое различие

< a test

---

> not a test

? >             Пользователь выбрал вторую версию

4,6с4,5         Второе различие

< your

< skill

< and comprehension.

---

> our

> ability.

? <             Пользователь выбрал первую (<) версию

idiff output in file idiff.out

$ 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 <stdio.h>

#include <ctype.h>

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);

   printf("!\n");

   break;

  default:

   printf("< or > or e or !\n");

   break;

  }

 } while (buf[0]!='<' && buf[0]!='>' && buf[0]!='e');

 nf1 = to1;

 nf2 = to2;

 ncopy(f1, HUGE, fout); /* can fail on very long files */

 unlink(tempfile);

}

Функция parse выполняет рутинную, но тонкую работу по разбору строк, выдаваемых diff, извлекая четыре номера строки и команду (одну из а, с или d). При этом parse немного усложняется, так как diff может выдать либо один номер строки, либо два с той или другой стороны буквы команды:

parse(s, pfrom1, pto1, pcmd, pfrom2, pto2)

 char *s;

 int *pcmd, *pfrom1, *pto1, *pfrom2, *pto2;

{

#define a2i(p) while (isdigit(*s)) p = 10*(p) + *s++ - '0'

 *pfrom1 = *pto1 = *pfrom2 = *pto2 = 0;

 a2i(*pfrom1);

 if (*s == ',') {

  s++;

  a2i(*pto1);

 } else

  *pto1 = *pfrom1;

 *pcmd = *s++;

 a2i(*pfrom2);

 if (*s == ',') {

  s++;

  a2i(*pto2);

 } else

  *pto2 = *pfrom2;

}

Макрокоманда a2i выполняет специальное преобразование из ASCII в целое в тех четырех местах, где она встречается.

Функции nskip и ncopy пропускают или копируют указанное число строк из файла:

nskip(fin, n) /* skip n lines of file fin */

 FILE *fin;

{

 char buf[BUFSIZ];

 while (n-- > 0)

  fgets(buf, sizeof buf, fin);

}

ncopy(fin, n, fout) /* copy n lines from fin to fout */

 FILE *fin, *fout;

{

 char buf[BUFSIZ];

 while (n-- > 0) {

  if (fgets(buf, sizeof buf, fin) == NULL)

   return;

  fputs(buf, fout);

 }

}

Программа idiff, если ее прервать, оставляет несколько файлов, хранящихся в /tmp. В следующей главе мы покажем, как перехватывать прерывания, чтобы убрать временные файлы, подобные использованным здесь.

Если критически подойти к zap и idiff, то оказывается, что самая трудная работа была уже кем-то сделана ранее. Эти программы только обеспечивают удобное взаимодействие с другой программой, которая обрабатывает нужную информацию. Всегда имеет смысл воспользоваться плодами чужих трудов это позволяет повысить эффективность своей работы.

Перейти на страницу:
Вы автор?
Жалоба
Все книги на сайте размещаются его пользователями. Приносим свои глубочайшие извинения, если Ваша книга была опубликована без Вашего на то согласия.
Напишите нам, и мы в срочном порядке примем меры.
Комментарии / Отзывы
    Ничего не найдено.