Брайан Керниган - UNIX — универсальная среда программирования
- Название:UNIX — универсальная среда программирования
- Автор:
- Жанр:
- Издательство:Финансы и статистика
- Год:1992
- Город:Москва
- ISBN:5-289-00253-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Брайан Керниган - UNIX — универсальная среда программирования краткое содержание
В книге американских авторов — разработчиков операционной системы UNIX — блестяще решена проблема автоматизации деятельности программиста, системной поддержки его творчества, выходящей за рамки языков программирования. Профессионалам открыт богатый "встроенный" арсенал системы UNIX. Многочисленными примерами иллюстрировано использование языка управления заданиями shell.
Для программистов-пользователей операционной системы UNIX.
UNIX — универсальная среда программирования - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Непосредственное выполнение команды p
осуществляется в print
:
print(fp, pagesize) /* print fp in pagesize chunks */
FILE *fp;
int pagesize;
{
static int lines = 0; /* number of lines so far */
char buf[BUFSIZ];
while (fgets(buf, sizeof buf, fp) != NULL)
if (++lines < pagesize)
fputs(buf, stdout);
else {
buf[strlen(buf)-1] = '\0';
fputs(buf, stdout);
fflush(stdout);
ttyin();
lines = 0;
}
}
Мы использовали здесь BUFSIZ
, который определен в как размер буфера входного потока. Функция fgets(buf, size, fp)
выбирает следующую строку входного потока из fp
до символа перевода строки (включая его) в буфер и добавляет завершающий символ \0
. Копируется на более size - 1
символов. По достижении конца файла возвращается NULL
. (Конструкция fgets
оставляет желать лучшего: она возвращает buf
вместо счетчика символов и, кроме того, выдает предупреждение о том, что входная строка была слишком длинной. Символы не потеряны, но вы должны взглянуть на buf
, чтобы понять, что в самом деле случилось.)
Функция strlen
возвращает длину строки, поэтому мы можем отбросить завершающий символ перевода строки последней входной строки. После вызова fputs(buf, fp)
строка buf
записана в файл fp
. При вызове fflush
в конце страницы происходит вывод буферизованного выходного текста.
Считывание ответа пользователя в конце каждой страницы возложено на функцию ttyin
. Функция ttyin
не может читать стандартный входной поток, тогда как p
должна выполняться, даже если входной поток поступает из файла или конвейера. Чтобы справиться с этим, программа открывает файл /dev/tty
, которому поставлен в соответствие пользовательский терминал при любом переключении стандартного входного потока. Приведенная ниже функция ttyin
возвращает первую букву ответа, но здесь это свойство не используется.
ttyin() /* process response from /dev/tty (version 1) */
{
char buf[BUFSIZ];
FILE *efopen();
static FILE *tty = NULL;
if (tty == NULL)
tty = efopen("/dev/tty", "r");
if (fgets(buf, BUFSIZ, tty) == NULL || buf[0] == 'q')
exit(0);
else /* ordinary line */
return buf[0];
}
Указатель на файл devtty
описан как статический, так что его значение сохраняется от одного вызова ttyin
до другого; файл /dev/tty
открывается только при первом вызове.
Очевидно, есть дополнительные средства, которые без особых усилий можно ввести в p
, однако наша первая версия этой программы только печатает 22 строки и ждет следующей порции. Прошло немало времени, прежде чем в нее были добавлены другие средства, но в настоящее время ими мало кто пользуется. В частности, весьма простое дополнение ввод переменной pagesize
для хранения числа строк на странице. Значение переменной можно установить из командной строки
$ p -n...
Она печатает порции по n
строк. Для этого требуется лишь добавить несколько знакомых вам операторов в начале main
:
/* p: print input in chunks (version 2) */
...
int i, pagesize = PAGESIZE;
progname = argv[0];
if (argc > 1 && argv[1][0] == '-') {
pagesize = atoi(&argv[1][1]);
argc--;
argv++;
}
Функция atoi
превращает строку символов в целое число (см. справочное руководство по atoi(3)
).
Еще одно средство временно остановить вывод на экран в конце каждой страницы, чтобы выполнить какую-либо иную команду. По аналогии с ed
и многими другими программами, если пользователь печатает строку, начинающуюся восклицательным знаком, остальная часть строки воспринимается как команда и передается shell
для выполнения. Данное средство также тривиально, поскольку для этой цели предусмотрена функция system(3)
, речь о которой пойдет ниже. Модифицированная версия ttyin
такова:
ttyin() /* process response from /dev/tty (version 2) */
{
char buf[BUFSIZ];
FILE *efopen();
static FILE *tty = NULL;
if (tty == NULL)
tty = efopen("/dev/tty", "r");
for (;;) {
if (fgets(buf,BUFSIZ,tty) == NULL || buf[0] == 'q')
exit(0);
else if (buf[0] == '!') {
system(buf+1); /* BUG here */
printf("!\n");
else /* ordinary line */
return buf[0];
}
}
К сожалению, эта версия ttyin
имеет серьезный недостаток. Команда, запущенная с помощью system
, получает стандартный входной поток от p
, так что если p
читает из программного канала или файла, их входные потоки могут мешать друг другу:
$ cat /etc/passwd | p -1
root:3d.fHR5KoB.3s:0:l:S.User:/:!ed
Вызвать ed из p
?
ed читает /etc/passwd
!
… запутывается и завершается
Для решения этой проблемы необходимо знать, как управлять процессами в UNIX, о чем речь пойдет в разд. 7.4. Пока же примите к сведению, что использование стандартной библиотечной функции system
может создать неприятности, однако ttyin
работает правильно, если компилируется с версией system
, описанной в гл. 7.
Итак, мы написали две программы vis
и p
, которые можно считать вариантами cat
с некоторыми "украшениями". Может быть, им следует быть частью cat
, доступной с помощью флагов -v
и -р
? Вопрос о том, писать ли новую программу или добавлять какие-то средства к старой, возникает всегда, как только у людей появляются новые идеи. Мы не можем со всей определенностью ответить на данный вопрос, но приведем здесь некоторые принципы, которые, возможно, вам помогут.
Основной принцип состоит в том, что программе следует выполнять только свою основную работу. Если у нее появляется слишком много функций, она становится большой, медленной, ее трудно сопровождать и использовать. В самом деле, ряд свойств часто остается невостребованным, поскольку пользователи никак не могут запомнить флаги.
Поэтому cat
и vis
совмещать не рекомендуется. Если cat
просто копирует входной поток без изменений, то vis
его трансформирует. Соединение их дает программу с двумя разными функциями. Это очевидно также для cat
и p
: cat
предназначена для быстрого эффективного копирования страниц, p
для их "перелистывания". Кроме того, p
преобразует выходной поток. Каждый 22-й символ перевода строки пропускается. Три отдельные программы представляются в таком случае правильным решением.
Работает ли p нормально, если pagesize
не является положительным?
Что еще можно было бы сделать с p
? Оцените и реализуйте (если оно вам подходит) свойство вновь выводить части ранее введенного текста. (Это дополнительное средство нам очень нравится.) Добавьте возможность выводить неполное содержимое экрана после каждой паузы, а также просматривать текст вперед или назад по строкам, задаваемым номером или содержимым.
Интервал:
Закладка: