ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы.



 

Часть 8


                           МОДУЛЬ  SYSTEM
                           ==============

         Модуль SYSTEM играет особую роль в компиляторе JPI Modula-2,  т.к.  содержит зависящие
    от компилятора характеристики (а именно Ofs и Seg).  Действительно, некоторые процедуры яв-
    ляются встроенными в компилятор,  поэтому модуль также называется pseudo module (псевдо мо-
    дуль).
         SYSTEM также содержит типы данных, которые представляют интерес в этом конкретном при-
    менении.

         TYPE
           PROCESS   = ADDRESS;
           Registers = RECORD
                CASE : BOOLEAN OF
                | TRUE  : AX,BX,CX,DX,BP,SI,DI,DS,ES: CARDINAL;
                          Flags                     : BITSET;
                | FALSE : AL,AH,BL,BH,CL,CH,DL,DH   : SHORTCARD;
                END;
              END;
         CONST
           CarryFlag = 0;
           ZeroFlag  = 6;
         VAR
           HeapBase  : CARDINAL ;
                    (* Базовый сегмент динамической области *)

         Тип Registers  используется  при выдаче запросов ДОСа и в прерываниях,  т.к.  доступ к
    внутренним регистрам процессора необходим при осуществлении этих действий.
         Тип PROCESS объясняется ниже.

                      Низкоуровневые процессы
                      -----------------------

         Т.к. IBM PC/AT (и сравнимые с ним) являются компилятором с  единственным  процессором,
    действительно одновременные процессы не могут быть реализованы посредством сопрограмм.
         Сопрограмма - это последовательная программа,  которая может быть приостановлена путем
    передачи выполнения другой сопрограмме (которая будет возобновлена с того места,  в котором
    она была раньше приостановлена). Когда сопрограмма приостанавливается, ее текущее состояние
    сохраняется;  таким образом,  что она может возобновить свое выполнение позже, когда другая
    сопрограмма передаст выполнение обратно данной сопрограмме.
         В дальнейшем мы будем использовать термин процесс вместо сопрограммы.


             Система приоритетов модулей в JPI Мodula-2
             ------------------------------------------

         Система приоритетов модулей управляет обработкой аппаратных прерываний.  Система прио-
    ритетов основана на контроллере аппаратных прерываний в компьютере РС/АТ. Приоритет интерп-
    ретируется как маска (BITSET-установка бита),  который разрешает/запрещает отдельные преры-
    вания.  Прерывание запрещено,  если его соответствующий бит в маске установлен в  1.  Чтобы
    использовать систему приоритетов,  требуются некоторые знания о контроллере прерываний (см.
    "Технические ссылки"). На входе блока (тело PROCEDURE или тело MODULE), который имеет прио-
    ритет маски в контроллере прерываний и приоритет для блока,  которые логически объединяются
    вместе; на выходе из блока маска в контроллере прерываний восстанавливается в то состояние,
    которое она имела на входе блока.
         АТ и РС отличаются тем,  что АТ имеет 2 контроллера прерываний,  а РС - только 1, т.к.
    АТ использует все 16 бит маски приоритета; 8 младших бит используются для установки маски в
    первичном контроллере прерываний,  старшие 8 бит используются для установки главного  конт-
    роллера.  В  случае  РС только младшие 8 бит используются для установки маски в контроллере
    прерываний.
         Маска в контроллере прерываний считается частью состояния процесса; таким образом, она
    сохраняется и восстанавливается операциями TRANSFER и IOTRANSFER (см. процедуры ниже).
         Если IOTRANSFER связана с аппаратным прерыванием, обрабатываемым контроллером прерыва-
    ний, выдается неопределенный End-Of-Interrupt (конец прерывания).
         Запросы прерываний (IRQs),  обрабатываемые аппаратурой, классифицированы через вектора
    прерываний от 08Н до 0FH для первичного контроллера и от 70Н до 77Н для главного контролле-
    ра. Это соответствует запросам прерываний от IRQ 0 - IRQ 15.

         Пример обработки прерывания:

         MODULE T;
         FROM SYSTEM IMPORT NEWPROCESS, IOTRANSFER, TRANSFER,
                           CurrentPriority, NewPriority,
                           ADRESS;
         VAR IntProc : ADDRESS;
         MODULE Int[CARDINAL{3}]; (* IRQ 3 выключено *)
         IMPORT IOTRANSFER;
         EXPORT IntHandler;

          PROCEDURE IntHandler;
          BEGIN
            ...
            IOTRANSFER( ..., 0BH);
             (* IOTRANSFER на IRQ 3 (Прерывание 0BH) *)

          END IntHandler;
         END Int;
         BEGIN
           ...
           NEWPROCESS( ...,IntProc );
           TRANSFER( ...,IntProc );
           NewPriority(CARDINAL(BITSET(CurrentPriority())-{3}));
           (* включено IRQ 3 *)
         END T.


                             NEWPROCESS
                             ----------

         PROCEDURE NEWPROCESS ( P : PROC;
                                A : ADDRESS;
                                S : CARDINAL;
                             VAR P1: ADDRESS);

         Создает новый процесс.  Р - это лишенная параметров процедура,  которая образует новый
    процесс.  А - это указатель на рабочую область для процесса. Рабочая область необходима для
    локальных переменных и для хранения состояния процесса при его приостановке. S - это размер
    в байтах этой рабочей области.  NEWPROCESS возвращает ссылку на заново созданный процесс  в
    Р1.  Заметим,  что NEWPROCESS только приготавливает процесс для выполнения,  он не вызывает
    начало его выполнения.

                              TRANSFER
                              --------

         PROCEDURE TRANSFER(VAR P1,P2 : ADDRESS);

         Передает выполнение  от одного процесса другому.  Текущий процесс приостанавливается и
    назначается Р1,  и процесс Р2 возобновляется (в его текущей точке приостановки).  Р2 должен
    быть результатом предыдущего запроса к NEWPROCESS или TRANSFER.  Процесс Р1 будет возобнов-
    лен позже, когда другой процесс передает выполнение обратно ему.
         Заметим, что назначение Р1 происходит после идентификации нового процесса Р2. Это зна-
    чит, что действительные параметры могут быть идентичными.
         Этот тип передачи называется синхронной передачей,  что противоположно асинхронной пе-
    редаче, которая выполняется процедурой IOTRANSFER.

                             IOTRANSFER
                             ----------

         PROCEDURE IOTRANSFER(VAR P1,P2:  ADDRESS; I: CARDINAL);

         IOTRANSFER - это управляющая прерыванием (или асинхронная) передача. Она связывает те-
    кущий процесс с номером прерывания,  данным в I. Затем она приостанавливает текущий процесс
    и назначает его Р1 и активизирует процесс,  данный Р2. Когда процессор получает прерывание,
    он проверяет,  связано ли это прерывание с процессом.  Если это происходит, текущий процесс
    приостанавливается и назначается Р2, и (приостановленный) процесс Р1 возобновляется.
         Раз прерывание и результирующая IOTRANSFEER произошли вместе,  то прерывание не  будет
    больше связано с этим процессом.
         Если большее количество процессов связано с прерыванием I, они будут обработаны в сте-
    ке похожим образом,  т.е. последний процесс, связанный с I будет активизирован, когда прои-
    зойдет первое прерывание I,  второй от конца процесс будет активизирован,  когда произойдет
    следующее прерывание I, и т. д.

                        InterruptRegisters
                        ------------------

        PROCEDURE InterruptRegisters(P: ADDRESS) : ADDRESS;

         InterruptRegister может быть использован для доступа к  содержимому  регистров,  когда
    происходит прерывание. Вызывать ее имеет смысл только тогда, когда имеет место IOTRANSFER к
    процессу Р. Она возвращает указатель на запись (на стек) со следующим расположением:

         TYPE
           ExtendedRegisters = RECORD
                                r  : Registers;
                   (* как определено выше *)
                                IP : CARDINAL;
                   (* указатель команды *)
                                CS : CARDINAL;
                   (* кодовый сегмент *)
                                RetFlags : CARDINAL;
                              END;


                         CurrentProcess
                         --------------

         PROCEDURE CurrentProcess() : ADDRESS;

         Возвращает ссылку на текущий процесс.

                          CurrentPriority
                          ---------------

         PROCEDURE CurrentPriority() : CARDINAL;

         Возвращает (MODULE) приоритет текущего процесса.


                            NewPriority
                            -----------

         PROCEDURE NewPriority(PR : CARDINAL;

         Дает текущему процессу новый (MODULE) приоритет, определяемый PR, см. описание системы
    приоритетов выше.


                              Listen
                              ------

         PROCEDURE Listen(Mask: BITSET);

         Listen временно разрешает прерывания,  определенные с помощью Mask (маски), что разре-
    шает принимать ожидающие прерывания. Затем эта процедура восстанавливает маску прерываний в
    ее первоначальное состояние.


                          ПРОЧИЕ ПРОЦЕДУРЫ
                          ================

         Компилятор генерирует внутренний код для всех процедур в этом разделе.


                                DI
                                --

         PROCEDURE DI();

         Запрещает аппаратные прерывания.  Она полезна,  когда имеется доступ к данным, которые
    являются общими для нескольких процессов.


                                EI
                                --

         PROCEDURE EI();

         Разрешает аппаратные прерывания.


                                Ofs
                                ---

         PROCEDURE Ofs(VAR A: WORD) : CARDINAL;

         Возвращает смещение адреса А.  Заметим,  что адреса состоят из смещения (Ofs) и адреса
    сегмента; физический адрес вычисляется как seg * 16 + ofs.


                                Seg
                                ---

         PROCEDURE Seg(VAR A: WORD) : CARDINAL;

         Возвращает адрес сегмента адреса А.


                                Out
                                ---

         PROCEDURE Out(P: CARDINAL; V: SHORTCARD);

         Выводит значение V в аппаратный порт Р.

                                In
                                --

         PROCEDURE In(P: CARDINAL) : SHORTCARD;

         Возвращает значение из аппаратного порта Р.


                              GetFlags
                              --------

         PROCEDURE GetFlags() : CARDINAL;

         Возвращает регистр флагов процессора.


                              SetFlags
                              --------

         PROCEDURE SetFlags(F: CARDINAL);

         Устанавливает регистр флагов процессора в значение, определенное с помощью F. Процеду-
    ры SetFlags и GetFlags особенно полезны при запрещениях и разрешениях прерываний,  для сох-
    ранения и восстановления предварительных значений флагов.


                           МОДУЛЬ Process
                           ==============

         Процедуры в этом модуле обрабатывают одновременные процессы.  Т.к. JPI Мodula-2 реали-
    зуется  на однопроцессорном компьютере,  процессы делят между собой процессорное время пос-
    редством time-slicinq (разделение времени). Другие (более низкого уровня) процедуры процес-
    са могут быть найдены в модуле SYSTEM.


                       ПЛАНИРОВЩИК ПРОЦЕССОВ
                       =====================

                           StartScheduler
                           --------------

         PROCEDURE StartScheduler;

         Запускает процедуру разделения времени.  Если она уже активна, этот запрос действия не
    имеет.

                           StopScheduler
                           -------------

         PROCEDURE StopScheduler:

         Останавливает процедуру разделения времени. Заметим, что операции SEND и WAIT функцио-
    нируют до тех пор, пока процедура не остановится (см. "СИГНАЛЫ" ).

                            StartProcess
                            ------------

         PROCEDURE StartProcess(P: PROC;  N:  CARDINAL;
                                         Pr: CARDINAL);

         Cоздает новый процесс, который выражается процедурой Р. Процесс будет распределять ра-
    бочую область размером N байт (N должен быть не более 1КБ). Каждый процесс имеет приоритет,
    который не должен быть перепутан с приоритетом MODULE. Pr - это приоритет процесса и должен
    быть больше нуля.  Если Pr больше или равен приоритету текущего процесса, то заново создан-
    ный процесс станет активным.


                              СИГНАЛЫ
                              =======

         Процессы могут  взаимодействовать  двумя  различными путями:  или благодаря глобальным
    разделяемым переменным, или благодаря сигналам. Сигналы используются для синхронизации про-
    цессов.  Кроме  инициализации,  следующие операции могут быть выполнены на сигналах:  SEND,
    WAIT, Notify, и Awaited. Сигнал состоит из двух категорий: счетчик и очередь.


                                Init
                                ----
         TYPE SIGNAL;
         PROCEDURE Init (VAR s: SIGNAL );

         Инициализирует сигнал s ( т.е. его счетчик установлен в 0, и очередь пуста).

                                SEND
                                ----

         PROCEDURE SEND (s: SIGNAL );

         Запрос SEND сделает активным 1-ый процесс,  ждущий s. Если никаких процессов не ожида-
    ется, запрос будет поставлен в очередь.
         Операция SEND работает посредством возрастания счетчика,  связанным с s.  Если счетчик
    < = 0,  то, по крайней мере, 1 процесс ждет s и 1-ый процесс в очереди будет готов к выпол-
    нению.  Этот  процесс также начнет выполняться,  если его приоритет > = приоритета текущего
    процесса.

                                Wait
                                ----

         PROCEDURE WAIT ( s: SIGNAL);

         Запрос WAIT заставляет запрашиваемый процесс ждать соответственно SEND,  если сигнал s
    не имеет предварительно поставленных в очередь операций SEND.
         Процедура WAIT уменьшает счетчик,  cвязанный с s.  Если счетчик меньше 0,  это значит,
    что запрашиваемый процесс должен ждать соответствующий SEND в s, и другой процесс будет ак-
    тивизирован.  Если счетчик больше или равен 0, то запрашиваемый процесс будет продолжаться.

                               Notify
                               ------

         PROCEDURE Notify (s: SIGNAL);


         Заставляет задачу,  ждущую сигнал s, регистрироваться, когда возможно, т.е в следующий
    момент времени.  Если никакой процесс не ждет s, то запрос не действует. Этот запрос не вы-
    зывает перерегистрацию,  таким образом, он может использоваться устройством управления пре-
    рыванием (см.ГЛАВУ 7), чтобы безопасно обозначить другой процесс в момент, когда происходит
    событие.

                              Awaited
                              -------

         PROCEDURE Awaited (s: SIGNAL): BOOLEAN;

         Возвращает TRUE (истина),  если любой процесс ждет сигнал s (т.е.,  если счетчик, свя-
    занный с s, отрицателен).


                          ПРОЧИЕ ПРОЦЕДУРЫ
                          ================

                               Delay
                               -----

         PROCEDURE Delay (t : CARDINAL);

         Задерживает текущий процесс по меньшей мере на t интервалов времени.  Интервал времени
    приблизительно 1/18 с. Если t=0, перерегистрация имеет место без задержки, разрешая другому
    процессу с таким же или большим приоритетом стать активным.


                                Lock
                                ----

         PROCEDURE Lock;

         Lock предотвращает текущий процесс от перерегистрации с помощью интервала  времени  до
    тех пор, пока не будет запрошен Unlock. Это полезно, когда процесс использует данные, кото-
    рые разделяются между несколькими процессами.  Запросы их к Lock  могут  быть  вложены,  но
    должны быть всегда спарены с запросами UnLock.

                               Unlock
                               ------

         PROCEDURE Unlock;

         Unlock разрешает перерегистрацию в интервал времени,  и должен быть  всегда  спарен  с
    запросом Lock. Текущий процесс будет перерегистрирован, если в готовности находится процесс
    такого же или большего приоритета.

         Пример:

         Процесс работы с клавиатурой:

     MODULE KBP;
     IMPORT Process,IO;
     VAR
     (*$W+*)
       KBbuff : ARRAY[0..1023] OF CHAR;
                   (* циклический буфер *)
       KBhead  : CARDINAL;
       KBtail  : CARDINAL;
       KeyReady: Process.SIGNAL;
     (*$W=*)
     PROCEDURE KBProcess;
     VAR
       k : CHAR;
       p : CARDINAL;
     BEGIN
       LOOP
         Process.Lock;  (* Общие и ДОС-переменные использованы *)
         IF IO.KeyPressed()  THEN
           k := IO.RdCharDirect();
           p := (KBhead+1)MOD SIZE(KBbuff);
           IF p <> KBtail THEN
              KBbuff[KBhead] := k; KBhead := p;
           END;
           Process.Unlock;
           IF Process.Awaited(KeyReady)  THEN
             Process.SEND(KeyReady)
           END;
         ELSE
           Process.Unlock;
         END;
       END;
     END KBProcess;

     PROCEDURE GetKey() : CHAR;
     VAR k : CHAR;
     BEGIN
       LOOP
         Process.Lock; (* Глобальные общие переменные
                                         использованы *)
         IF KBtail<>KBhead THEN
           k := KBbuff[KBtail];
           KBtail := (KBtail+1)MOD SIZE(KBbuff);
           Process.Unlock;
           RETURN k;
         END;
           Process.Unlock;
           Process.WAIT(KeyReady);
       END;
     END GetKey;

     PROCEDURE InitKBProcess;
     BEGIN
       KBhead := 0;
       KBtail := 0;
       Process.Init(KeyReady);
       Process.StartProcess(KBProcess,1000,1);
       Process.StartScheduler;
     END InitKBProcess;

     VAR c : CHAR;
       BEGIN
         InitKBProcess;
         LOOP
           c :=GetKey();
           Process.Lock;  (* поскольку процедура IO.WrChar
                              вызывает ДОС *)
           IO.WrChar(c);
           Process.Unlock;
           IF c=CHR(27) THEN EXIT END;
       END;
     END KBP.


                           МОДУЛЬ MATHLIB
                           ==============

         Процедуры из этого модуля выполняют общие математические вычисления.  Кроме того,  мо-
    дуль содержит некоторые процедуры, специфичные для микропроцессора Intel 8087.


                         ОБРАБОТКА ОШИБОК
                         ================

         В случае  ошибочных  аргументов некоторые процедуры вызывают функции обработки ошибок,
    определенные ниже:

         MODULE MATHLIB

         VAR
           MathError : PROCEDURE (LONGREAL, ARRAY OF CHAR);
           MathError2 :  PROCEDURE (LONGREAL,  LONGREAL,
                                    ARRAY OF CHAR);

         Отмечаем, что процедуры обработки ошибок являются переменными типа "Процедура",  кото-
    рые могут быть заменены процедурами, определенными пользователем. По умолчанию они присвое-
    ны процедурам MathError и MathError2 в модуле Lib.
         Процедуры обработки ошибок вызываются:

         MathError             Sin, Cos, Tan, Asin, Acos, Log,
                               Log10, Sqrt.
         MathError2            ATan2.

                    Тригонометрические функции
                    --------------------------

         PROCEDURE Sin(A : LONGREAL) : LONGREAL;
         PROCEDURE Cos(A : LONGREAL) : LONGREAL;
         PROCEDURE Tan(A : LONGREAL) : LONGREAL;
         PROCEDURE ASin(A : LONGREAL) : LONGREAL;
         PROCEDURE ACos(A : LONGREAL) : LONGREAL;
         PROCEDURE ATan(A : LONGREAL) : LONGREAL;
         PROCEDURE ATan2(X,Y : LONGREAL) : LONGREAL;

         Sin, Cos  и  Tan осуществляют соответствующие математические функции.  Аргумент А этих
    процедур определен в радианах. Sin и Cos возвращают значения в диапазоне от -1 до 1.
         ASin, ACos и ATan возвращают арксинус,  арккосинус и арктангенс соответственно.  Аргу-
    мент А у ASin и ACos должен быть в диапазоне от -1 до 1.  ASin возвращает значения в диапа-
    зоне  от  -pi/2 до pi/2.  ACos возвращает значения в диапазоне от 0 до pi.  ATan возвращает
    значения в диапазоне от -pi/2 до pi/2.
         ATan2 возвращает арктангенс от X/Y. Результат - в диапазоне от -pi до pi.

                      Гиперболические функции
                      -----------------------

         PROCEDURE SinH(A : LONGREAL) : LONGREAL;
         PROCEDURE CosH(A : LONGREAL) : LONGREAL;
         PROCEDURE TanH(A : LONGREAL) : LONGREAL;

         Эти процедуры возвращают гиперболический синус,  гиперболический косинус и  гиперболи-
    ческий тангенс соответственно переданного аргумента А.


                      Натуральный логарифм
                      --------------------

         PROCEDURE Log(A: LONGREAL) : LONGREAL;

         Возвращает натуральный логарифм (по основанию е) аргумента А.

                      Десятичный логарифм
                      -------------------

         PROCEDURE Log10(A : LONGREAL) : LONGREAL;

         Возвращает логарифм (по основанию 10) аргумента А.

                           Степень числа
                           -------------

         PROCEDURE Pow(X,Y : LONGREAL) : LONGREAL;

         Возвращает X, возведенный в степень Y.

                             Экспонента
                             ----------

         PROCEDURE Exp(A : LONGREAL) : LONGREAL;

         Возвращает результат  возведения  е  в  степень  А (эта
    функция обратна Log).

                               Модуль
                               ------

         PROCEDURE Mod(X,Y : LONGREAL) : LONGREAL;

         Возвращает X, являющийся абсолютной величиной Y.

                                Rexp
                                ----

         PROCEDURE Rexp(VAR I: INTEGER; A: LONGREAL) : LONGREAL;

         Разбивает значение А на его экспоненту и мантиссу с помещением экспоненты в I,  а ман-
    тисса - значение, возвращаемое функцией.

                         Квадратный корень
                         -----------------

         PROCEDURE Sqrt(A: LONGREAL) : LONGREAL;

         Возвращает квадратный корень аргумента А.


                     ПРОЦЕДУРЫ ПРЕОБРАЗОВАНИЯ
                     ========================

         Две процедуры, приведенные ниже, преобразуют целую часть вещественного значения в дво-
    ично-десятичное число и наоборот. Двоично-десятичное число представлено типом PackedBcd:

         TYPE PackedBcd = ARRAY [0..9] OF SHORTCARD;

         Две десятичные цифры упакованы в каждый элемент массива. Элемент номер 9 является зна-
    ком.


                             LongToBcd
                             ---------

         PROCEDURE LongToBcd(A: LONGREAL) : PackedBcd;

         Возвращает значение А в виде PackedBcd. А округляется к ближайшему целому. Например,

         a := LongToBcd(-12345.67);

         После этого вызова будем иметь значение:

         элемент:            9  8  7  6  5  4  3  2  1  0
         шестнадцатеричное
         значение:          80  0  0  0  0  0  0  1  23 46


                             BcdToLong
                             ---------

         PROCEDURE BcdToLong(A: PackedBcd) : LONGREAL;

         Возвращает LONGREAL представленные значения PackedBcd, заданного посредством А.


                    ПРОЦЕДУРЫ СОПРОЦЕССОРА 8087
                    ===========================

         За описанием  управляющего слова и среды микропроцессора 8087 обратитесь к вашей доку-
    ментации по 8087.

                          LoadControlWord
                          ---------------

         PROCEDURE LoadControlWord(C: BITSET);

         Загружает сопроцессор 8087 с управляющим словом, заданным посредством С.

                          StoreControlWord
                          ----------------

         PROCEDURE StoreControlWord() : BITSET;

         Возвращает управляющее слово микропроцессора 8087.

                          ClearExceptions
                          ---------------

         PROCEDURE ClearExceptions();

         Стирает флаги  исключения,  флаг запроса прерывания и флаг занятости в слове состояния
    микропроцессора 8087.


                          StoreEnvironment
                          ----------------

         TYPE
           Environment = RECORD
                           ControlWord : BITSET;
                           StatusWord  : BITSET;
                           TagWord     : BITSET;
                           IP          : CARDINAL;
                           Opcode      : CARDINAL;
                           DataPointer : CARDINAL;
                           R80287      : CARDINAL;
                         END;

         PROCEDURE StoreEnvironment() : Environment;

         Возвращает среду процессора 8087, описанную посредством типа Environment. Смотри также
    документацию по сопроцессору 8087.

                            МОДУЛЬ FIO
                            ==========

         Процедуры этого модуля используются для обработки файлов и файлового ввода/вывода. FIO
    также содержит процедуры для обработки директорий.
         Файлу ставится в соответствие файловая позиция, которая изменяется при операциях запи-
    си и чтения. Первая позиция в файле - 0.
         Файлы являются последовательными,  но прямой доступ к конкретным элементам в файле мо-
    жет быть достигнут посредством процедуры Seek.
         Перед тем, как файл может быть прочитан или записан, он должен быть открыт использова-
    нием одной из процедур Open,  Create или Append.  Эти процедуры все возвращают  управляющую
    переменную файла, которая используется во всех последующих обращениях к этому файлу. Откры-
    тые файлы должны быть закрыты процедурой Close перед окончанием работы программы  или когда
    они не будут более использоваться.


                    ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ В FIO
                    ===========================

         Эти переменные  используются для управления поведением и проверки результатов процедур
    обработки файла и процедур ввода/вывода.

         CONST
           MaxOpenFiles = 15;
           DiskFull = 0F0H; (* Ошибка, если при записи файлов
                               диск переполнен. *)
           StandardInput = 0;  (* MS-DOS-стандартные номера
                                  файлов. *)
           StandardOutput = 1;
           ErrorOutput    = 2;
           AuxDevice      = 3;
           PrinterDevice  = 4;
         TYPE
           File  = CARDINAL;  (* Тип файлового номера. *)
         VAR
           EOF        : BOOLEAN;
           IOcheck    : BOOLEAN; (* Если TRUE - ошибочное
                завершение программы с сообщением. *)
           Separators : Str.CHARSET;
           OK         : BOOLEAN;
           ChopOff    : BOOLEAN;
           Eng        : BOOLEAN; (* Инженерное представление. *)

         Предопределенные MS-DOS-овские  стандартные  номера файлов именуются от 0 до 4 как это
    определено выше посредством констант.  Пользовательские файлы нумеруются от 5  до  значения
    MaxOpenFiles. Файлы, отмеченные стандартными номерами, определены, когда программа начинает
    выполнение, и не требуют открытия перед использованием.
         Булевская переменная ОК устанавливается всеми процедурами форматированного ввода/выво-
    да: WrBin и RdBin. Она указывает, была ли успешной предпринятая операция.
         Если сделана попытка записи форматированных данных в меньшую область, чем специфициро-
    вано,  то записывается последовательность '?', если ChopOff - TRUE; в противном случае опи-
    санный размер поля превышается. ChopOff по умолчанию - FALSE.
         EOF устанавливается,  если конец файла был достигнут во время последней операции  чте-
    ния.
         Separators - множество разделителей данных,  использующихся в процедуре RdItem. Значе-
    ние по умолчанию:

         CHARSET{CHR(9), CHR(13), CHR(26), ' '}.

         Eng устанавливается, если вещественные числа сформатированы в инженерном представлении
    (см. RealToStr). По умолчанию Eng - FALSE.
         Если IOcheck - TRUE,  то ошибки,  которые случатся во время выполнения процедур, пере-
    численных ниже,  будут завершать программу с выдачей сообщения об ошибке.  Если  IOcheck  -
    FALSE,  ошибки  вместо  этого  могут  быть проверены посредством вызова процедуры IOresult.
    IOcheck по умолчанию TRUE. Следующие процедуры вызовут сообщения об ошибках, если IOcheck -
    TRUE:   Open,   Append,  Create,  Close,  Truncate,  GetPos,  Seek,  Size,  Erase,  Rename,
    ReadFirstEntry, ReadNextEntry, ChDir, MkDir, RmDir, GetDir.


                          ОБРАБОТКА ФАЙЛОВ
                          ================

         Файлы являются по умолчанию небуферизованными,  т.е. ДОС доступна для выполнения в лю-
    бое  время операция чтения или записи.  Для достижения большей эффективности ввода/вывода с
    файлом нужно связать буфер при помощи процедуры AssignBuffer с тем, чтобы пропускать к ДОС-
    у большие порции данных.

                                Open
                                ----

         PROCEDURE Open(Name: ARRAY OF CHAR) : File;


         Открывает файл  Name  для чтения или записи и возвращает основу множества операций над
    файлом.  Позиция файла устанавливается на начало файла. Если IOcheck - FALSE и специфициро-
    ванный файл не может быть открыт, возвращается значение MAX(CARDINAL).

                               Append
                               ------

         PROCEDURE Append(Name: ARRAY OF CHAR) : File;


         Открывает файл  Name,  устанавливает позицию файла на конец файла,  и возвращает номер
    открытого файла (или MAX(CARDINAL),  если файл не был успешно открыт).  Выполнение операций
    записи в непустой файл,  открытый посредством Append,  будет добавлять данные в файл вместо
    того, чтобы перезаписывать их.

                               Create
                               ------

         PROCEDURE Create(Name: ARRAY OF CHAR) : File;

         Создает файл,  специфицированный посредством Name, и возвращает номер этого файла (или
    MAX(CARDINAL),  если файл не был успешно создан). Если файл уже существует, то предшествую-
    щее содержимое его теряется. Созданный файл открывается для операций чтения или записи.

                               Close
                               -----

         PROCEDURE Close(F: File);

         Стирает буфер, соответствующий файлу F (если он существует) и затем закрывает файл.

                            AssignBuffer
                            ------------

         PROCEDURE AssignBuffer(F : File; VAR Buf: ARRAY OF BYTE);

         Назначает буфер Buf файлу F.  Для большой эффективности используемый размер буфера бу-
    дет: N*512+BufferOverHead, где N не меньше 2.


                               Exists
                               ------

         PROCEDURE Exists(Name: ARRAY OF CHAR) : BOOLEAN;

         Возвращает TRUE,  если специфицированный файл существует.  Exists использует процедуру
    ReadFirstEntry для определения результата.

                               Erase
                               -----

         PROCEDURE Erase(Name: ARRAY OF CHAR);

         Удаляет файл, заданный посредством Name.

                               Rename
                               ------

         PROCEDURE Rename(Name,NewName : ARRAY OF CHAR);

         Переименовывает файл Name на NewName.

                              Truncate
                              --------

         PROCEDURE Truncate(F: File);

         Отсекает файл F по его текущую файловую позицию.

                               GetPos
                               ------

         PROCEDURE GetPos(F: File) : LONGCARD;

         Возвращает текущую файловую позицию файла F.

                                Seek
                                ----

         PROCEDURE Seek(F : File; Pos: LONGCARD);

         Устанавливает файловую позицию файла F и помещает значение в Pos.

                                Size
                                ----

         PROCEDURE Size(F: File) : LONGCARD;

         Возвращает размер файла F в байтах.

                              IOresult
                              --------

         PROCEDURE IOresult() : CARDINAL;

         IOresult может быть вызвана после большинства  операций  для  тестирования  успешности
    операции.  Нуль означает,  что операция успешна, в противном случае IOresult возвращает код
    ошибки,  определенный в ДОС.  Заметьте, что глобальная переменная IOcheck должна быть FALSE
    для использования этой функции.

                       ФОРМАТИРОВАННЫЙ ВЫВОД
                       =====================

         Процедуры, описанные ниже,  выполняют форматированный вывод в файл.  Процедура  записи
    возможна  для каждого простого типа JPI Modula-2.  Все Wr'простой-тип' процедуры ( исключая
    WrChar) вызывают WrStrAdj.

                          Wr'простой-тип'
                          ---------------

         PROCEDURE WrChar(F : File; V : CHAR);
         PROCEDURE WrBool(F : File; V : BOOLEAN; Length:INTEGER);
         PROCEDURE WrShtInt(F:File; V:SHORTINT; Length:INTEGER);
         PROCEDURE WrInt(F : File; V : INTEGER; Length:INTEGER);
         PROCEDURE WrLngInt(F:File; V:LONGINT; Length:INTEGER);
         PROCEDURE WrShtCard(F:File;                V:SHORTCARD;
                                     Length:INTEGER);
         PROCEDURE WrCard(F:File; V:CARDINAL; Length:INTEGER);
         PROCEDURE WrLngCard(F:File; V:LONGCARD; Length:INTEGER);
         PROCEDURE WrShtHex(F:File; V:SHORTCARD; Length:INTEGER);
         PROCEDURE WrHex(F:File; V:CARDINAL; Length:INTEGER);
         PROCEDURE WrLngHex(F:File; V:LONGCARD; Length:INTEGER);

         PROCEDURE WrReal(F:File; V:REAL; Precision:CARDINAL;
                                          Length:INTEGER);
         PROCEDURE WrLngReal(F:File; V:LONGREAL;
                             Precision:CARDINAL; Length:INTEGER);

         Процедуры Wr'простой-тип' принимают следующие параметры:  номер файла F,  значение для
    записи V и размер поля форматированных данных Length  (не  применяется  для  WrChar).  Если
    Length  отрицательно,  форматированные  данные будут выровнены по левому краю,  в противном
    случае - по правому краю.
         Все процедуры (исключая WrChar и WrBool) вызывают соответствующую процедуру преобразо-
    вания из модуля Str для получения строкового представления значения V (см.  описание модуля
    Str); эта строка далее выводится с использованием WrStrAdj.
         Значение типа CARDINAL может быть записано  в  шестнадцатеричном  формате  посредством
    процедур WrShtHex, WrHex и WrLngHex.
         WrReal и WrLngReal принимают дополнительный параметр Precision,  который имеет  то  же
    значение,  что и в процедуре RealToStr (см. описание модуля Str). Глобальная переменная Eng
    указывает, сформатировано ли вещественное значение в инженерной нотации.

                               WrStr
                               -----

         PROCEDURE WrStr(F:File; V: ARRAY OF CHAR);

        Записывает строку V в файл F.

                              WrStrAdj
                              --------

         PROCEDURE WrStrAdj(F:File;  S:ARRAY  OF  CHAR;
                                        Length: INTEGER);

         Записывает строку S в файл F,  используя ABS(Length) как длину поля.  Если ABS(Length)
    меньше,  чем Str.Length(S) и глобальная переменная ChopOff -  TRUE,  то  последовательность
    '?' записывается вместо S. Если Length отрицательна, то форматированные данные будут выров-
    нены по левому краю, в противном случае - по правому краю.

         Пример:

         WrStrAdj(StandardOutput,'Hello',10);
         WrLn(StandardOutput);
         WrStrAdj(StandardOutput,'Hello',-10);

    дает следующий вывод:
              Hello
         Hello

                             WrCharRep
                             ---------

         PROCEDURE WrCharRep(F:File; V:CHAR; Count:CARDINAL);

         Записывает символ V в файл F Count число раз.

                                WrLn
                                ----

         PROCEDURE WrLn(F:File);

         Записывает новую строку (CHR(13) (возврат каретки),  CHR (10) (перевод строки)) в файл
    F.

                               WrBin
                               -----

         PROCEDURE WrBin(F:File; Buf:ARRAY OF BYTE;
                                 Count:CARDINAL);

         Записывает блок "необработанных" неформатированных данных,  заданных посредством Buf в
    файл F. Count - размер блока в байтах.



                       ФОРМАТИРОВАННЫЙ ВВОД
                       ====================

         Глобальная переменная  EOF устанавливается в TRUE,  если читается символ "конец-файла"
    (CHR(26)) или нет более входной информации,  которую можно было бы прочитать  из  заданного
    файла.

                          Rd'простой-тип'
                          ---------------

         PROCEDURE RdChar    (F : File) : CHAR;
         PROCEDURE RdBool    (F : File) : BOOLEAN;
         PROCEDURE RdShtInt  (F : File) : SHORTINT;
         PROCEDURE RdInt     (F : File) : INTEGER;
         PROCEDURE RdLngInt  (F : File) : LONGINT;
         PROCEDURE RdShtCard (F : File) : SHORTCARD;
         PROCEDURE RdCard    (F : File) : CARDINAL;
         PROCEDURE RdLngCard (F : File) : LONGCARD;
         PROCEDURE RdShtHex  (F : File) : SHORTCARD;
         PROCEDURE RdHex     (F : File) : CARDINAL;
         PROCEDURE RdLngHex  (F : File) : LONGCARD;
         PROCEDURE RdReal    (F : File) : REAL;
         PROCEDURE RdLngReal (F : File) : LONGREAL;

         Все процедуры Rd'простой-тип' получают файловую управляющую F,  специфицирующую  файл,
    из которого будет производиться чтение,  и возвращают значения 'простого типа', как указано
    в приведенном выше описании.
         Все процедуры  (исключая RdChar) вызывают RdItem для получения последовательности сим-
    волов,  которая ограничена символом из глобальной переменной типа множество Separators. Эта
    строка преобразуется к значению, используя одну из процедур преобразования из модуля Str.
         Процедуры RdShtHex, RdHex и RdLngHex читают значения типа CARDINAL в шестнадцатеричном
    формате.
         Процедура RdBool возвращает TRUE,  если читает строку 'TRUE', для всех других выходных
    данных она возвращает FALSE.
        Синтаксис для имеющих силу значений типа REAL можно найти в ГЛАВЕ 6.
         Глобальная переменная ОК устанавливается в FALSE, если значение требуемого типа не мо-
    жет быть прочитано, т.е., если значение имеет недопустимый формат или значение.

                               RdStr
                               -----

         PROCEDURE RdStr(F:File; VAR V:ARRAY OF CHAR);

         Читает строку из файла F и возвращает ее в V. Символы читаются до тех пор, пока не вы-
    полнится одно из следующих условий:
         - прочитан символ "конец файла" (CHR(26)),  EOF установлен в TRUE, и V завершается ну-
    лем;
         - прочитан символ "возврат каретки" (CHR(13)). V завершается нулем;
         - строка заполнена, т.к. HIGH(V)+1 символов прочитано. V завершается не нулем.

                               RdItem
                               ------

         PROCEDURE RdItem(F:File; VAR V: ARRAY OF CHAR);

         RdItem читает строку (из файла F), которая отделена посредством символов из глобальной
    переменной Separators. Строка возвращается в V.

                               RdBin
                               -----

         PROCEDURE RdBin(F       : File;
                         VAR Buf : ARRAY OF BYTE;
                         Count   : CARDINAL) : CARDINAL;

         Читает блок  размером Count "необработанных" байтов из файла F и возвращает его в Buf.


                        ОБРАБОТКА КАТАЛОГОВ
                        ===================

                               ChDir
                               -----

         PROCEDURE ChDir(Name : ARRAY OF CHAR);

         Изменяет текущую директорию.  Name специфицирует новый путь  для  директории  и  может
    включать имя устройства.

                               MkDir
                               -----

         PROCEDURE MkDir(Name : ARRAY OF CHAR);

         Создает новую поддиректорию на пути, определенном посредством Name.
                               RmDir
                               -----

         PROCEDURE RmDir(Name : ARRAY OF CHAR);

         Директория, специфицированная через Namе (которая должна быть пустой),  исключается из
    структуры директорий. Заметим, что текущая директория не может быть исключена.

                               GetDir
                               ------

         PROCEDURE GetDir(    Drive : SHORTCARD;
                          VAR Name  : ARRAY OF CHAR);

         GetDir возвращает полное имя пути в Name для текущей директории на устройстве,  специ-
    фицированная через Drive (0=по умолчанию, 1=устройство А и т.д.).

                           ReadFirstEntry
                           --------------

         TYPE
           PathTail = ARRAY[0..12] OF CHAR;
           FileAttr = SET OF (readonly,hidden,system,
                              volume,directory,archive);
           DirEntry = RECORD
                        rsvd : ARRAY[0..20] OF SHORTCARD;
                                   (* зарезервировано *)
                        attr : FileAttr;
                        time : CARDINAL;
                        date : CARDINAL;
                        size : LONGCARD;
                        name : PathTail;
                      END;
         PROCEDURE ReadFirstEntry( DirName : ARRAY OF CHAR;
                                   Attr    : FileAttr;
                                   VAR D   : DirEntry) : BOOLEAN;

         Ищет директорию DirName,  содержащую имя устройства, путь и имя файла для файла, кото-
    рый должен быть найден.  Имя файла может содержать символы шаблона '*' и '?'. Параметр Attr
    требует некоторого объяснения:  если он - пустое множество, то ищется только вхождение нор-
    мальных  файлов  (то  же применяется,  если установлены атрибуты readonly и archive);  если
    должно быть взято в расчет вхождение скрытых файлов,  системных файлов или  директорий,  то
    соответствующий атрибут должен быть установлен; наконец, если установлен атрибут volume, то
    возвращается только имя тома.
         Если подходящее вхождение найдено, ReadFirstEntry возвращает TRUE, и D будет содержать
    директорию вхождения.
         Смотри также процедуру ReadNextEntry.
         Пример:

         ReadFirstEntry("c:\com\*.*",FileAttr{hidden,system,
                        directory},e)

         Подходящими будут все файлы директории "c:\com",  и e будет содержать первое вхождение
    (если результат функции - TRUE).




Яндекс цитирования