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
, то оказывается, что самая трудная работа была уже кем-то сделана ранее. Эти программы только обеспечивают удобное взаимодействие с другой программой, которая обрабатывает нужную информацию. Всегда имеет смысл воспользоваться плодами чужих трудов это позволяет повысить эффективность своей работы.
Упражнение 6.13
Добавьте команду q к idiff
: ответ q с автоматически выберет остаток от альтернатив '<'
; q > возьмет все оставшееся от альтернатив '>'
.
Упражнение 6.14
Модифицируйте idiff
так, чтобы некоторые аргументы idiff
передавались к diff
; -b
и -h
вероятные кандидаты. Выполните еще одну модификацию idiff
, позволяющую определять другой редактор, как в команде
$ idiff -е другой редактор file1 file2
Как взаимодействуют эти две модификации?
Упражнение 6.15
Измените idiff
, чтобы использовать popen
и pclose
вместо временного файла для выходного потока diff
. Как это скажется на сложности и скорости выполнения программы?
Упражнение 6.16
Если один из аргументов diff
-каталог, то в этом каталоге идет поиск файла с именем, заданным другим аргументом. Но если вы попробуете сделать то же самое с idiff
, то она почему-то собьётся. Объясните, что в данном случае происходит, и исправьте дефект.
Из Си-программы легко "добраться" до переменных в среде shell
, что можно использовать для упрощения адаптации программы к окружению. Допустим, например, что размер экрана вашего терминала больше обычного (24-строкового). Чего вы сможете добиться, применив p и воспользовавшись преимуществами своего терминала? Необходимость определять размер экрана всякий раз, когда вы вводите p
, надоедает:
$ p -36...
Вы могли бы всегда вставлять файл shell
в свой bin
:
$ cat /usr/you/bin/p
exec /usr/bin/p -36 $*
$
Третье решение модифицировать p
, чтобы использовать те переменные среды, которые определяют свойства вашего терминала. Предположим, что вы определили переменную PAGESIZE
в своем .profile
:
PAGESIZE=36
export PAGESIZE
Функция getenv("var")
ищет в среде командную переменную var и возвращает ее значение как строку символов или NULL
, если переменная не определена. При наличии getenv
легко модифицировать p: достаточно лишь добавить пару описаний и вызов getenv
к началу основной программы.
/* p: print input in chunks (version 3) */
...
char *p, *getenv();
progname = argv[0];
if ((p=getenv("PAGESIZE")) != NULL)
pagesize = atoi(p);
if (argc > 1 && argv[1][0] == '-') {
pagesize = atoi(&argv[1][1]);
argc--;
argv++;
}
Флаги обрабатываются вслед за переменной среды, так что любой явно заданный размер страницы в конце концов заменит неявно заданный.
Упражнение 6.17
Модифицируйте idiff
так, чтобы она искала в среде имя редактора, который следует применить. Измените 2, 3 и т.д., чтобы использовать PAGESIZE
.
Историческая и библиографическая справка
Стандартная библиотека ввода-вывода была разработана Д. Ритчи вслед за переносимой библиотекой ввода вывода М. Леска. Оба пакета имели целью предоставить пользователю стандартные средства, чтобы можно было переносить программы без изменений с UNIX в другие системы.
Наша версия p
основана на программе Г. Спенсера. Программа adb
написана С. Борном, sdb
Г. Катцефом, a lint
С. Джонсоном.
Читать дальше
Конец ознакомительного отрывка
Купить книгу