6.4 Вывод на экран порциями: программа
pДо сих пор мы использовали cat для просмотра файлов. Но если файл длинный, а связь с системой высокоскоростная, cat выдает выходной файл слишком быстро, что затрудняет его чтение, даже если вы успеваете делать это с помощью ctl-s и ctl-q.
Очевидно, нужно иметь программу для печати файла небольшими удобными порциями, но такая программа не является стандартной, возможно, потому, что первоначальная система UNIX была написана в те времена, когда использовались терминалы "твердой копии" (печати на бумаге) и медленные линии связи. Поэтому наш следующий пример программа
ppp$ 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В самом деле, у нас оказывается слишком много средств, которые мы можем внести в программу. Лучше сделать "неоснащенную" версию, а затем развивать ее, как подскажет опыт. Иными словами, необходимые средства это те, которые действительно вам нужны, а не те, которые, по нашему мнению, вы хотели бы иметь.
Структура
pvisprint/* p: print input in chunks (version 1) */#include <stdio.h>#define PAGESIZE 22char *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);}Функция
efopenefopenprognamemainFILE *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);}Мы испытали две версии программы
efopenefopenefopenНепосредственное выполнение команды
pprintprint(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)