Брайан Керниган - UNIX — универсальная среда программирования Страница 54
- Категория: Компьютеры и Интернет / Программное обеспечение
- Автор: Брайан Керниган
- Год выпуска: -
- ISBN: -
- Издательство: -
- Страниц: 103
- Добавлено: 2019-06-19 14:37:03
Брайан Керниган - UNIX — универсальная среда программирования краткое содержание
Прочтите описание перед тем, как прочитать онлайн книгу «Брайан Керниган - UNIX — универсальная среда программирования» бесплатно полную версию:В книге американских авторов — разработчиков операционной системы UNIX — блестяще решена проблема автоматизации деятельности программиста, системной поддержки его творчества, выходящей за рамки языков программирования. Профессионалам открыт богатый "встроенный" арсенал системы UNIX. Многочисленными примерами иллюстрировано использование языка управления заданиями shell.Для программистов-пользователей операционной системы 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, то оказывается, что самая трудная работа была уже кем-то сделана ранее. Эти программы только обеспечивают удобное взаимодействие с другой программой, которая обрабатывает нужную информацию. Всегда имеет смысл воспользоваться плодами чужих трудов это позволяет повысить эффективность своей работы.
Жалоба
Напишите нам, и мы в срочном порядке примем меры.