Чтение онлайн

на главную - закладки

Жанры

Linux программирование в примерах

Роббинс Арнольд

Шрифт:

23 while (fgets(p, end - р, ebuf->fp) != 0)

24 {

25 char *p2;

26 unsigned long len;

27 int backslash;

28

29 len = strlen(p);

30 if (len == 0)

31 {

32 /* Это случается лишь тогда, когда первый символ строки '\0'.

33 Это довольно безнадежный случай, но (верите или нет) ляп Афины

34 бьет снова! (xmkmf помещает NUL в свои makefile.)

35
Здесь на самом деле нечего делать; мы создаем новую строку, чтобы

36 следующая строка не была частью данной строки. */

37 error (&ebuf->floc,

38 _("warning: NUL character seen; rest of line ignored"));

39 p[0] = '\n';

40 len = l;

41 }

Функция

fgets
(строка 23) принимает указатель на буфер, количество байтов для прочтения и переменную
FILE*
для файла, из которого осуществляется чтение. Она читает на один байт меньше указанного, чтобы можно было завершить буфер символом '
\0
'. Эта функция подходит, поскольку она позволяет избежать переполнения буфера. Она прекращает чтение, когда встречается с символами конца строки или конца файла; если это символ новой строки, он помещается в буфер. Функция возвращает
NULL
при неудаче или значение указателя первого аргумента при успешном завершении.

В этом случае аргументами являются указатель на свободную область буфера, размер оставшейся части буфера и указатель

FILE
для чтения.

Комментарии в строках 32–36 очевидны; если встречается нулевой байт, программа выводит сообщение об ошибке и представляет вывод как пустую строку. После компенсирования нулевого байта (строки 30–41) код продолжает работу.

43 /* Обойти только что прочитанный текст. */

44 p += len;

45

46 /* Если последний символ - не конец строки, она не поместилась

47 целиком в буфер. Увеличить буфер и попытаться снова. */

48 if (p[-1] != '\n')

49 goto more_buffer;

50

51 /* Мы получили новую строку, увеличить число строк. */

52 ++nlines;

Строки 43–52 увеличивают указатель на участок буфера за только что прочитанными данными. Затем код проверяет, является ли последний прочитанный символ символом конца строки. Конструкция

p[-1]
(строка 48) проверяет символ перед p, также как
p[0]
является текущим символом, а
p[1]
— следующим. Сначала это кажется странным, но если вы переведете это на язык математики указателей,
*(p-1)
, это приобретет больший смысл, а индексированная форма, возможно, проще для чтения.

Если последний символ не был символом конца строки, это означает, что нам не хватило места, и код выходит (с помощью

goto
) для увеличения размера буфера (строка 49). В противном случае увеличивается число строк.

54 #if !defined(WINDOWS32) && !defined(__MSDOS__)

55 /* Проверить, что строка завершилась CRLF; если так,

56 игнорировать CR. */

57 if ((p - start) > 1 && p[-2] == '\r')

58 {

59 --p;

60 p[-1] = '\n';

61 }

62 #endif

Строки 54–62 обрабатывают вводимые строки, следующие

соглашению Microsoft по завершению строк комбинацией символов возврата каретки и перевода строки (CR-LF), а не просто символом перевода строки (новой строки), который является соглашением Linux/Unix. Обратите внимание, что
#ifdef
исключает этот код на платформе Microsoft, очевидно, библиотека
<stdio.h>
на этих системах автоматически осуществляет это преобразование. Это верно также для других не-Unix систем, поддерживающих стандартный С.

64 backslash = 0;

65 for (p2 = p - 2; p2 >= start; --p2)

66 {

67 if (*p2 != '\\')

68 break;

69 backslash = !backslash;

70 }

71

72 if (!backslash)

73 {

74 p[-1] = '\0';

75 break;

76 }

77

78 /* Это была комбинация обратный слеш/новая строка. Если есть

79 место, прочесть еще одну строку. */

80 if (end - p >= 80)

81 continue;

82

83 /* В конце буфера нужно больше места, поэтому выделить еще.

84 Позаботиться о сохранении текущего смещения в p. */

85 more_buffer:

86 {

87 unsigned long off = p - start;

88 ebuf->size *= 2;

89 start = ebuf->buffer=ebuf->bufstart=(char*)xrealloc(start,

90 ebuf->size);

91 p = start + off;

92 end = start + ebuf->size;

93 *p = '\0';

94 }

95 }

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

