- •Системное программирование в unix средствами Free Pascal
- •Глава 1. Основные понятия и терминология 13
- •Глава 2. Файл 17
- •Глава 3. Работа с файлами 43
- •Глава 4. Каталоги, файловые системы и специальные файлы 62
- •Глава 5. Процесс 86
- •Глава 6. Сигналы и их обработка 117
- •Глава 7. Межпроцессное взаимодействие при помощи программных каналов 139
- •Глава 8. Дополнительные методы межпроцессного взаимодействия 163
- •Глава 9. Терминал 196
- •Глава 10.Сокеты 224
- •Глава 11. Стандартная библиотека ввода/вывода 239
- •Глава 12. Разные дополнительные системные вызовы и библиотечные процедуры 267
- •Глава 13. Задачи с решениями 287
- •Предисловие о книге
- •Назначение этой книги
- •Спецификация х/Open
- •Структура книги
- •Что вы должны знать
- •Соглашения
- •Глава 1. Основные понятия и терминология
- •1.1. Файл
- •1.1.1. Каталоги и пути
- •1.1.2. Владелец файла и права доступа
- •1.1.3. Обобщение концепции файла
- •1.2. Процесс
- •1.2.1. Межпроцессное взаимодействие
- •1.3. Системные вызовы и библиотечные подпрограммы
- •Глава 2. Файл
- •2.1. Примитивы доступа к файлам в системе unix
- •2.1.1. Введение
- •2.1.2. Системный вызовfdopen
- •Описание
- •Предостережение
- •2.1.3. Создание файла при помощи вызоваfdopen
- •Описание
- •2.1.4. Системный вызов fdcreat
- •Описание
- •2.1.5. Системный вызовfdclose
- •Описание
- •2.1.6. Системный вызовfdread
- •Описание
- •Указатель чтения-записи
- •2.1.7. Системный вызовfdwrite
- •Описание
- •2.1.8. Пример copyfile
- •2.1.9. Эффективность вызововfdread иfdwrite
- •Описание
- •2.1.10. Вызов fdseek и произвольный доступ
- •Описание
- •2.1.11. Пример: гостиница
- •2.1.12. Дописывание данных в конец файла
- •2.1.13. Удаление файла
- •Описание
- •2.1.14. Системный вызов fcntl
- •Описание
- •2.2. Стандартный ввод, стандартный вывод и стандартный вывод диагностики
- •2.2.1. Основные понятия
- •2.2.2. Программа io
- •2.2.3. Использование стандартного вывода диагностики
- •2.3. Стандартная библиотека ввода/вывода: взгляд в будущее
- •Описание
- •Вывод сообщений об ошибках при помощи функции writeln
- •2.4. Системные вызовы и переменнаяlinuxerror
- •2.4.7. Подпрограмма perror
- •Глава 3. Работа с файлами
- •3.1. Файлы в многопользовательской среде
- •3.1.1. Пользователи и права доступа
- •Действующие идентификаторы пользователей и групп
- •3.1.2. Права доступа и режимы файлов
- •Описание
- •3.1.3. Дополнительные права доступа для исполняемых файлов
- •3.1.4. Маска создания файла и системный вызов umask
- •Описание
- •3.1.5. Вызовfdopen и права доступа к файлу
- •3.1.6. Определение доступности файла при помощи вызова access
- •Описание
- •3.1.7. Изменение прав доступа при помощи вызова chmod Описание
- •3.1.8. Изменение владельца при помощи вызова chown
- •Описание
- •3.2. Файлы с несколькими именами
- •3.2.1. Системный вызов link Описание
- •3.2.2. Системный вызов unlink
- •3.2.3. Системный вызов frename
- •Описание
- •3.2.4. Символьные ссылки
- •Описание
- •Описание
- •3.2.5. Еще об именах файлов
- •Описание
- •3.3. Получение информации о файле: вызов fstat
- •Описание
- •Описание
- •3.3.1. Подробнее о вызове chmod
- •Глава 4. Каталоги, файловые системы и специальные файлы
- •4.1. Введение
- •4.2. Каталоги с точки зрения пользователя
- •Текущий рабочий каталог
- •4.3. Реализация каталогов
- •4.3.1. Снова о системных вызовах link и unlink
- •4.3.2. Точка и двойная точка
- •4.3.3. Права доступа к каталогам
- •4.4. Использование каталогов при программировании
- •4.4.1. Создание и удаление каталогов
- •Описание
- •Описание
- •4.4.2. Открытие и закрытие каталогов
- •Описание
- •Описание
- •4.4.3. Чтение каталогов: вызовы readdir и rewinddir
- •Описание
- •Описание
- •Второй пример: процедура find_entry
- •4.4.4. Текущий рабочий каталог
- •4.4.5. Смена рабочего каталога при помощи вызова chdir Описание
- •4.4.6. Определение имени текущего рабочего каталога
- •Описание
- •Описание
- •4.4.7. Обход дерева каталогов
- •Описание
- •Описание
- •4.5. Файловые системы unix
- •4.5.1. Кэширование: вызовы sync и fsync
- •Описание
- •4.6. Имена устройств unix
- •4.6.1. Файлы блочных и символьных устройств
- •4.6.2. Структураtstat
- •4.6.3. Информация о файловой системе
- •Описание
- •4.6.4. Ограничения файловой системы: процедуры pathconf и fpathconf
- •Описание
- •Глава 5. Процесс
- •5.1. Понятие процесса
- •5.2. Создание процессов
- •5.2.1. Системный вызов fork
- •Описание
- •Идентификатор процесса
- •5.3. Запуск новых программ при помощи вызова ехес
- •5.3.1. Семейство вызовов ехес
- •Описание
- •Вызовы execv, execlpи execvp
- •5.3.2. Доступ к аргументам, передаваемым при вызове exec
- •5.4. Совместное использование вызовов ехес и fork
- •Пример docommand
- •5.5. Наследование данных и дескрипторы файлов
- •5.5.1. Вызов fork,файлы и данные
- •5.5.2. Вызов ехес и открытые файлы
- •5.6. Завершение процессов при помощи системного вызова halt Описание
- •5.7. Синхронизация процессов
- •5.7.1. Системный вызов wait Описание
- •5.7.2. Ожидание завершения определенного потомка: вызов waitpid
- •Описание
- •5.8. Зомби-процессы и преждевременное завершение программы
- •5.9. Командный интерпретатор smallsh
- •5.10. Атрибуты процесса
- •5.10.1. Идентификатор процесса
- •5.10.2. Группы процессов и идентификаторы группы процессов
- •Описание
- •5.10.3. Изменение группы процесса
- •Описание
- •5.10.4. Сеансы и идентификатор сеанса
- •Описание
- •Описание
- •5.10.5. Переменные программного окружения
- •Описание
- •5.10.6. Текущий рабочий каталог
- •5.10.7. Текущий корневой каталог
- •Описание
- •5.10.8. Идентификаторы пользователя и группы
- •5.10.9. Ограничения на размер файла: вызов ulimit
- •Описание
- •5.10.10. Приоритеты процессов
- •Описание
- •Глава 6. Сигналы и их обработка
- •6.1. Введение
- •6.1.1. Имена сигналов
- •6.1.2. Нормальное и аварийное завершение
- •6.2. Обработка сигналов
- •6.2.1. Наборы сигналов
- •Описание
- •6.2.2. Задание обработчика сигналов: вызов sigaction
- •Описание
- •Пример 1: перехват сигнала sigint
- •Пример 2: игнорирование сигнала sigint
- •Пример 3: восстановление прежнего действия
- •Пример 4: аккуратный выход
- •6.2.3. Сигналы и системные вызовы
- •6.2.4. Процедуры sigsetjmpи siglongjmp
- •Описание
- •6.3. Блокирование сигналов
- •Описание
- •6.4. Посылка сигналов
- •6.4.1. Посылка сигналов другим процессам: вызов kill
- •Описание
- •6.4.2. Посылка сигналов самому процессу: вызовы sigraiseи alarm
- •Описание
- •Описание
- •6.4.3. Системный вызов pause
- •Описание
- •6.4.4. Системные вызовы sigpending и sigsuspend
- •Описание
- •Глава 7. Межпроцессное взаимодействие при помощи программных каналов
- •7.1. Каналы
- •7.1.1. Каналы на уровне команд
- •7.1.2. Использование каналов в программе
- •Описание
- •7.1.3. Размер канала
- •7.1.4. Закрытие каналов
- •7.1.5. Запись и чтение без блокирования
- •7.1.6. Использование системного вызова select для работы с несколькими каналами
- •Описание
- •Описание
- •Описание
- •7.1.7. Каналы и системный вызов ехес
- •7.2. Именованные каналы, или fifo
- •7.2.1. Программирование при помощи каналов fifo
- •Описание
- •Глава 8. Дополнительные методы межпроцессного взаимодействия
- •8.1. Введение
- •8.2. Блокировка записей
- •8.2.1. Мотивация
- •8.2.2. Блокировка записей при помощи вызова fcntl
- •Описание
- •Установка блокировки при помощи вызова fcntl
- •Снятие блокировки при помощи вызова fcntl
- •Задача об авиакомпании acme Airlines
- •Проверка блокировки
- •8.3. Дополнительные средства межпроцессного взаимодействия
- •8.3.1. Введение и основные понятия
- •Ключи средств межпроцессного взаимодействия
- •Описание
- •Операция get
- •Другие операции
- •Структуры данных статуса
- •8.3.2. Очереди сообщений
- •Описание
- •Работа с очередью сообщений: примитивы msgsndи msgrcv
- •Описание
- •Пример передачи сообщений: очередь с приоритетами
- •Программа etest
- •Программа stest
- •Системный вызов msgctl
- •Описание
- •8.3.3. Семафоры Семафор как теоретическая конструкция
- •Системный вызов semget Описание
- •Системный вызов semctl Описание
- •Операции над семафорами: вызов semop
- •Описание
- •Флаг sem_undo
- •Пример работы с семафорами
- •8.3.4. Разделяемая память
- •Системный вызов shmget
- •Описание
- •Операции с разделяемой памятью: вызовы shmat и shmdt
- •Описание
- •Системный вызов shmctl Описание
- •Пример работы с разделяемой памятью: программа shmcopy
- •8.3.5. Команды ipcsи ipcrm
- •Глава 9. Терминал
- •9.1. Введение
- •9.2. Терминал unix
- •9.2.1. Управляющий терминал
- •9.2.2. Передача данных
- •9.2.3. Эхо-отображение вводимых символов и опережающий ввод с клавиатуры
- •9.2.4. Канонический режим, редактирование строки и специальные символы
- •9.3. Взгляд с точки зрения программы
- •9.3.1. Системный вызовfdopen
- •9.3.2. Системный вызов fdread
- •9.3.3. Системный вызов fdwrite
- •9.3.4. Функции ttynameи isatty
- •Описание
- •9.3.5. Изменение свойств терминала: структура termios
- •Описание
- •Описание
- •Определение структуры termios
- •Массив с_сс
- •Поле c_cflag
- •Описание
- •Поле c_iflag
- •Поле c_oflag
- •Поле с_lflag
- •Описание
- •9.3.6. Параметры min и time
- •9.3.7. Другие системные вызовы для работы с терминалом
- •Описание
- •9.3.8. Сигнал разрыва соединения
- •9.4. Псевдотерминалы
- •9.5. Пример управления терминалом: программа tscript
- •Глава 10.Сокеты
- •10.1. Введение
- •10.2. Типы соединения
- •10.3. Адресация
- •10.3.1. Адресация Internet
- •Описание
- •10.3.2. Порты
- •10.4. Интерфейс сокетов
- •10.4.1. Создание сокета
- •Описание
- •10.5. Программирование в режиме tcp-соединения
- •10.5.1. Связывание
- •Описание
- •10.5.2. Включение приема tcp-соединений
- •Описание
- •10.5.3. Прием запроса на установку tcp-соединения
- •Описание
- •10.5.4. Подключение клиента
- •Описание
- •10.5.5. Пересылка данных
- •Описание
- •10.5.6. Закрытие tcp-соединения
- •10.6. Программирование в режиме пересылок udp-дейтаграмм
- •10.6.1. Прием и передача udp-сообщений
- •Описание
- •10.7. Различия между двумя моделями
- •Глава 11. Стандартная библиотека ввода/вывода
- •11.1. Введение
- •11.2. Структура tfile
- •11.3. Открытие и закрытие потоков: процедуры fopenи fclose Описание
- •Описание
- •11.4. Посимвольный ввод/вывод: процедуры getc и putc Описание
- •11.5. Возврат символов в поток: процедура ungetc Описание
- •11.6. Стандартный ввод, стандартный вывод и стандартный вывод диагностики
- •11.7. Стандартные процедуры опроса состояния
- •Описание
- •11.8. Построчный ввод и вывод
- •Описание
- •Описание
- •11.9. Ввод и вывод бинарных данных: процедуры freadи fwrite Описание
- •11.10. Произвольный доступ к файлу: процедуры fseek, rewindи ftell
- •Описание
- •11.11. Форматированный вывод: семейство процедур printf Описание
- •Задание ширины поля и точности
- •Комплексный пример
- •Специальные символы
- •Процедура sprintf
- •11.12. Форматированный ввод: семейство процедур scanf Описание
- •11.13. Запуск программ при помощи библиотек стандартного ввода/вывода
- •Описание
- •Описание
- •11.14. Вспомогательные процедуры
- •11.14.1. Процедуры freopen и fdopen Описание
- •11.14.2. Управление буфером: процедуры setbufи setvbuf Описание
- •Глава 12. Разные дополнительные системные вызовы и библиотечные процедуры
- •12.1. Введение
- •12.2. Управление динамическим распределением памяти
- •Описание
- •Описание
- •Описание
- •Пример использования функции malloc:связные списки
- •Вызовы brk и sbrk
- •12.3. Ввод/вывод с отображением в память и работа с памятью
- •Описание
- •Системные вызовы ттар и munmap
- •Описание
- •Описание
- •12.4. Время
- •Описание
- •Описание
- •12.5. Работа со строками и символами
- •12.5.1. Семейство процедур strings
- •Описание
- •12.5.2. Преобразование строк в числовые значения
- •Описание
- •12.5.3. Проверка и преобразование символов
- •12.6. Дополнительные средства
- •12.6.1. Дополнение о сокетах
- •12.6.2. Потоки управления
- •Описание
- •12.6.3. Расширения режима реального времени
- •12.6.4. Получение параметров локальной системы
- •12.6.5. Интернационализация
- •12.6.6. Математические функции
- •12.6.7. Работа с портами ввода вывода
- •Глава 13. Задачи с решениями
- •13.1. Введение
- •13.2. Обработка текста
- •13.3. Бинарные файлы
- •13.4. Каталоги
- •13.5. Файловые системы
- •13.6. Файловая системаproc
- •13.7. Управление файлами
- •13.8. Управление процессами
- •13.9. Программные каналы
- •13.10. Управление терминалом
- •13.11. Дата и время
- •13.12. Генератор лексических анализаторовlex
- •Приложение 1. Коды ошибок переменной linuxerror и связанные с ними сообщения Введение
- •Список кодов и сообщений об ошибках
- •Приложение 2. История unix
- •Основные стандарты
- •Ieee/posix
- •Приложение 3. Модульstdio
- •Приложение4. Замечания о компиляции воFree Pascal 2.0
- •Литература
13.12. Генератор лексических анализаторовlex
Упражнение 13.66. Составьте вариант программы подсчета служебных слов языка Си, не учитывающий появление этих слов, заключенных в кавычки.
%{
uses lexlib;
const
_AND=1;
_ASM=2;
_ARRAY=3;
_BEGIN=4;
_CASE=5;
_CONST=6;
_CONSTRUCTOR=7;
_DESTRUCTOR=8;
_DIV=9;
_DO=10;
_DOWNTO=11;
_ELSE=12;
_END=13;
_EXPORTS=14;
_FILE=15;
_FOR=16;
_FUNCTION=17;
_GOTO=18;
_IF=19;
_IMPLEMENTATION=20;
_IN=21;
_INHERITED=22;
_INLINE=23;
_INTERFACE=24;
_LABEL=25;
_LIBRARY=26;
_MOD=27;
_NIL=28;
_NOT=29;
_OBJECT=30;
_OF=31;
_OR=32;
_PACKED=33;
_PROCEDURE=34;
_PROGRAM=35;
_RECORD=36;
_REPEAT=37;
_SET=38;
_SHL=39;
_SHR=40;
_STRING=41;
_THEN=42;
_TO=43;
_TYPE=44;
_UNIT=45;
_UNTIL=46;
_USES=47;
_VAR=48;
_WHILE=49;
_WITH=50;
_XOR=51;
_STR=52;
_IDENT=53;
%}
letter [a-zA-Z]
digit [0-9]
%%
'[^']*' begin yydone:=true; yyretval:=_STR; end;
\"[^\"]\" begin yydone:=true; yyretval:=_STR; end;
"end." begin yydone:=true; yyretval:=_END; end;
and begin yydone:=true; yyretval:=_AND; end;
asm begin yydone:=true; yyretval:=_ASM; end;
array begin yydone:=true; yyretval:=_ARRAY; end;
begin begin yydone:=true; yyretval:=_BEGIN; end;
case begin yydone:=true; yyretval:=_CASE; end;
const begin yydone:=true; yyretval:=_CONST; end;
constructor begin yydone:=true; yyretval:=_CONSTRUCTOR; end;
destructor begin yydone:=true; yyretval:=_DESTRUCTOR; end;
div begin yydone:=true; yyretval:=_DIV; end;
do begin yydone:=true; yyretval:=_DO; end;
downto begin yydone:=true; yyretval:=_DOWNTO; end;
else begin yydone:=true; yyretval:=_ELSE; end;
end begin yydone:=true; yyretval:=_END; end;
exports begin yydone:=true; yyretval:=_EXPORTS; end;
file begin yydone:=true; yyretval:=_FILE; end;
for begin yydone:=true; yyretval:=_FOR; end;
function begin yydone:=true; yyretval:=_FUNCTION; end;
goto begin yydone:=true; yyretval:=_GOTO; end;
if begin yydone:=true; yyretval:=_IF; end;
implementation begin yydone:=true; yyretval:=_IMPLEMENTATION; end;
in begin yydone:=true; yyretval:=_IN; end;
inherited begin yydone:=true; yyretval:=_INHERITED; end;
inline begin yydone:=true; yyretval:=_INLINE; end;
interface begin yydone:=true; yyretval:=_INTERFACE; end;
label begin yydone:=true; yyretval:=_LABEL; end;
library begin yydone:=true; yyretval:=_LIBRARY; end;
mod begin yydone:=true; yyretval:=_MOD; end;
nil begin yydone:=true; yyretval:=_NIL; end;
not begin yydone:=true; yyretval:=_NOT; end;
object begin yydone:=true; yyretval:=_OBJECT; end;
of begin yydone:=true; yyretval:=_OF; end;
or begin yydone:=true; yyretval:=_OR; end;
packed begin yydone:=true; yyretval:=_PACKED; end;
procedure begin yydone:=true; yyretval:=_PROCEDURE; end;
[pP][rR][oO][gG][rR][aA][mM] begin yydone:=true; yyretval:=_PROGRAM; end;
record begin yydone:=true; yyretval:=_RECORD; end;
repeat begin yydone:=true; yyretval:=_REPEAT; end;
set begin yydone:=true; yyretval:=_SET; end;
shl begin yydone:=true; yyretval:=_SHL; end;
shr begin yydone:=true; yyretval:=_SHR; end;
string begin yydone:=true; yyretval:=_STRING; end;
then begin yydone:=true; yyretval:=_THEN; end;
to begin yydone:=true; yyretval:=_TO; end;
type begin yydone:=true; yyretval:=_TYPE; end;
unit begin yydone:=true; yyretval:=_UNIT; end;
until begin yydone:=true; yyretval:=_UNTIL; end;
uses begin yydone:=true; yyretval:=_USES; end;
var begin yydone:=true; yyretval:=_VAR; end;
while begin yydone:=true; yyretval:=_WHILE; end;
with begin yydone:=true; yyretval:=_WITH; end;
xor begin yydone:=true; yyretval:=_XOR; end;
{letter}({letter}|{digit})* begin yydone:=true; yyretval:=_IDENT; end;
\n ;
. ;
%%
function yywrap:integer;
begin
yywrap:=1;
end;
const
words:array[_AND.._XOR] of string=(
'AND',
'ASM',
'ARRAY',
'BEGIN',
'CASE',
'CONST',
'CONSTRUCTOR',
'DESTRUCTOR',
'DIV',
'DO',
'DOWNTO',
'ELSE',
'END',
'EXPORTS',
'FILE',
'FOR',
'FUNCTION',
'GOTO',
'IF',
'IMPLEMENTATION',
'IN',
'INHERITED',
'INLINE',
'INTERFACE',
'LABEL',
'LIBRARY',
'MOD',
'NIL',
'NOT',
'OBJECT',
'OF',
'OR',
'PACKED',
'PROCEDURE',
'PROGRAM',
'RECORD',
'REPEAT',
'SET',
'SHL',
'SHR',
'STRING',
'THEN',
'TO',
'TYPE',
'UNIT',
'UNTIL',
'USES',
'VAR',
'WHILE',
'WITH',
'XOR' );
var
kwcount:array [1..51] of integer;
token,i:integer;
begin
if paramcount<>1 then
begin
writeln('Используйте: ', paramstr(0), ' файл');
exit;
end;
assign(yyinput,paramstr(1));
{$I-}
reset(yyinput);
if ioresult<>0 then
begin
writeln('Ошибка открытия для чтения ', paramstr(1));
exit;
end;
for i:=_AND to _XOR do
kwcount[i]:=0;
token:=yylex;
while not eof(yyinput) do
begin
if token in [_AND.._XOR] then
inc(kwcount[token]);
token:=yylex;
end;
if token in [_AND.._XOR] then
inc(kwcount[token]);
for i:=_AND to _XOR do
if kwcount[i]<>0 then
writeln('Слово ', words[i], ' встречается ', kwcount[i], ' раз');
close(yyinput);
end.
Упражнение 13.67. Составьте программу удаления из программы на языке Си всех комментариев. Обратите внимание на особые случаи со строками в кавычках и символьными константами; так строка char s[] = "/*"; не является началом комментария! Комментарии записывайте в отдельный файл.
%{
uses lexlib;
const
STROKA=1;
COMMENT=2;
ANY=3;
ENTER=4;
%}
%%
'[^']*' begin yyretval:=STROKA; yydone:=true; end;
\"[^"]*\" begin yyretval:=STROKA; yydone:=true; end;
"end." begin yyretval:=STROKA; yydone:=true; end;
\n begin yyretval:=ENTER; yydone:=true; end;
. begin yyretval:=ANY; yydone:=true; end;
"{"[^"}"]*"}" begin yyretval:=COMMENT;yydone:=true; end;
"/*""/"*([^*/]|[^*]"/"|"*"[^/])*"*"*"*/" begin
yyretval:=COMMENT;yydone:=true;
end;
"(*""("*([^*)]|[^*]")"|"*"[^)])*"*"*"*)" begin
yyretval:=COMMENT;yydone:=true;
end;
"//"[^\n]*\n begin yyretval:=COMMENT;yydone:=true; end;
%%
(*
function yywrap:boolean;
begin
writeln('end?');
yywrap:=true;
end;
*)
var
token:integer;
fresult,fcomment:text;
begin
if paramcount<>3 then
begin
writeln('Используйте: ', paramstr(0), ' исходный_файл результирующий_файл извлеченные_комментарии');
exit;
end;
assign(yyinput,paramstr(1));
{$I-}
reset(yyinput);
if ioresult<>0 then
begin
writeln('Ошибка открытия для чтения ', paramstr(1));
exit;
end;
assign(fresult,paramstr(2));
rewrite(fresult);
if ioresult<>0 then
begin
writeln('Ошибка создания ', paramstr(2));
exit;
end;
assign(fcomment,paramstr(3));
rewrite(fcomment);
if ioresult<>0 then
begin
writeln('Ошибка создания ', paramstr(3));
exit;
end;
token:=yylex;
while not eof(yyinput) do
begin
if token=COMMENT then
writeln(fcomment,yytext)
else
write(fresult,yytext);
token:=yylex;
end;
write(fresult,yytext);
close(yyinput);
close(fcomment);
close(fresult);
end.