Linux программирование в примерах | страница 63
В этом случае аргументами являются указатель на свободную область буфера, размер оставшейся части буфера и указатель >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, очевидно, библиотека >
на этих системах автоматически осуществляет это преобразование. Это верно также для других не-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 /* В конце буфера нужно больше места, поэтому выделить еще.