Вход/Регистрация
UNIX — универсальная среда программирования
вернуться

Керниган Брайан Уилсон

Шрифт:

$ p vis.с

...

$ grep '#define' *.[ch] | p

...

$

Эту программу легче всего писать на Си; стандартные средства неудобны, когда происходит смешанный ввод из файла или конвейера и с терминала. Решение состоит в том, чтобы печатать входной поток небольшими порциями. Удобный размер порции 22 строки, что составляет немногим меньше, чем размер в 24 строки на большинстве видеотерминалов, и одну треть стандартной страницы в 66 строк. Простой способ подсказки пользователю не печатать последний символ перевода строки каждой порции. Курсор остановится на правом конце строки, а не на левой границе (новой строки). При нажатии клавиши RETURN выполняется перевод строки, и следующая строка появляется в нужном месте. Если пользователь печатает ctl-d или q в конце экрана, выполнение программы

p
заканчивается.

Мы не станем принимать специальных мер для вывода длинных строк. Мы также не будем беспокоиться о множестве файлов: просто перейдем от одного к другому без примечаний. Следующая команда

$ p имена файлов...

по своему действию аналогична команде

$ cat имена файлов... | p

Если нужны имена файлов, их можно добавить циклом

for
:

$ for i in имена файлов

> do

> echo $i:

> cat $i

> done | p

В самом деле, у нас оказывается слишком много средств, которые мы можем внести в программу. Лучше сделать "неоснащенную" версию, а затем развивать ее, как подскажет опыт. Иными словами, необходимые средства это те, которые действительно вам нужны, а не те, которые, по нашему мнению, вы хотели бы иметь.

Структура

p
аналогична структуре
vis
: основная процедура выполняет цикл по файлам, вызывая функцию
print
, выполняющуюся с каждым файлом:

/* p: print input in chunks (version 1) */

#include <stdio.h>

#define PAGESIZE 22

char *progname; /* program name for error message */

main(argc, argv)

 int argc;

 char *argv[];

{

 int i;

 FILE *fp, *efopen;

 progname = argv[0];

 if (argc ==1)

print(stdin, PAGESIZE);

 else

for (i = 1; i < argc; i++) {

fp = efopen(argv[i], "r");

print(fp, PAGESIZE);

fclose(fp);

}

 exit(0);

}

Функция

efopen
реализует весьма общую операцию: пытается открыть файл. Если же это невозможно, она выводит на печать сообщение об ошибке, и ее выполнение завершается. Чтобы обеспечить выдачу сообщений об ошибках, идентифицирующих программу, в которой происходит (или произошла) ошибка,
efopen
ссылается на внешнюю строку
progname
, где содержится имя программы, устанавливаемое в
main
:

FILE *efopen(file, mode) /* fopen file, die if can't */

 char *file, *mode;

{

 FILE *fp, *fopen;

 extern char *progname;

 if ((fp = fopen(file, mode)) != NULL)

return fp;

 fprintf(stderr, "%s: can't open file %s mode %s\n",

progname, file, mode);

 exit(1);

}

Мы испытали две версии программы

efopen
, прежде чем остановиться на данной. Одна из них должна была после печати сообщения завершиться, возвратив нулевой указатель, свидетельствующий о неудаче. Это позволяет вызвавшей программе продолжить свое выполнение или завершиться. Другая версия снабжала
efopen
третьим аргументом, указывающим, следует ли возвращаться после того, как файл открыть не удалось. Почти во всех наших примерах, однако, нет смысла продолжать работу, если файл недоступен, так что текущая версия
efopen
является для нас наилучшей.

Непосредственное выполнение команды

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

  • Читать дальше
  • 1
  • ...
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: