Примеры, подобранные в настоящей главе, имеют общее свойство: они представляют собой небольшие "инструменты", которые используются регулярно, но не являются частью седьмой версии системы. Если ваша система обладает подобными программами, вам будет легче сравнивать системы. Если же вы с ними еще не знакомы, то они могут оказаться вам чрезвычайно полезными. Эти программы помогут вам понять, что совершенной системы не существует, и для того чтобы добиться улучшения и устранить те или иные дефекты, достаточно приложить лишь небольшие усилия
6.1 Стандартные входной и выходной потоки: программа vis
Многие программы читают только из одного входного потока и пишут в один выходной поток: для таких программ полностью подходят функции ввода-вывода, использующие лишь стандартные входной и выходной потоки, и для того чтобы начать работу, этого почти всегда достаточно.
Проиллюстрируем изложенное с помощью программы vis
, которая копирует свой стандартный входной поток в стандартный выходной, изображая при этом все непечатаемые символы в виде \nnn
, где nnn
— восьмеричное значение символа. Vis
полезна для обнаружения "посторонних" или нежелательных символов, которые могут попасть в файлы. Например, vis
будет печатать каждый символ "шаг назад" как \010, что является его восьмеричным значением:
$ cat x abc
$ vis < x
abc\010\010\010 ___
$
Чтобы просмотреть несколько файлов с помощью этой элементарной версии vis
, вы можете использовать cat
для сбора файлов
$ cat файл1 файл2 ... | vis
...
$ cat файл1 файл2 ... | vis | grep '\\'
...
и избежать тем самым выяснения способа доступа к файлам из программы.
Между прочим, может показаться, что подобную работу следует выполнить с привлечением sed
, поскольку команда '1'
выдает на экран непечатаемые символы в наглядном виде:
$ sed -n 1 x
abc←←←___
$
Результат выполнения программы sed
, вероятно, вам покажется яснее, чем результат выполнения vis
. Но применение sed
к нетекстовым файлам бессмысленно:
$ sed -n 1 /usr/you/bin
$
Ничего в ответ!
(Так получилось на PDP-11; в одной из систем для VAX sed
аварийно завершилась, возможно, потому, что ввод был воспринят как очень длинная текстовая строка.) Таким образом, sed
нам не подходит, и мы вынуждены писать новую программу.
Простейшие функции ввода и вывода getchar
и putchar
. При каждом вызове getchar
появляется очередной символ из стандартного входного потока, которому может быть поставлен в соответствие файл, конвейер или терминал (последнее принимается по умолчанию). Программа "не знает", что конкретно он собой представляет. Аналогично putchar(c)
помещает символ в стандартный выходной поток, который по умолчанию также связан с терминалом.
Функция printf(3)
выполняет форматное преобразование при выводе. Вызовы printf
и putchar
могут следовать в любом порядке; выходной поток отразит порядок этих вызовов. Для форматного преобразования входного потока предусмотрена функция scanf(3)
; она читает входной поток и разбивает его, как требуется, на строки, числа и т.п. Вызовы scanf
и getchar
также могут чередоваться.
Приведем первую версию vis
:
/* vis: make funny characters visible (version 1) */
#include
#include
main() {
int c;
while ((c = getchar()) != EOF)
if (isascii(c) &&
(isprint(с) || c=='\n' || c=='\t' || c==' '))
putchar(c);
else
printf("\\%03o", c);
exit(0);
}
Getchar
возвращает из входного потока очередной байт или значение EOF, когда встречает конец файла (или ошибку). Между прочим, EOF не является байтом из файла; вспомните: во второй главе объяснялось, что такое "конец файла". Значение EOF отличается от значения любого байта, поэтому его трудно спутать с реальными данными; переменная с описана как int
(целая), а; не как char
(символьная), так что она может хранить значение EOF. Строка
#include
должна находиться в начале каждого исходного файла. Это заставляет компилятор Си читать файл макроопределений ( /usr/include/stdio.h
), в котором специфицированы стандартные функции и имена, в том числе и EOF
. Мы будем использовать как краткую запись полного имени файла.
Файл — еще один файл макроопределений в /usr/include
, который задает машинно-независимые макрокоманды (макросы) для классификации символов. Чтобы выяснить, принадлежит ли входной символ набору ASCII (т.е. его значение меньше 0200) и печатается ли он, мы использовали здесь isascii
и isprint
. Остальные макросы перечислены в табл. 6.1. Отметим, что определяет символы "перевод строки", "табуляция" и пробел как непечатаемые.
Читать дальше
Конец ознакомительного отрывка
Купить книгу