UNIX — универсальная среда программирования
Шрифт:
> 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);
else {
buf[strlen(buf)-1] = '\0';
fputs(buf, stdout);
fflush(stdout);
ttyin;
lines = 0;
}
}
Мы
BUFSIZ
, который определен в <stdio.h>
как размер буфера входного потока. Функция 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
для хранения числа строк на странице. Значение переменной можно установить из командной строки
Поделиться:
Популярные книги
Газлайтер. Том 3
3. История Телепата
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Новик
2. Помещик
Фантастика:
альтернативная история
6.67
рейтинг книги
Иной. Том 3. Родственные связи
3. Иной в голове
Фантастика:
боевая фантастика
рпг
аниме
5.00
рейтинг книги
Последний Паладин. Том 2
2. Путь Паладина
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Бастард Императора. Том 14
14. Бастард Императора
Фантастика:
городское фэнтези
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Двойник Короля
1. Двойник Короля
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Камень. Книга 3
3. Камень
Фантастика:
фэнтези
боевая фантастика
8.58
рейтинг книги
Зауряд-врач
1. Зауряд-врач
Фантастика:
альтернативная история
8.64
рейтинг книги
Геном хищника. Книга пятая
5. Я - Легенда!
Фантастика:
рпг
фэнтези
попаданцы
6.00
рейтинг книги
Кодекс Крови. Книга II
2. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Изыскатель
5. Травник
Фантастика:
фэнтези
7.00
рейтинг книги
Главный рубильник. Расцвет и гибель информационных империй от радио до интернета
Деловая литература:
о бизнесе популярно
5.00
рейтинг книги
Адепт
4. Ушедший Род
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Я все еще барон
4. Дорогой барон!
Фантастика:
боевая фантастика
5.00