backslash
из 0 в 1 и обратно. (Строки 64–70.)

Если число четное, условие '

!backshlash
' (строка 72) будет истинным. В этом случае конечный символ конца строки замещается байтом NUL, и код выходит из цикла.

С другой стороны, если число нечетно, строка содержит четное число пар обратных слешей (представляющих символы \\, как в С), и конечную комбинацию символов обратного слеша и конца строки. [43] В этом случае, если в буфере остались по крайней мере 80 свободных байтов, программа продолжает чтение в цикле следующей строки (строки 78–81). (Использование магического числа 80 не очень здорово; было бы лучше определить и использовать макроподстановку.)

43

Этот код несет с собой аромат практического опыта, не удивительно было узнать, что более ранние версии просто проверяли наличие обратного слеша перед символом конца строки, пока кто-то не пожаловался, что он не работает, когда в конце строки есть несколько обратных слешей — Примеч. автора.

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

Моя на одну ночь

Тоцка Тала
Любовные романы:
современные любовные романы
короткие любовные романы
5.50
рейтинг книги
Моя на одну ночь

Черный Маг Императора 8

Герда Александр
8. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Черный Маг Императора 8

Измена. Отбор для предателя

Лаврова Алиса
1. Отбор для предателя
Фантастика:
фэнтези
5.00
рейтинг книги
Измена. Отбор для предателя

Кодекс Крови. Книга II

Борзых М.
2. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Крови. Книга II

Шаг в бездну

Муравьёв Константин Николаевич
3. Перешагнуть пропасть
Фантастика:
фэнтези
космическая фантастика
7.89
рейтинг книги
Шаг в бездну

Часовая битва

Щерба Наталья Васильевна
6. Часодеи
Детские:
детская фантастика
9.38
рейтинг книги
Часовая битва

Вечная Война. Книга II

Винокуров Юрий
2. Вечная война.
Фантастика:
юмористическая фантастика
космическая фантастика
8.37
рейтинг книги
Вечная Война. Книга II

Хроники странного королевства. Вторжение. (Дилогия)

Панкеева Оксана Петровна
110. В одном томе
Фантастика:
фэнтези
9.38
рейтинг книги
Хроники странного королевства. Вторжение. (Дилогия)

Часовой ключ

Щерба Наталья Васильевна
1. Часодеи
Фантастика:
фэнтези
9.36
рейтинг книги
Часовой ключ

Инвестиго, из медика в маги

Рэд Илья
1. Инвестиго
Фантастика:
фэнтези
городское фэнтези
попаданцы
5.00
рейтинг книги
Инвестиго, из медика в маги

Кротовский, может, хватит?

Парсиев Дмитрий
3. РОС: Изнанка Империи
Фантастика:
попаданцы
альтернативная история
аниме
7.50
рейтинг книги
Кротовский, может, хватит?

Драконий подарок

Суббота Светлана
1. Королевская академия Драко
Любовные романы:
любовно-фантастические романы
7.30
рейтинг книги
Драконий подарок

Очешуеть! Я - жена дракона?!

Амеличева Елена
Фантастика:
юмористическая фантастика
5.43
рейтинг книги
Очешуеть! Я - жена дракона?!

Идеальный мир для Лекаря 9

Сапфир Олег
9. Лекарь
Фантастика:
боевая фантастика
юмористическое фэнтези
6.00
рейтинг книги
Идеальный мир для Лекаря 9