Системное программирование в UNIX средствами Free Pascal

Пример: гостиница


В качестве несколько надуманного, но возможно наглядного примера, предположим, что имеется файл residents, в котором записаны фамилии постояльцев гостиницы. Первая строка содержит фамилию жильца комнаты 1, вторая – жильца комнаты 2 и т.д. (очевидно, это гостиница с прекрасно организованной системой нумерации комнат). Длина каждой строки составляет ровно 41 символ, в первые 40 из которых записана фамилия жильца, а 41-й символ является символом перевода строки для того, чтобы файл можно было вывести на дисплей при помощи команды UNIX cat.

Следующая функция getoccupier вычисляет по заданному целому номеру комнаты положение первого байта фамилии жильца, затем перемещается в эту позицию и считывает данные. Она возвращает либо указатель на строку с фамилией жильца, либо нулевой указатель в случае ошибки (мы будем использовать для этого значение nil). Обратите внимание, что мы присвоили переменной дескриптора файла infile исходное значение –1. Благодаря этому мы можем гарантировать, что файл будет открыт всего один раз.

(* Функция getoccupier - получить фамилию из файла residents *)

uses linux;

const

  NAMELENGTH=41;

var

  namebuf:array [0..NAMELENGTH-1] of char;     (* Буфер для фамилии *)

const

  infile:integer=-1;         (* Для хранения дескриптора файла *)

function getoccupier(roomno:integer):pchar;

var

  offset, nread:longint;



begin

  (* Убедиться, что файл открывается впервые *)

  if infile = -1 then

  begin

    infile := fdopen ('residents', Open_RDWR);

    if infile = -1 then

    begin

      getoccupier := nil;          (* Невозможно открыть файл *)

      exit;

    end;

  end;

  offset := (roomno - 1) * NAMELENGTH;

  (* Найти поле комнаты и считать фамилию жильца *)

  if fdseek (infile, offset, SEEK_SET) = -1 then

  begin

    getoccupier := nil;

    exit;

  end;

  nread := fdread (infile, namebuf, NAMELENGTH);

  if nread <= 0 then

  begin

    getoccupier := nil;

    exit;




  end;

  (* Создать строку, заменив символ перевода строки на '\0' *)

  namebuf[nread - 1] := #0;

  getoccupier := namebuf;

end;

Если предположить, что в гостинице 10 комнат, то следующая программа будет последовательно вызывать функцию getoccupier для просмотра файла и выводить каждую найденную фамилию при помощи процедуры writeln из стандартного модуля system:

(* Программа listoc выводит все фамилии жильцов *)

const

  NROOMS=10;

var

  j:integer;

  p:pchar;

begin

  for j := 1 to NROOMS do

  begin

    p := getoccupier (j);

    if p<>nil then

      writeln('Комната ', j:2, ', ', p)

    else

      writeln('Ошибка для комнаты ', j);

  end;

end.

Упражнение 2.9. Придумайте алгоритм для определения пустых комнат. Измените функцию getoccupier и файл данных, если это необходимо, так, чтобы он отражал эти изменения. Затем напишите процедуру с названием findfree для поиска свободной комнаты с наименьшим номером.

Упражнение 2.10. Напишите процедуру freeroom для удаления записи о жильце. Затем напишите процедуру addguest для внесения новой записи о жильце, с предварительной проверкой того, что выделяемая комната свободна.

Упражнение 2.11. Объедините процедуры getoccupier, freeroom, addguest и findfree в простой программе с названием frontdesk, которая управляет файлом данных. Используйте аргументы командной строки или напишите интерактивную программу, которая вызывает функции writeln и readln. В обоих случаях для вычисления номера комнаты вам потребуется преобразовывать строки в целые числа. Вы можете использовать для этого библиотечную процедуру StrToInt:

i := StrToInt(str);

где string – указатель на строку символов, а i

– целое число.

Упражнение 2.12. В качестве обобщенного примера напишите программу на основе системного вызова fdseek, которая копирует в обратном порядке байты из одного файла в другой. Насколько эффективным получилось ваше решение?

Упражнение 2.13. Используя вызов fdseek, напишите процедуры для копирования последних 10 символов, последних 10 слов и последних 10 строк из одного файла в другой.


Содержание раздела