
                          ГЛАВА 12

                     Стандартные модули

     В Главе 11 ("Стандартные процедуры и функции)  описыва-
лись все встроенные процедуры и функции Турбо-Паскаля, кото-
рые могут вызываться без явного их указания  (каким,  напри-
мер,  является  стандартное  определение Паскаля). Используя
стандартные модули Турбо-Паскаля, вы сможете реализовать на-
ибольшие  возможности  программирования (более подробная ин-
формация содержится в Главе 16  "Процедуры и функции  Турбо-
Паскаля").
     Стандартные  модули не отличаются от тех модулей, кото-
рые вы  сами  можете писать.  Можно  использовать  следующие
стандартные модули:
     Сrt - позволяет использовать все возможности  дисплея и
клавиатуры персонального компьютера РС,  включая  управление
режимом экрана,  расширенные  коды  клавиатуры, цвет, окна и
звуковые сигналы;
     Dos - поддерживает различные функции ДОС, включая уста-
новку и получение текущего значения даты и времени, поиск по
каталогам файлов и выполнение программ;
     Graph3 - реализует  графику  версии  3.0 Турбо-Паскаля,
использующую относительные команды (TurtleGraphics);
     Overlay - реализует мощную подсистему управления  овер-
леями версии 5.0 Турбо-Паскаля (см. Главу 13 "Оверлеи").
     Рrinter - позволяет легко организовать доступ к устрой-
тству печати.
     System - библиотека  поддержки  Турбо-Паскаля (этот мо-
дуль може автоматически вызываться любым модулем программы).
     Тurво3 - обеспечивает  наиболее высокую степень совмес-
тимости с версией 3 Турбо-Паскаля.
     Graph - мощный  графический пакет с независимой от уст-
ройств графической поддержкой для графических адаптеров СGS,
ЕGА, VGА, НЕRС, ИБМ 3270 РС, МСGА и АТТ 6300.
     Чтобы использовать  стандартный  модуль, его имя доста-
точно включить в предложение  использования вашей программы.

Например:

   uses Dos,Crt,Graph;

     Обычно все стандартные  модули  находятся в  библиотеке
TURBO.ТРL,  которая  автоматически  загружается  при запуске
Турбо-Паскаля.  Для  экономии памяти вы можете удалить редко
используемые модули,  такие,  как  ТURВО3 и GRAPН3, из файла
ТURВО.ТРL с помощью утилиты ТРUМОVЕR.

              Зависимость стандартных модулей

     Оба модуля, предназначенных  для совместимости версий -
ТURВО3 и GRАРН3 - зависят от  средств,  доступных для модуля
Сrt. Поэтому при использовании данных  модулей нужно сначала
определить  модуль  Сrt  в  предложении  использования вашей
программы.  В Таблице 12.1 приводится список стандартных мо-
дулей.

                  Стандартные модули       Таблица 12.1
-------------------------------------------------------
       Модуль                    Задание в предложении
                                     использование
-------------------------------------------------------
      Сrt                            не требуется
      Dos                            не требуется
      Grарн                          не требуется
      Grарн3                            Сrt
      Overlay                        не требуется
      Printer                        не требуется
      System                         не требуется
      Тurво3                            Сrt
-------------------------------------------------------

     Мы намеренно не отметили в  таблице, что все модули ис-
пользуют блок Systем,  программы  динамической поддержки для
всех встроенных функций, таких, как файловый ввод-вывод, об-
работка строк,  операции  с плавающей запятой и динамическое
распределение  памяти. Модуль Systем автоматически использу-
ется  любым модулем или программой и его не требуется указы-
вать в предложении uses.
     Процедуры и функции, содержащиеся в модуле System, опи-
сываются в Главе 10 ("Ввод и вывод") и в Главе 11 ("Стандар-
тные процедуры и функции"). Имеется также ряд  предописанных
переменных, включая:

  const
    OvrCodeList : word = 0;  { список сегментов оверлейного
                               кода }
    OvrHeapSize : word = 0;  { начальный размер оверлейного
                               буфера }
    OvrDebugPtr : pointer = nil; { используется при отладке
                                оверлеев }
    OvrHeapOrg : word = 0;    { начало оверлейного буфера }
    OvrHeapPtr : word = 0;  { указатель оверлейного буфера }
    OvrHeapEnd : word = 0;    { конец оверлейного буфера }
    OvrLoadList : word = 0;  { список загруженных оверлеев }
    OvrDosHandle : word = 0;  { канал оверлеев ДОС }
    OvrEmsHandle : word = 0;  { канал оверлеев EMS }
    HeapOrg : pointer = nil;  { начало динамически рас-
                                пределяемой области }
    HeapPtr : pointer = nil;  { указатель динамически рас-
                                пределяемой области }
    FreePtr : pointer = nil;  { указатель на список свобод-
                                ных областей }
    FreeMin : word = 0; { минимальный размер списка свобод-
                                ных областей }
    HeapError : pointer = nil; { функция ошибки динамически
                                распределяемой области памя-
                                ти }
    ExitProc : pointer = nil;  { процедура выхода }
    ExitCode : integer = 0;    { код выхода }
    ErrorAddr : pointer = nil; { адрес ошибки времени выпол-
                                 нения }
    PrefixSeg : word = 0;      { префиксный сегмент програм-
                                 мы }
    StackLimit : word = 0;     { указатель на нижнюю границу
                                 стека }
    InOutRes : integer = 0;    { буфер результата операции
                                 ввода-вывода }
    RandSeed : longint = 0;    { случайное число (генериру-
                                 ется датчиком случайных
                                 чисел) }
    FileMode : byte = 2;       { режим открытия файла }
    Test8087 : byte = 0;       { результат проверки процес-
                                 сора 8087 }

  var
    Input: text;          { стандартный файл ввода }
    Output: text;         { стандартный файл вывода }
    SaveInt00: pointer;   { сохраненное прерывание $00 }
    SaveInt02: pointer;   { сохраненное прерывание $02 }
    SaveInt1B: pointer;   { сохраненное прерывание $1B }
    SaveInt23: pointer;   { сохраненное прерывание $23 }
    SaveInt24: pointer;   { сохраненное прерывание $24 }
    SaveInt34: pointer;   { сохраненное прерывание $34 }
    SaveInt35: pointer;   { сохраненное прерывание $35 }
    SaveInt36: pointer;   { сохраненное прерывание $36 }
    SaveInt37: pointer;   { сохраненное прерывание $37 }
    SaveInt38: pointer;   { сохраненное прерывание $38 }
    SaveInt39: pointer;   { сохраненное прерывание $39 }
    SaveInt3A: pointer;   { сохраненное прерывание $3A }
    SaveInt3B: pointer;   { сохраненное прерывание $3B }
    SaveInt3C: pointer;   { сохраненное прерывание $3C }
    SaveInt3D: pointer;   { сохраненное прерывание $3D }
    SaveInt3E: pointer;   { сохраненное прерывание $3E }
    SaveInt3F: pointer;   { сохраненное прерывание $3F }
    SaveInt75: pointer;   { сохраненное прерывание $75 }

     Модулем Overlay для  реализации  подсистемы  управления
оверлеями используются переменные: OvrCodeList, OvrHeapSize,
OvrDebugPtr, OvreHeapOrg, OvrHeapPtr,  OvrHeapEnd,  OvrLoad-
List, OvrDosHandle и OvrEmsHandle. Оверлейный буфер распола-
гается между сегментом стека  и  динамически  распределяемой
областью,  при этом OvrHeapOrg и OvrHeapEnd содержат началь-
ный и конечный адреса  сегмента.  Назначаемый  по  умолчанию
размер  оверлейного буфера соответствует размеру наибольшего
оверлея программы. Если программа не содержит  оверлеев,  то
размер  оверлейного буфера будет равен нулю. Размер оверлей-
ного буфера можно увеличить с помощью обращения к  программе
модуля  Overlay  OvrSetBuf.  В  этом  случае при перемещении
HeapOrg в более старшие адреса размер  динамической  области
будет соответственно уменьшаться.
     Подсистемой управления динамически распределяемой обла-
стью  памяти для реализации программ динамического распреде-
ления памяти Турбо-Паскаля используются переменные  HeapOrg,
HeapPtr, FreePtr, FreeMin и HeapError. Подсистема управления
динамически распределяемой  областью  памяти  описывается  в
Главе 15 ("Внутренняя организация Турбо-Паскаля").
     Для реализации процедур выхода используются  переменные
ExitProc, ErrorCode и ErrorAdr. Это также описывается в Гла-
ве 15.
     PrefixSeg представляет собой переменную длиной в слово,
содержащую  адрес префиксного сегмента программы (PSP), соз-
даваемого при  выполнении  программы  операционной  системой
ДОС. Полное описание PSP приведено в руководстве по операци-
онной системе ДОС.
     Переменная StackLimit содержит  смещение  анчала  стека
относительно  сегмента стека, что соответствует минимальному
допустимому значению регистра SP, после которого уже  возни-
кает ситуация переполнения стека. По умолчанию значение этой
переменной равно 0, но если программа компилируется с дирек-
тивами {$N+,$E+}, то эмулятор сопроцессора 8087 при отсутст-
вии в системе сопроцессора 8087 для резервирования  места  в
младших адресах сегмента стека будет устанавливать ее в зна-
чение 224.
     Переменная InOutRes используется встроенными программа-
ми  ввода-вывода  для  сохранения значения, возращаемого при
следующем обращении к фукнции IOResult.
     В RandSeed сохраняется начальное значение для  встроен-
ного генератора случайных чисел. Если присваивать этой пере-
менной определенное значение, то функция Random будет  гене-
рировать  заданную  последовательность  случайных чисел. Это
может оказаться  полезным в  задачах  кодирования  данных, а
также в статистике и моделировании.
     Переменная FileMode позволяет изменять режим доступа  к
открытым типизованным и нетипизованным файлам. Более подроб-
но это описано в Главе 10 ("Ввод и вывод").
     В переменной Test8087 сохраняется результат работы  ал-
горитмов  автоматическиго  распознавания  сопроцессора 8087,
которые начинают работать при запуске программы, скомпилиро-
ванной с директивой {$N+}. Более подробно это описано в Гла-
ве 14 ("Использование сопроцессора 8087").
     Input и Оutput - это  стандартные  файлы  ввода-вывода,
необходимые  в  каждой  реализации Паскаля. По умолчанию они
связываются со стандартными входными и выходными  файлами  в
Dos. Более подробно это описано в Главе 10 ("Ввод и вывод").
     Модуль System перехватывает некоторые векторы  прерыва-
ний.  Перед  инициализацией своих собственных программ обра-
ботки прерываний модуль Systем сохраняет  старые  векторы  с
помощью четырех переменных-указателей:

  SaveInt00,          { $00 }
  SaveInt02,          { $02 }
  SaveInt23,          { $23 }
  SaveInt75 : pointer { $75 }

     Отметим, что для отслеживания критических ошибок модуль
System  содержит  обработчик  прерывания INT 24. В программе
Турбо-Паскаля критическая ошибка  ДОС  обрабатывается  точно
также,  как любая другая ошибка ввода-вывода. При компиляции
с директивой {$I+} программа будет завершать работу с  ошиб-
кой  времени  выполнения, в состоянии {$I-} функция IOResult
будет возвращать ненулевое значение.
     Приведем пример небольшой программы, которая восстанав-
ливает  первоначальный вектор и, таким образом, первоначаль-
ную логику обработки критической ошибки:

 program Restore;
 uses Dos;
 begin
   SetIntVec($24, SaveInt24);
   ...
 end.

     Программа SwapVectors в модуле Dos меняет  местами  со-
держимое  переменных SaveIntXX и текущее содержимое векторов
прерываний. Процедуру SwapVectors  следует  вызывать  непос-
редственно  перед и непосредственно после обращения к проце-
дуре Exec. Этим обеспечивается, что процесс Exec не  исполь-
зует  никаких обработчиков прерываний, установленных текущим
процессом (и нооборот). Более подробная информация приведена
в  Главе 16 ("Краткий справочник по Турбо-Паскалю") в описа-
нии SwapVactors.

                        Модуль Рrinter

     Модуль Рrinter - это очень  небольшой модуль, созданный
для облегчения использования в программе устройства  печати.
Модуль Рrinter описывает текстовый файл с именем Lst  и свя-
зывает его с устройством Lpt1.  Использование модуля Рrinter
избавляет вас от необходимости  описания, присваивания, отк-
рытия и закрытия текстовых файлов.  Приведем пример небольшой
программы, в которой используется модуль Рrinter:

  program HelloPrinter;
  uses Printer;
  begin
    Writeln(Lst,'Hello printer...');
  end.

                         Модуль Dоs

     С помощью модуля  Dos  реализуется  целый  ряд программ
операционной системы и программ обработки файлов. Ни одна из
программ модуля Dos не определена в стандартном Паскале, по-
этому они помещаются в отдельный модуль.
     Более полное описание операций ДОС приведено в руковод-
ствах по ДОС фирмы IBM.

                Константы, типы и переменные

     В данном разделе  кратко  обсуждаются константы, типы и
переменные, определяемые в модуле  Dos.  Более детальная ин-
формация содержится в  описании  процедур и функций, которые
зависят  от  этих  объектов, в Главе 16  ("Процедуры и функ-
ции Турбо-Паскаля).

                      Константы флагов

     После обращения к процедурам Inrt или МsDos для провер-
ки отдельных битов в регистре флагов  используются следующие
константы:

  const
    FCarry             = $0001
    FParity            = $0004
    FAuxilliary        = $0010
    FZero              = $0040
    FSign              = $0080
    FOverflow          = $0800

     Например, если  Р является записью, содержащей регистр,
то проверки:

  R.Flags and FCarry <> 0
  R.Flags and FZero = 0

принимают значение  Тruе,  когда, соответственно, установлен
флаг переноса (Carry) и сброшен флаг Zero.

                   Константы режима файла

     Эти константы используются в  процедурах обработки фай-
лов при открытии и  закрытии файлов  на  диске.  Поля режима
файловых переменных  Турбо-Паскаля будут  содержать  одно из
приведенных ниже значений:

  const
    fmClosed   = $D780
    fmInput    = $D781
    fmOutput   = $D782
    fmInOut    = $D783

                         Тип FileRec

     Определения записей, использующиеся в Турбо-Паскале для
внутренних  целей,  описываются  также  в  модуле  Dos.  Тип
FilеRес используется как для типизованных, так и для нетипи-
зованных файлов, в то время, как ТехtRес  представляет собой
внутренний формат переменной текстового типа.

  type
    { Типизованные и нетипизованные файлы }
    FileRec = record
                Handle: Word;
                Mode: Word;
                RecSize: Word;
                Private: array[1..26] of Byte;
                UserData: array[1..16] of Byte;
                Name: array[0..79] of Char;
              end;
    { запись Textfile }
    TextBuf = array[0..127] of Char;
    TextRec = record
               Handle: Word;
               Mode: Word;
               BufSize: Word;
               Private: Word;
               BufPos: Word;
               BufPtr: ^TextBuf;
               OpenProc: Pointer;
               InOutProc: Pointer;
               FlushProc: Pointer;
               CloseProc: Pointer;
               UserData: array[1..16] of Byte;
               Name: array[0..79] of Char;
               Buffer: TextBuf;
             end;

                  Константы атрибута файла

     Эти константы используются  для  проверки,  установки и
очистки  битов  атрибута  файлов  при использовании процедур
GetFAttr, SetFAttr, FindFirst и FindNext:

  const
    ReadOnly   = $01;  { доступ только по чтению }
    Hidden     = $02;  { "скрытый" файл }
    SysFile    = $04;  { системный файл }
    VolumeID   = $08;  { метка тома }
    Directory  = $10;  { каталог }
    Achive     = $20;  { признак архивизации }
    AnyFile    = $3F;  { прочий файл }

     Эти константы являются аддитивными, то есть оператор

  FindFirst('*.*',ReadOnly + Directory, S);

приведет к поиску  всех обычных файлов, а также файлов, дос-
тупных только по чтению, в текущем каталоге файлов. Констан-
та АnyFilе - это просто сумма всех атрибутов.

                 Регистровый тип (Registers)

     Переменные  регистрового  типа применяются в процедурах
Intr и  МsDos  для  задания  содержимого входного регистра и
проверки содержимого выходного регистра при прерываниях, ис-
пользующихся в программном обеспечении.

  type
    Registers = record
                 case integer of
                  0: (AX,BX,CX,DX,BP,SI,DS,ES,Flags: word);
                  1: (AL,AH,BL,BH,CL,CH,L,DH: byte);
                 end;

     Обратите внимание на использование  оператора  варианта
для того, чтобы отметить запись из  восьмибитовых регистров,
находящихся в начале шестнадцатибитовой записи.

                Тип даты и времени (DateTime)

     Переменные типа DateTiме  (даты и времени) используются
в процедурах  UnраскТiме и  РаскТiме для анализа, упаковки и
построения  четырехбайтового  значения,  содержащего  дату и
время. Это четырехбайтовое  значение  используется  затем  в
процедурах GetFTiме, SetTiме, FindFirst и FindNехt.

  type
    DateTime = record
                 Year,Month,Day,Hour,Min,Sec: integer;
               end;

     Допустимыми  диапазонами  являются: для переменной Year
(год) - с 1980 по 2099,  для  переменной Моnth (месяц) - с 1
по 12, для переменной Dау (день) - с 1 по 31, для переменной
Ноur (час) - от 0 до 23,  для переменной Мin (минута) - от 0
до 59, для переменной Sес (секунда) - от 0 до 59.

                        Тип SearchRec

     Переменные типа  SearchRес  используются  в  процедурах
FindFirst и Findnext для просмотра каталогов файлов.

  type
    SearchRec = record
    Fill: array[1..2] of byte;
    Attr: byte;
    Time: longint;
    Size: longint;
    Name: string[12];
  end;

     Информация по каждому из найденных с помощью  одной  из
этих   процедур   файлов   помещается   опять  в  переменную
SearchRес. Поле Аttr содержит атрибуты файла (построенные из
констант атрибута файла),  поле  Тiме  содержит дату и время
создания файла в  упакованном формате (для распаковки содер-
жимого этого поля  можно использовать процедуру UnpackТiме),
поле Sizе содержит размер файла в байтах, а поле Nаме содер-
жит его имя. Поле Fill в зарезервировано ДОС и не должно из-
меняться.

                    Переменная DosError

     Переменная  Doserror используется во многих программах,
работающих с  модулем Dos, для того, чтобы получить информа-
цию об ошибках.

  var DosError: integer;

     В переменной Doserror запоминаются коды ошибок ДОС.
Значение 0  указывает на отсутствие ошибки. Другие возможные
коды ошибок включают в себя:

     2 - файл не найден;
     3 - путь доступа не найден;
     5 - доступ отвергнут;
     6 - недопустимая обработка;
     8 - недостаточно памяти;
     10 - недопустимая программная среда;
     11 - неверный формат;
     18 - файлы отсутствуют.

             Процедуры обслуживания прерываний

     Приведем краткий список процедур, обслуживающих преры-
вания:

------------------------------------------------------------
     Процедура GetIntVес - возвращает адрес,  сохраненный  в
заданном векторе прерываний.
     Процедура Intr - выполняет заданное  программное преры-
вание.
     Процедура МsDos - выполняет вызов функции ДОС.
     Процедура SetIntVес - устанавливает по заданному адресу
заданный вектор прерывания.
     Процедура GetDate - возвращает  текущую  дату, установ-
ленную в операционной системе.
     Процедура GetFTime - возвращает дату и время  последней
записи файла.
     Процедура GetTiме - возвращает текущее время,  установ-
ленное в операционной системе.
     Процедура РackТiме - преобразует запись  DateTiме в че-
тырехбайтовое  упакованное  символьное  представление даты и
времени длинного  целого типа, которое используется в проце-
дуре SetTiме.  Поля записи DateTiме не проверяются на допус-
тимость границ.
     Процедура SetDate - устанавливает для операционной сис-
темы текущую дату.
     Процедура SetFTiме - устанавливает время и дату послед-
ней записи файла.
     Процедура SetTiме - устанавливает в операционной систе-
ме текущее время.
     Процедура UnpackТiме - преобразует четырехбайтовое упа-
кованной символьное  представление  даты  и времени длинного
целого типа, возвращаемого процедурами  GetFTiме, FindFirst,
FindNext в распакованную запись DateTiме.
------------------------------------------------------------

           Функции, проверяющие состояние  диска

------------------------------------------------------------
     Функция DiskFrее - возвращает число свободных байтов на
диске в заданном дисководе.

     Функция DiskSize - возвращает полный объем в байтах за-
данного диска.
------------------------------------------------------------

                 Процедуры обработки файлов

------------------------------------------------------------
     Процедура FindFirst - производит  поиск в заданном (или
текущем) каталоге записи, содержимое которой совпадает с за-
данным именем файла и атрибутами.
     Процедура FindNext - возвращает  следующую  запись, имя
файла и атрибуты в которой  совпадают с  теми,  которые были
заданы при предыдущем обращении к продедуре FindFirst.
     Процедура GetFAttr - возвращает атрибуты файла.
     Процедура SetFAttr - устанавливает атрибуты файла.
------------------------------------------------------------

         Процедуры и функции управления процессами

------------------------------------------------------------
     Функция DosExitCode -  возвращает для  подпроцесса  код
завершения.
     Процедура Ехесutе - выполняет заданную программу с ука-
занной командной строкой.
     Процедура Keep -  сохраняет  (прекращает  выполнение  и
сохраняет в памяти) прекратившую работу программу,  оставляя
ее резидентной в памяти.
     Процедура SwapVectors - меняет местами содержимое  сох-
раненных векторов прерываний и текущих векторов.
------------------------------------------------------------

           Фукнции управления операционной средой

------------------------------------------------------------
     Функция EnvCount - возвращает число строк, содержащихся
в операционной среде ДОС.
     Функция EnvStr - возвращает заданную строку  операцион-
ной среды.

     Функция GetEnv - возвращает значение заданной  перемен-
ной операционной среды.
------------------------------------------------------------

               Смешанные процедуры и функции

------------------------------------------------------------
     DosVersion - возвращает номер версии операционной  сис-
темы ДОС.
     GetCBreak  -  возвращает  проверяемое   ДОС   состояние
Ctrl-Break.
     SetCBreak -  устанавливает  проверяемое  ДОС  состояние
Ctrl-Break.
     GetVerify - возвращает состояние флага проверки в ДОС.
     SetVerify - устанавливает состояние  флага  проверки  в
ДОС.
------------------------------------------------------------

                         Модуль Сrt

     Модуль Сrt реализует ряд мощных  программ, предоставля-
ющих вам полную возможность управления средствами компьютера
РС, такими, как управление режимом экрана, расширенные  коды
клавиатуры, цвета, окна, и звуковые сигналы.  Модуль Сrt мо-
жет использоваться только в программах, работающих на персо-
нальных компьютерах IBM РС, РС АТ, РS/2  фирмы  ИБМ  и  пол-
ностью совместимых с ними.
     Одним из основный преимуществ использования  модуля Сrt
является является большая скорость и гибкость при выполнении
операций работы с экраном. Программы, не  работающие с моду-
лем Сrt, выводят на экран информацию с  помощью средств опе-
рационной системы ДОС, что  связано с  дополнительными избы-
точными  затратами.  При  использовании модуля Сrt выводимая
информация посылается непосредственно в базовую систему вво-
да-вывода  (ВIОS),  или, для еще более быстрых операций, не-
посредственно в видеопамять.

                  Входные и выходные файлы

     При инициализации модуля Сrt для того, чтобы можно было
обращаться к СRТ,  вместо  стандартных файлов ввода и вывода
ДОС  назначаются  стандартные  входные  и выходные текстовые
файлы. Это соответствует выполнению в  начале программы сле-
дующих операторов:

  AssignCrt(Input); Reset(Input);
  AssignCrt(Output); Rewrite(Output);

     Это означает, что  переопределение  входных  и выходных
файлов далее не допускается до тех пор, пока для данных фай-
лов не будет выполнено обратного  переназначения и  не прои-
зойдет  переход к  стандартному вводу и выводу с помощью вы-
полнения операторов:

  Assing(Input,''); Reset(Input);
  Assing(Output,''); RewriteOutput);

                            Окна

     Модуль Сrt поддерживает простую, но, тем не менее, мощ-
ную форму использования окон. Процедура Window позволяет вам
определить  в каком-либо месте экрана окно. При записи в это
окно  оно  ведет себя точно также, как целый экран. При этом
остальная часть экрана остается нетронутой. Другими словами,
доступ к экрану  вне окна отсутствует. Внутри окна можно до-
бавлять и  удалять  строки,  при  этом курсор возвращается к
правому краю и при  достижении  курсором нижней строки текст
продвигается вверх.
     Все координаты  экрана, кроме тех, которые используются
для определения окна,  относятся к текущему окну. Координата
экрана (1,1) соответствует левому верхнему углу экрана.
     По умолчанию окном считается весь экран.

                    Специальные символы

     При записи в выходной файл или в файл, который назначен
для модуля Сrt, специальное  значение имеют следующие управ-
ляющие символы:
     #7 - вызывает звуковой  сигнал,  издаваемый  с  помощью
внутреннего динамика.
     #8 - возврат на одну позицию. Вызывает перемещение кур-
сора  влево на одну позицию. Если курсор уже находится у ле-
вого  края текущего окна, то никаких действий не производит-
ся.
     #10 - перевод строки.  Перемещает курсор на одну строку
вниз.  Если курсор  уже  находится на нижней строке окна, то
окно пролистывается вверх на одну строку.
     #13 - возврат каретки.  Возвращает курсор с левому краю
текущего окна.
     Все другие символы при записи выводятся на экран.

                         Ввод строк

     При чтении из входного файла (Input) или при из тексто-
вого файла, который назначен  для модуля Сrt, текст вводится
по одной строке.  Строка  запоминается  во внутреннем буфере
текстового файла и  когда  переменные  считываются, то в ка-
честве  источника  используется этот буфер. Каждый раз когда
буфер становится  пустым,  вводится  новая строка. При вводе
строк можно использовать следующие клавиши редактирования:

     Вacksрасе - удаляет последний введенный символ.
     Еsс - удаляет всю вводимую строку.
     Еnter - прекращает ввод строки и записывает метку конца
строки (возврат каретки / перевод строки) в буфере.
     Сtrl-S - действует также, как Васкsрасе.
     Сtrl-D - извлекает  один  символ  из последней вводимой
строки и выводит его на экран.
     Сtrl-F - восстанавливает на  экране  последнюю вводимую
строку.
     Сtrl-Z - завершает ввод строки и генерирует символ кон-
ца файла.
     Сtrl-Z  генерирует  символ конца  файла  только  в  том
случае, если  переменная  СhескЕоf  установлена  в  значение
Тruе (по умолчанию ей присвоено значение Falsе).

     Для  проверки  состояния  клавиатуры  и ввода отдельных
символов  под   управлением  программы  используйте  функции
KeyРressed и Rеаdkey.

                Константы, типы и переменные

     В данном разделе кратко обсуждается каждая из констант,
типов переменных, задаваемых с помощью модуля Сrt.

                Константы режима модуля Сrt

     В качестве параметров процедуры  ТextМоdе  используются
следующие константы:

 const
  BW40  = 0;       { 40х25,  черно-белый  режим  на  цветном
                     адаптере }
  C40   = 1;       { 40х25, цветной режим на  цветном  адап-
                     тере }
  BW80  = 2;       { 80х25,  черно-белый  режим  на  цветном
                     адаптере }
  C080  = 3;       { 80х25, цветной режим на цветном адапте-
                     ре }
  Mono  = 7;       { 80х25, черно-белый режим на  монохрома-
                     тическом адаптере }
  Font8x8 = 256;   { 43 и 50 строк для адаптеров EGA/VGA }
  C40   = C040;    { для совместимости с версией 3.0 }
  C80   = C080;    { для совместимости с версией 3.0 }

     ВW40, С040, ВW80 и С080 представляют собой четыре цвет-
ных  текстовых  режима, поддерживаемых в цветном графическом
адаптере (СGА) на компьютере РС фирмы  ИБМ.  Константа  Моnо
представляет собой отдельный черно-белый режим, поддерживае-
мый монохроматическим адаптером на компьютере РС фирмы  ИБМ.
Font8x8  -  это режимы адаптеров EGA/VGA с 43 и 50 строками.
Константы С40 и С80 предназначены для совместимости с верси-
ей 3.0 Турбо-Паскаля.

                      Константы цветов

     При работе с процедурами ТехтСоlor и ТехтВаскground ис-
пользуются следующие константы:

 const
   Black          = 0;      { черный }
   Blue           = 1;      { синий  }
   Green          = 2;      { зеленый }
   Cyan           = 3;      { бирюзовый }
   Red            = 4;      { красный }
   Magenta        = 5;      { малиновый }
   Brown          = 6;      { коричневый }
   LightGray      = 7;      { светло-серый }
   DarkGray       = 8;      { темно-серый }
   LightBlue      = 9;      { светло-голубой }
   LightGreen     = 10;     { светло-зеленый }
   LightCyan      = 11;     { светло-бирюзовый }
   LightRed       = 12;     { светло-красный }
   LightMagenta   = 13;     { светло-малиновый }
   Yellow         = 14;     { желтый }
   White          = 15;     { белый }
   Blink          = 128;    { мерцание }

     Цвета представлены их номерами от 0 до 15. Чтобы легко
идентифицировать каждый цвет, вместо цветов можно использо-
вать данные константы. В цветном текстовом режиме цвет каж-
дого символа выбирается из 16 цветов, а фоновый цвет - из 8
цветов. Цвет каждого символа можно сделать мерцающим.

                       Переменные Crt

     В модуле Crt содержатся следующие переменные:

 var
   CheakBreak   : boolean;
   CheckEof     : boolean;
   CheckSnow    : boolean;
   DirectVideo  : boolean;
   LastMode     : word;
   TextAttr     : byte;
   WindMin      : word;
   WindMax      : word;

                   Переменная СhескВrеak

     Переменная СheckВrеak разрешает или запрещает  проверки
ситуации Сtrl-Вreak.

     var CheckBreak: boolean;

     Когда переменная СhескВrеak принимает значение Тruе, то
нажатие  клавиш Сtrl-Вrеak приведет к принудительному завер-
шению работы программы при следующей операции вывода на  эк-
ран  дисплея, которую выполнит эта программа. Когда перемен-
ная СhескВreak  принимает  значение  Falsе,  нажатие  клавиш
Сtrl-Вreak  не  вызовет никаких действий. По умолчанию пере-
менная СhескВrеак принимает значение Тruе. (Во время  выпол-
нения  модуль  Сrt  сохраняет  старый  вектор  прерываний по
Сtrl-Вreak, $1В, в глобальной переменной-указателе с  именем
SaveInt1В).

                     Переменная СhесkЕОF

     Переменная СhесkЕОF разрешает или запрещает символ кон-
ца файла:

  var CheckEOF: boolean;

     Если переменная СhесkЕОF имеет значение Тruе, то, когда
чтение производится  из  файла  назначенного экрану дисплея,
при нажатии клавиш  Сtrl-Z  генерируется символ конца файла.
Когда переменная СhесkЕОF имеет значение False  при  нажатии
клавиш  Сtrl-Z  никаких  действий  не выполняется.  Значение
Falsе присваивается переменной СhесkЕОF по умолчанию.

                    Переменная СhесkSnow

     Переменная СhесkSnow  разрешает  или  запрещает  видео-
контроль при записи  символов непосредственно в видеопамять.
(При отсутсвии такого контроля на экране дисплея могут  воз-
никать помехи в виде "снега".)

  var CheckSnow: boolean;

     В большинстве  адаптеров СGА, если символы запоминаются
в видеопамяти не во время интервалов обратного хода горизон-
тальной развертки, то будут возникать помехи.  При использо-
вании монохроматических адаптеров или адаптера ЕGА этого  не
происходит.
     Когда   выбран   цветной  текстовый  режим,  переменной
СhескSnow присвоено значение Тruе и прямая запись в видеопа-
мять  производится только во время интервалов обратного хода
горизонтальной развертки.  При работе в последними  моделями
адаптеров СGА вы, возможно,  захотите в  начале  программы и
после каждого вызова процедуры ТехтМоdе присвоить переменной
СhескSnow значение Falsе. Это вызовет отмену  видеоконтроля,
что приведет к значительно большей скорости работы.
     Когда  переменная DirectVideo имеет значение Falsе, пе-
ременная СhескSnow никаких действий не вызывает.

                   Переменная DirесtVidео

     Переменная DirесtVidео разрешает или  запрещает  прямой
доступ к  памяти  при  использовании  операторов  Writе  или
Writeln, с помощью которых информация выводится на экран.

  var DirectVideo: boolean;

     Когда переменная  DirесtVidео  имеет  значение Тruе, то
при использовании операторов записи Write и  Writeln в файл,
связанный с  устройством  СRТ, вместо обращения  для  вывода
символов  к  средствам  ВIОS (базовая система ввода-вывода),
что значительно замедляет процесс,  они  будут  записываться
непосредственно в видеопамять.
     По умолчанию переменная DirесtVidео всегда имеет значе-
ние Тruе. Если по каким-либо  причинам вы хотите, чтобы сим-
волы выводились с  помощью  обращений к базовой системе вво-
да-вывода, то в начале вашей программы и после каждого обра-
щения в процедуре ТехтМоdе присвойте переменной DirесtVidео
значение Falsе.

                    Переменная ТехтАttr

     Переменная ТехтАttr используется для сохранения выбран-
ных текущих текстовых атрибутов.

  var TextAttr: byte;

     Текстовые атрибуты обычно устанавливаются с помощью вы-
зова процедур  ТехtСоlоr и  ТехtВаckground, однако вы можете
также установить их путем непосредственной записи значения в
переменную TextАttr.  Информация о цветах кодируется в пере-
менной TextАttr следующим образом:

          7    6  5  4   3  2  1  0
       ------------------------------
       !  В  ! b  b  b ! f  f  f  f !
       ------------------------------

где ffff - четырехбитовый цвет текста, bbb - трехбитовый фо-
новый цвет, а В - бит,  разрешающий режим мерцания. Если для
задания значений переменной ТехтАttr вы используете констан-
ты цветов, заметим, что в качестве фонового цвета можно выб-
рать только  один  из  первых 8 цветов и что для того, чтобы
разместить  его  в  правильных  позициях битов, это значение
нужно умножить на 16. При следующих присвоениях будут выбра-
ны желтые мерцающие символы на голубом фоне.

  TextAttr := Yellow + Blue * 16 + Blink;

                Переменные WindMin и WindМах

     Переменные WindMin и WindМах используются для запомина-
ния координат экрана для текущего окна.

  var WindMin, WindMax : word;

     Эти переменные устанавливаются с помощью  вызова проце-
дуры Window.  Переменная  WindMin  определяет  левый верхний
угол, а переменная  WindМах -  нижний правый угол. В младшем
байте хранится  координата Х, а в старшем байте - координата
Y. Например,  Lо(WindMin)  дает координату  Х левого края, а
Нi(WindМах)  - кординату Y нижнего края.  Левый верхний угол
экрана соответствует координатам (Х,Y) = (0,0). Заметим, од-
нако, что при передаче  координат в  качестве параметров при
обращении  к процедурам  Window и  GоtоХY верхний левый угол
задается координатами (1,1).

                    Процедуры и функции

------------------------------------------------------------
     Процедура АssignCrt - назначает текстовый файл для уст-
ройства СRТ.
     Процедура СlrЕоl - очищает все символы, начиная от  по-
зиции курсора до конца строки, без перемещения курсора.
     Процедура СlrScr - очищает экран и  помещает  курсор  в
верхнем левом углу.
     Процедура Dеlау - выполняет задержку на указанное число
миллисекунд.
     Процедура DelLine - удаляет строку, на которой находит-
ся курсор и перемещает все  следующие  строки на одну строку
вверх. Нижняя строка очищается.
     Процедура GоtоХY - выполняет позиционирование  курсора.
Х - это горизонтальная позиция, Y - вертикальная позиция.
     Процедура НightVideo - выбирает символы с подсветкой.
     Процедура InsLine - вставляет  пустую  строку  в  месте
расположения курсора.
     Функция KeyРrеssеd - возвращает  значение  Тruе,   если
клавиша на клавиатуре нажата и Falsе - в противном случае.
     Процедура LowVidео - выбирает символы с пониженной  яр-
костью.
     Функция NormVideo - выбирает символы с нормальной ярко-
стью.
     Процедура NoSound - выключает внутренний динамик.
     Функция Rеаdкеу - считывает символ с клавиатуры.
     Процедура RеstorеСrt - восставливает  исходный видеоре-
жим, который использовался при запуске.
     Процедура Sound - включает внутренний динамик.
     Процедура ТехtВаскground - выбирает фоновый цвет.
     Процедура ТехtСоlor - выбирает цвет самого символа.
     Процедура ТехtМоdе - выбирает  конкретный текстовый ре-
жим.
     Функция WherеХ - возвращает координату  Х  для  текущей
позиции курсора, относящуюся к текущему окну. Х представляет
собой горизонтальную позицию.
     Функция WhereY - возвращает  координату  Y  для текущей
позиции курсора, относящуюся к текущему окну. Y представляет
собой вертикальную позицию.
     Процедура Window - определяет на экране текстовое окно.
------------------------------------------------------------

                        Модуль Graph

     Модуль Graph  реализует  полную библиотеку из более чем
50 графических программ -  от вызовов процедур и функций вы-
сокого уровня, как,  например, SetViewPort, Ваr3D, DrowPoly,
до программ,  ориентированных на работу с битами, таких, как
GetImage или РutImage. Поддерживается несколько видов закра-
шивания и  типов  линий и имеется несколько шрифтов, которые
можно изменять  по величине, выравнивать и ориентировать го-
ризонтально или вертикально.
     Для  компиляции  программы,  использующей модуль Grарh,
вам не потребуется никаких внешних  файлов  (кроме, конечно,
исходного  текста  вашей  программы, компилятора и доступа к
стандартным модулям в ТURВО.ТРL). Для запуска программы, ис-
пользующей модуль Grарh, кроме вашей программы с расширением
.ЕХЕ вам  потребуются  один  или более графических драйверов
(см. далее файлы .BGI).  В  придачу к  этому вам потребуется
также один или  более  файлов  шрифтов  (.СНR), если в вашей
программе используются какие-либо шрифты.
     В соответствии  с  лицензионными  условиями  вы  можете
распростанять файлы .CHR и .BGI наряду с со своими  програм-
мами.

                          Драйверы

     Для перечисленных ниже графических  адаптеров и  полно-
стью совместимых с ними предусмотрены  следующие графические
драйверы:

     - СGА;
     - МСGА;
     - ЕGА;
     - VGА;
     - Неrcules;
     - АТ&Т 400;
     - 3270 РС;
     - IBM-8514.

     Каждый драйвер содержит выполняемый код и данные и хра-
нится в отдельном файле на диске. Во время работы  процедура
InitGraph идентифицирует графическую аппаратуру и производит
загрузку и инициализацию соответствующего графического драй-
вера, переводит систему в графический режим, а затем возвра-
щает управление вызывающей  программе.  Процедура СloseGraph
выгружает драйвер из памяти и восстанавливает предыдущий ви-
деорежим. С помощью программ  RеstoreCrtMode и  SetGraphMode
вы можете переключаться между текстовым и графическим  режи-
мом.
     Модуль Grаph может также работать на компьютерах с дву-
мя мониторами. При инициализации модуля Graph с помощью про-
цедуры InitGraph для графического драйвера и требуемого  ре-
жима будет выбран нужный монитор. При завершении работы гра-
фической программы предыдущий видеорежим будет восстановлен.
Если для графической аппаратуры с двумя мониторами требуется
автоматическое распознавание, то процедура InitGraph выберет
монитор и графическую плату,  при  которой  будет получаться
наилучшее качество выводимой графической информации.

 CGA.BGI     - драйвер для адаптеров CGA, MCGA фирмы IBM.
 EGAVGA.BGI  - драйвер для адаптеров EGA, VGA фирмы IBM.
 HERC.BGI    -   драйвер   для  монохроматического  адаптера
Hercules фирмы IBM.
 ATT.BGI     - драйвер для AT&T 6300 (400 строк).
 PC3270.BGI  - драйвер для IBM PC 3270.
 IBM8514.BGI - драйвер для IBM8514.

               Поддержка устройства IBM-8514

     Турбо-Паскаль поддерживает графическую плату  IBM-8514,
которая представляет собой новую графическую плату с высоким
разрешением, позволяющую получить разрешающую способность до
1024х768 точек и палитру, содержащую  256  оттенков  из  256
цветов. Файл драйвера для этой графической платы  называется
IBM8514.BGI.
     Графическая плата IBM-8514 не может правильно распозна-
ваться при автоматическом обнаружении  (она будет  распозна-
ваться алгоритмами автообнаружения,  как плата  VGA).  Таким
образом,  чтобы  использовать  плату  IBM-8514,   переменной
GraphDriver при вызове InitGraph  нужно  присвоить  значение
IBM8514 (которое определено в модуле  Graph).  При  работе с
платой   IBM-8514   не  следует   использовать  с  InitGraph
DetectGraph или DETECT (если только вы не хотите эмулировать
режим VGA).
    Для  платы  IBM-8514  поддерживаются  следующие  режимы:
IBM8514LO (640х480 элементов изображения) и IBM8514HI  (1024
х768 элементов изображения). Обе константы режима определены
в интерфейсной части GRAPH.TPU.
    Для определения цветов в плате IBM-8514 используются три
6-битовых значения. Для каждого определяемого цвета  имеются
6-битовые компоненты Red (красный), Green (зеленый)  и  Blue
(голубой). Для того, чтобы при работе с  графической  платой
IBM-8514 пользователь мог задавать цвета,  в библиотеку  BGI
добавлена новая программа. Эта программа определяется в  мо-
дуле GRAPH.TPU следующим образом:

 procedure SetRGBPalette(ColorNum, Red, Green, Blue : word);

    Аргумент  ColorNum  задает запись палитры, которую нужно
загрузить. Этот аргумент представляет собой целое значение в
диапазоне от 0 до 255 (дес.). Аргументы Red,  Green  и  Blue
определяют компоненты цветов в записи палитры.  Используется
только младший байт этих значений и только 6  старших  битов
этого байта загружаются в палитру.
    Другие программы, модифицирующие палитру (SetAllPalette,
SetPalette, GetPalette),  при работе  с  графической  платой
IBM-8514 использовать не следует.
    Для совместимости с графическими  адаптерами  фирмы  IBM
драйверы формата BGI определяют для первых 16 цветов палитры
IBM-8514 значения цветов, принятые по умолчанию для  адапте-
ров EGA/VGA. Эти значения могут использоваться в  неизменен-
ном   виде   или   модифицироваться   с   помощью  процедуры
SetGRBPalette.
    Процедура   FloodFill  с  драйвером  графической   платы
IBM-8514 работать не будет.
    При  работе с графическим адаптером VGA в цветном режиме
256К имеют место те же ограничения.

                     Система координат

     По соглашению верхний левый угол экрана имеет координа-
ту (0,0). У более правого столбца координата х больше, у бо-
лее нижней строки больше координата y.  То есть координата х
увеличивается при перемещении вправо,  а  координата y - при
перемещении вниз. Таким образом координаты каждого из  четы-
рех углов и конкретной точки (середины экрана) будут  выгля-
деть следующим образом:

 (0,0)                                    (319,0)
   --------------------------------------------
   !                                          !
   !                                          !
   !                                          !
   !                . (159,99)                !
   !                                          !
   !                                          !
   !                                          !
   !                                          !
   --------------------------------------------
 (0,199)                                 (319,199)

                     Текущий указатель

     Понятие текущего указателя  (СР - Сurrent Pointer)  ис-
пользуется во многих графических системах. Понятие СР анало-
гично понятию курсора для  текстового режима, за исключением
того, что текущий указатель невидим.

  Write('ABC');

     В текстовом  режиме предшествующий оператор Write оста-
вит курсор в колонке, непосредственно следующим за буквой С.
Если буква С была  введена  в колонке 80, то курсор перейдет
на колонку 1  следующей строки.  Если буква С была введена в
колонке 80  строки  25,  то  произойдет пролистывание экрана
вверх на 1  строку и  курсор  будет находится в 1 колонке 25
строки.

  MoveTo(0,0);
  LineTo(20,20)

     В графическом режиме данный оператор LinеТо оставит те-
кущий  указатель  в последней заданной точке  (20,20).  Если
действует режим отсечения, реальная  выводимая  прямая будет
отсечена до  текущей  точки.  Заметим, что текущий указатель
никогда не отсекается.
     Команда  МоvеТо  является  эквивалентом команды GotoXY.

Единственное ее назначение - это перемещение текущего указа-
теля. Перемещение текущего  указателя  может  использоваться
только в следующих командах, использующих текущий указатель:

 MoveTo, InitGraph, MoveRel, LineTo, LineRel, OutText,
 SetGraphMode, ClearDevice, SetViewPort, ClearViewPort

                           Текст

     В графическом режиме  для  вывода  текста  используется
шрифт с растром 8х8 и несколько "штриховых" шрифтов. Растро-
вый  символ  задается  с  помощью  матрицы элементов изобра-
жения. Штриховой шрифт задается рядом векторов, которые ука-
зывают графической системе, как рисовать шрифт.
     Преимущество использования штриховых шрифтов становится
очевидным, когда вы начинаете рисовать большие символы. Пос-
кольку штриховой шрифт задается векторами, то при увеличении
шрифта качество и разрешение остаются, тем не менее, хороши-
ми.
     Когда увеличивается растровый шрифт, то матрица умножа-
ется на масштабный коэффициент, а когда  этот масштабный ко-
эффициент  увеличивается,  разрешение  у символов становится
более грубым.  Для маленьких  шрифтов растровый шрифт должен
быть достаточно приемлимым, но для больших шрифтов вы, веро-
ятно, захотите выбрать шириховой шрифт.
     Выравнивание графического текста управляется процедурой
SetТехtJustify. Масштабирование и выбор шрифта осуществляет-
ся с помощью процедуры SetТехtStyle. Графический текст выво-
дится с помощью процедур ОutТехt или ОutТехtХY. Запрос о те-
кущих  установленных для текста параметрах выполняется с по-
мощью обращения к процедуре GetТехtSettings. Шириховые шриф-
ты хранятся каждый в отдельном файле на диске и должны  при-
сутствовать  там  во  время  работы  (при  вызове  процедуры
SetТехtStyle).  Размер  штрихового  шрифта можно настроить с
помощью процедуры SetUserCharSize.  Файлы  шрифтов  (которые
имеют  расширение  .CHR) могут загружаться с диска автомати-
чески модулем Graph, или их можно компоновать  с  программой
пользователя  или загружать и "регистрировать" с помощью мо-
дуля Graph.
     Для преобразования файла  шрифта  (или  любого  другого
предназначенного  для  этой  цели  двоичного файла данных) в
файл .OBJ, который можно компоновать с модулем или  програм-
мой  с помощью директивы компилятора $L предусмотрена специ-
альная утилита BINOBJ.EXE. При этом становится возможным по-
местить  все файлы шрифтов в выполняемый файл .EXE (см. ком-
ментарии в начале примера программы GRLINK.PAS на  дистрибу-
тивном диске).

             Графические изображения и их виды

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

  SetFillStyle, SetFloodPattern, FillPoly, FloodFill


            Области просмотра и двоичные образы

     Процедура  ViewPoint позволяет всем командам вывода ра-
ботать в прямоугольной области  экрана.  Графики,  прямые  и
другие графические изображения (весь графический вывод) свя-
зывается с областью просмотра, пока эта область не изменяет-
ся. Предусмотрены программы для  очистки области просмотра и
считывания ее текущих определений.  Если задан режим отсече-
ния, то весь графический  вывод отсечется  до текущей точки.
Заметим, что текущий указатель никогда не отсекается.
     Для считывания и вывода  элементов  изображения предус-
мотрены  процедуры  GetPixel и  Putpixel.  Чтобы сохранить и
восстановить на экране прямоугольную область,  можно исполь-
зовать  процедуры  GetImage и  PutImage.   Они  обеспечивают
полное выполнение  операций  процедуры  ВitВlt  (нормальное,
хоr, оr, аnd, nоt).

                 Поддержка страниц и цвета

     Имеется много других поддерживающих  программ,  включая
поддержку  для  нескольких  графических  страниц (только для
адаптеров  ЕGА, VGА и Неrcules; это особенно полезно при ис-
пользовании в мультипликации), палитры, цвета и так далее.

                      Обработка ошибок

     Внутренние  ошибки  модуля  Graph возвращаются функцией
GraphResult. Эта функция возвращает код ошибки, показывающий
состояние последней графической операции.  Имеются следующие
коды возврата с ошибкой:

      0 - ошибки нет;
     -1 - (BGI) графика не установлена (используйте процеду-
          ру InitGraph);
     -2 - аппаратное обеспечение для графики не найдено;
     -3 - не найден файл драйвера устройства;
     -4 - неверный файл драйвера устройства;
     -5 - не хватает памяти для загрузки драйвера;
     -6 - выход за границы памяти при сканировании области
          закрашивания;
     -7 - выход за границы памяти при заполнении закрашивае-
          мой области;
     -8 - не найден файл шрифта;
     -9 - не хватает памяти для загрузки шрифта;
     -10 - недопустимый для вы
     error in text............................
талоге С: DRIVERS). Если графическая аппаратура не распозна-
на или в  процессе инициализации произошла ошибка, то на эк-
ран выводится сообщение об ошибке и программа прекращает ра-
боту. В противном случает вдоль краев экрана рисуется прямо-
угольник и в центре экрана выводится текст.

      Примечание: Устройство АТ&Т400 не распознается автома-
      тически. Тем не менее вы можете пользоваться драйвером
      графии АТТ путем отмены автоматической проверки, пере-
      сылки  исполняемого  кода   драйвера   АТ&Т  процедуре
      InitGraph и установки допустимого графического режима.
      Замените 8 и 9 строку в предыдущем примере  следующими
      тремя строками:

   GraphDriver := ATT400;
   GraphMode := ATT400Hi;
   InitGraph(GraphDriver, GraphMode, 'C:\DRIVER');

           Это укажет  графической  системе на необходимость
      загрузки драйвера устройства АТ&Т400, расположенного в
      каталоге  С: DRIVERS и установит графический режим 640
      на 400.

     Приведем еще один пример, который показывает, как можно
переключаться между графическим и текстовым режимами:

  1 program GraphTest;
  2 uses
  3   Graph;
  4 var
  5   GraphDriver  : integer;
  6   GraphMode    : integer;
  7   ErrorCode    : integer;
  8 begin
  9   GraphDriver := Detect;    { Установить флаг: выполнить
                                  распознавание }
  10  InitGraph(GraphDriver, GraphMode, 'C:\DRIVERS');
  11  ErrorCode := GraphResult;
  12  if ErrorCode <> grOk then  { ошибка+ }
  13  begin
  14    Writeln('Ошибка графики: ',GraphErrorMsg(ErrorCode);
  15    Writeln('Программа аварийно завершила работу...');
  16    Helt(1);
  17  end;
  18  OutText('Графический режим. Нажмите <RETURN>');
  19  Readln;
  20  RestoreCrtMode;
  21  Write('Текстовый режим. Нажмите <RETURN>');
  22  Readln;
  23  SetGraphMode(GraphMode);
  24  OutText('Снова графический режим. Нажмите <RETURN>');
  25  Readln;
  26  CloseGraph;
  27 end. { GraphTest }

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

             Программы управления динамически
     распределяемой областью, написанные пользователем

     Для модуля Graph предусмотрены две программы управления
динамически   распределяемой    областью    GraphFrееМем   и
GraphGetМем. Первая из них освобождает память,  распределен-
ную для драйверов, а вторая -  распределяет память для драй-
веров  графических  устройств.  Стандартные  программы имеют
следующий вид:

  procedure GraphGetMem(var P : Pointer; Size : word);
  { выделить память для драйверов графических устройств }
  procedure GraphFreeMem(var P : Pointer; Size : word);
  { освободить память для драйверов графических устройств }

     В модуле Graph имеются два указателя, которые по умол-
чанию указывают на две описанные здесь стандартные програм-
мы. Эти указатель определяются следующим образом:

  var
    GraphGetMemPtr  : pointer;
    { указатель на программу распределения памяти }
    GraphFreeMemPtr : pointer;
    { указатель на программу освобождения памяти }

     Во время инициализации модуля Graph  эти указатели ссы-
лаются  на  стандартные  графические  программы  распределе-
ния-освобождения,  которые  определяются в секции реализации
модуля Graph.  Чтобы  задать ваше собственное управление па-
мятью, в модуле Graph вы можете изменить значения этих  ука-
зателей так, чтобы они ссылались на ваши  собственные  прог-
раммы. Программы, заданные пользователем должны иметь тот же
список параметров,  что  и  стандартные  программы, и должны
иметь дальний тип  вызова.  Приведем  далее  пример заданных
пользователем программ распределения и  освобождения памяти.
Заметим, что при использовании процедуры Ехit  автоматически
вызывается процедура СloseGraph.

 program UserHeapManegement;
 { программа показывает, как пользователь может работать с
   программами управления динамически распределяемой облас-
   тью памяти, используемыми в модуле Graph }
 uses
    Graph;
 var
    GraphDriver, GraphMode : integer;
    ErrorCode              : integer; { используется для
              сохранения кода возврата функции GraphResult }

    PreGraphExitProc       : pointer { используется для сох-
              ранения исходной процедуры выхода }
 {$F+}      { процедуры пользователя должны использовать
              дальний тип обращения }
  procedure MyGetMem(var P : Pointer; Size : word);
            { выделить память для драйверов графичес-
              ких устройств }
  begin
    Write('Была вызвана процедура MyGetMem, нажмите
           <RETURN>:');
    GetMem(P, Size);
  end; { MyGetMem }

  procedure MyFreeMem(ver P : Pointer; Size : word);
  { освободить память, занятую драйверами графических
    устройств }
  begin
    RestoreCRTMode;
    Write('Была вызвана процедура MyFreeMem, нажмите
           <RETURN>:'); Readln;
    if P <> Nil Then { не освобождать пустые указатели }
    begin
      FreeMem(P, Size);
      P := Nil;
    end; { MyFreeMem }

 procedure MyExitProc;
 { процедура всегда получает вызов при прекращении работы
   программы }
 begin
   ExitProc := PreGraphExitProc; { восстановить исходную
                                   процедуру выхода }
   CloseGraph;         { очистить динамически распределяемую

                         область }
 end; { MyExitProc }

 { $F- }

 Begin
 { инициализировать программу очистки памяти }
    PreGraphExitProc := ExitProc;
    ExitProc := @MyExitProc;
    GraphGetMemPtr := @MyGetMem ; { заменить распределение
                                    памяти }
    GraphFreeMemPtr := @MyFreeMem ; { заменить освобождение
                                    памяти }
    GraphDriver := Detect;
    InitGraph(GraphDriver, GraphMode, '');
    ErrorCode := GraphResult;
    if ErrorCode <> grOk then
  begin
   Writeln('Графическая ошибка: ' GraphErrorMsg(ErrorCode);
   Readln;
   Halt(1);
  end;
  Line(0, 0, GetMaxX, GetMaxY);
  OutText(1, 1, 'Нажмите клавишу <RETURN>:');
  Readln;
 end. { UserHeapManegement }

             Интерфейсная секция модуля  Graph:
                константы, типы и переменные

     В модуле  Graph имеется много полезных описаний типов и
констант.  Ниже  приводится  часть интерфейсной секции файла
GRАРН.ТРU, на переменные которой вы можете ссылаться.

                         Константы

     Функцией GraphResult  возвращаются  следующие  значения
кодов ошибок:

 const
    { коды ошибок, возвращаемые процедурой GraphResult }
   grOk                     =  0;
   grNoInitGraph            = -1;
   grNotDetected            = -2;
   grFileNotFound           = -3;
   grInvalidDriver          = -4;
   grNoLoadMem              = -5;
   grNoScanMem              = -6;
   grNoFloodMem             = -7;
   grFontNotFound           = -8;
   grNoFontMem              = -9;
   grInvalidMode            = -10;
   grError                  = -11;  { общая ошибка графики }
   grIOError                = -12;
   grInvalidFont            = -13;
   grInvalidFontNum         = -14;

     Следующие константы драйверов и константы режимов можно
использовать при работе с процедурами InitGraph, DetectGraph
и GetModeRange:

   { определить графические драйверы }
 const
   Detect          = 0; { требуется автоматическое распозна-
                          вание }
   CGA             = 1;
   MCGA            = 2;
   EGA             = 3;
   EGA64           = 4;
   EGAMono         = 5;
   RESERVED        = 6; { зарезервировано (не используется) }
   HercMono        = 7;
   ATT400          = 8;
   VGA             = 9;
   PC3270          = 10;

   { графические режимы для каждого драйвера }
   CGAC1        = 0; { 1 палитра цветов 320х200: красный,
                       желтый, зеленый; 1 страница }
   CGAC2        = 1; { 2 палитра цветов 320х200: светло-
                       бирюзовый, малиновый, белый; 1
                       страница }
   CGAHi        = 2; { 640х200, 1 страница }
   MCGAC1       = 0  { 1 палитра цветов 320х200: красный,
                       желтый, зеленый; 1 страница }
   MCGAC2       = 1; { 2 палитра цветов 320х200: светло-
                       бирюзовый, малиновый, белый; 1
                       страница }
   MCGAMed      = 2; { 640х200, 1 страница }
   MCGAHi       = 3; { 640х480, 2 цвета, 1 страница }
   EGALo        = 0; { 640х200, 4 страницы }
   EGAHi        = 1; { 640х350, 16 цветов, 2 страницы }
   EGA64Lo      = 0; { 640х200, 16 цветов, 1 страница }
   EGA64Hi      = 1; { 640х350, 4 цвета, 1 страница }
   EGA64MonoHi  = 3; { 640х350, 64К на плату, 1 страница -
                       256К на плзту, 4 страницы }
   HercMonoHi   = 0; { 720х348, 2 страницы }
   ATT400C1     = 0; { 1 палитра цветов 320х200: красный,
                       желтый, зеленый; 1 страница }
   ATT400C2     = 1; { 2 палитра цветов 320х200: светло-
                       бирюзовый, малиновый, белый; 1
                       страница; 20 - 640х200, 1 страница }
   ATT400C3     = 3; { 3 палитра цветов 320х200: светло-
                       бирюзовый, малиновый, белый; 1
                       страница; 20 - 640х200, 1 страница }
   ATT400Med    = 4; { 640х200, 1 страница }
   ATT400Hi     = 5; { 640х200, 1 страница }
   VGALo        = 0; { 640х200, 16 цветов, 4 страницы }
   VGAMed       = 1; { 640х350, 16 цветов, 2 страницы }
   VGAHi        = 2; { 640х480, 16 цветов, 1 страница }
   VGANi2       = 3; { 640х480, 2 цвета, 1 страница }
   PC3270Hi     = 0; { 720х350, 1 страница }
   IBM8514LO    = 0; { 640х480 точек, 256 цветов }
   IBM8514HI    = 1; { 1024х768 точек, 256 цветов }

     Следующие константы можно  использовать  при  работе  с
процедурами SetPalette и SetAllPalette:

 const
  { цвета для процедур SetРаlette и SetАllРаlette }
   Black          = 0;      { черный }
   Blue           = 1;      { синий  }
   Green          = 2;      { зеленый }
   Cyan           = 3;      { бирюзовый }
   Red            = 4;      { красный }
   Magenta        = 5;      { малиновый }
   Brown          = 6;      { коричневый }
   LightGray      = 7;      { светло-серый }
   DarkGray       = 8;      { темно-серый }
   LightBlue      = 9;      { светло-голубой }
   LightGreen     = 10;     { светло-зеленый }
   LightCyan      = 11;     { светло-бирюзовый }
   LightRed       = 12;     { светло-красный }
   LightMagenta   = 13;     { светло-малиновый }
   Yellow         = 14;     { желтый }
   White          = 15;     { белый }

     Следующие константы цветов могут использоваться в  про-
цедуре  SetGRBPalette  для выбора стандартных цветов EGA при
работе с графической платой IBM 8514:

 const
  EGABlack          = 0;      { черный }
  EGABlue           = 1;      { синий  }
  EGAGreen          = 2;      { зеленый }
  EGACyan           = 3;      { бирюзовый }
  EGARed            = 4;      { красный }
  EGAMagenta        = 5;      { малиновый }
  EGABrown          = 20;     { коричневый }
  EGALightGray      = 7;      { светло-серый }
  EGADarkGray       = 56      { темно-серый }
  EGALightBlue      = 57;     { светло-голубой }
  EGALightGreen     = 58;     { светло-зеленый }
  EGALightCyan      = 59;     { светло-бирюзовый }
  EGALightRed       = 60;     { светло-красный }
  EGALightMagenta   = 61;     { светло-малиновый }
  EGAYellow         = 62;     { желтый }
  EGAWhite          = 63;     { белый }

     При работе с процедурами  GetLineStyle  и  SetLineStyle
можно использовать следующие константы типов линий:

 const
  { типы линий и их толщина для процедур Get или
    SetLineStyle }
   SolidLn       = 0;       { непрерывная линия }
   DottedLn      = 1;       { линия, состоящая из точек }
   CenterLn      = 2;       { центрированная линия }
   DashedLn      = 3;       { пунктирная линия }
   UserBitLn     = 4;       { тип линии, заданный пользова-
                              телем }
   NormWidth     = 1;       { обычная толщина }
   ThickWidth    = 3;       { жирная линия }

     При работе с процедурами  SetTextStyle  и  GetTextStyle
можно использовать следующие константы управления шрифтом:

 const
  { константы для процедур Set/GetTextStyle }
   DefaultFont  = 0;        { шрифт с побитовым отображением
                              8х8 }
   TriplexFont  = 1;        { "штриховой" шрифт }
   SmallFont    = 2;        { мелкий шрифт }
   SanScrifFont = 3;
   GothicFont   = 4;

   HorizDir       = 0;      { направление слева-направо }
   VertDir        = 1;      { снизу-вверх }
   NormSize       = 1;      { типовой размер }

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

 const
  { константы отсечения }
   ClipOn  =  true;
   ClipOff =  false;

     Следующие константы можно  использовать  при  работе  с
процедурой  Bar3D. Они задают, будет ли следующий параллеле-
пипед располагаться на вершине  предыдущего  (таким  образом
столбец будет наращиваться):

 const
  { константы Bar3D }
   TopOn   = true;
   TopOff  = false;

     Следующие константы образцов заполнителей  используются
процедурами GetFillSettings и SetFillStyle. Чтобы определить
ваш собственный образец заполнителя (UserFill),  используйте
процедуру   SetFillPattern,   а   затем  вызовите  процедуру
SetFillStyle. Например:

     SetFillStyle(UserFill, SomeColor)

 const
  { образцы заполнителей для процедур Get/SetFill/Style }
   EmptyFill     = 0;   { заполнить область фоновым цветом }
   SolidFill     = 1;   { непрерывное заполнение област  за-
                          данным цветом }
   LineFill      = 2;   { заполнить --- }
   LtSlashFill   = 3;   { заполнить /// }
   SlashFill     = 4;   { заполнить жирными линиями ///}
   BkSlashFill   = 5;   { заполнить \\\ (жирными линиями) }
   LtBkSlashFill = 6;   { заполнить \\\ }
   HatchFill     = 7;   { заполнить редкой штриховкой }
   XHatchFill    = 8;   { заполнить частой пересекающейся
                          штриховкой }
   InterLeaveFill = 9;  { заполнить прерывистой линией }
   WideDotFill   = 10;  { заполнить редкими точками }
   CloseDotFill  = 11;  { заполнить частыми точками }

     Следующие операции используются при работе с процедура-
ми PutImage и SetWriteMode:

 const
    CopyPut         = 0;            { MOV }
    XORPut          = 1;            { XOR }

     Сдедующие операции используются  только  при  работе  с
процедурой PutImage:

 const
  { битовые операции для процедуры PutImage }
   OrPut      = 2;  { OR }
   AndPut     = 3;  { AND }
   NotPut     = 4;  { NOT }

     Для определения записи PaletteType и при работе с  про-
цедурами  GetPalette,  GetDefaultPAlette,  SetAllPalette ис-
пользуется следующая константа:

 const
    MaxColors  = 15;

     Для горизонтального и вертикального выравнивания текста
при  работе с процедурой SetTextJustify используются следую-
щие константы:

 const
  { горизонтальное и вертикальное выравнивание для  процеду-
ры SetТехtJustify }
  CenterText = 1;  { центрирование текста }
  LeftText   = 0;  { выравнивание по левому краю }
  RightText  = 2;  { выравнивание по правому краю }
  BottomText = 0;  { перемещение текста в нижнюю часть экра-
                     на }
  TopText    = 2;  { перемещение текста в верхнюю часть  эк-
                     рана }

                            Типы

     Следующая запись используется в процедурах  GetPalette,
GetDefaultPalette и SetAllPalette:

 type
   PaletteType = record;
       Size   : byte;
       Colors : array[0..MaxColors] of shortint;
   end;

     Данная запись используется процедурой GetLineSettings:

 type
   LineSettingType = record
       LineStyle   : word;
       Pattern     : word;
       Thickness   : word;

     Следующая      запись      используется      процедурой
GetTextSettings:

 type
   TextSettingsType = record;
       Font       : word;
       Direction  : word;
       CharSize   : CharSizeType;
       Horiz      : word;
       Vert       : word;
   end;

     Следующая      запись      используется      процедурой
GetFillSettings:

 type
   FillSettingsType = record;
       Pattern    : word;
       Color      : word;
   end;

     Следующая     запись      используется      процедурами
GetFillPattern и SetFillPattern:

 type
   FillPatternType = array[1..8] of byte; { тип заполнителя,
                                определяемый пользователем }

     Этот тип введен для вашего удобства. Обратите внимание,
что поля записи имеют тип integer, а не word:

 type
   PointType = record
      X, Y : integer;
    end;

     Следующая      запись      используется      процедурой
GetViewSettings  для  сообщении  о состоянии текущей области
просмотра:

 type
   ViewPotrType = record
      x1, y1, x2, y2 : word;
      Clip           : boolean;
    end;

     Следующая запись используется процедурой GetArcCoords и
может служить для получения информации о последнем обращении
к процедурам Arc или Ellipse:

 type
   ArcCoordsType = record
      X, Y : integer;
      Xstart, Ystart, Xend, Yend : integer;
    end;

                         Переменные

      Данные переменные первоначально указывают на программы
управления динамически распределяемой областью памяти модуля
Graph. Если ваша программа использует  собственные  средства
управления  динамически  распределяемой  областью, присвойте
адреса ваших программ ваших процедур выделения и  освобожде-
ния  памяти  соответственно переменным GraphGetMemPtr и Gra-
phFreeMemPtr:

   GraphGetMemPtr : Pointer { позволяет пользователям  заме-
                              нить распределение  динамичес-
                              кой области }
   GraphFreeMemPrt : Pointer { позволяет пользователям заме-
                               нить распределение динамичес-
                               кой области }

                    Процедуры и функции

------------------------------------------------------------
     Процедура Аrс - рисует дугу  окружности  от  начального
угла до конечного угла; точка  (x,y) берется в качестве цен-
тра окружности.
     Процедура Ваr - рисует  столбец,  используя текущий тип
закраски.
     Процедура Ваr3D - рисует  трехмерный столбец, используя
текущий тип закраски.
     Процедура Сirclе - рисует  окружность с центром в точке
(x,y).
     Процедура СlearDeviсе -  сбрасывает  текущие параметры,
установленные  для  устройства  вывода, и подготавливает его
для вывода.
     Процедура ClearViewPort - очищает текущую область прос-
мотра (окно экрана).
     Процедура CloseGraph -  выполняет  останов  графической
системы.
     Процедура DetectGraph - распознает аппаратуру и опреде-
ляет, какой графический драйвер и режим нужно использовать.
     Процедура DrawPoly -  рисует  многоугольник,  используя
текущий тип линии и цвет.
     Процедура Еllipse - рисует  эллиптическую  дугу  от на-
чального угла до конечного угла, использую (Х,Y), как  точку
центра.
     Процедура FillPoly - закрашивает многоугольник, исполь-
зуя преобразователь развертки.
     Процедура FloodFill - закрашивает ограниченную область,
используя текущий образец закраски.
     Процедура GetArcCoods - позволяет пользователю запраши-
вать координаты последней команды Аrс.
     Процедура GetAspectRatio - возвращает  действующее раз-
решение графического экрана, на  основе  которого может быть
вычислен коэффициент относительного удлиннения (Хаsр,Yаsр).
     Функция GetВkСоlor - возвращает текущий фоновый цвет.
     Функция GetСоlor - возвращает текущий цвет рисунка.
     Процедура GetDefaultPalette - в записи типа PaletteType
возвращает используемую по умолчанию палитру.
     Функция GerDriverName - возвращает  строку,  содержащую
имя текущего драйвера.
     Процедура GetFillPattern - возвращает последний образец
заполнителя,  установленный  с помощью обращения к процедуре
SetFillPattern.
     Процедура GetFillSetting - позволяет  пользователю  вы-
полнить запрос о текущем образце и цвете  закраски, установ-
ленными с помощью процедур SetFillStyle и SetFillPattern.
     Функция GetGraphMode - возвращает  текущий  графический
режим.
     Процедура GetImage - сохраняет двоичный  образ заданной
области в буфере.
     Процедура GetLineSettings - возвращает  текущий тип ли-
нии, образец  линии и  толщину  линии,  заданные  процедурой
SetLineStyle.
     Функция GetMaxColor - возвращает максимальное  значение
цвета, которое можно передать процедуре SetColor.
     Функция GetMAxMode - возвращает максимальный номер  ре-
жима для текущего загруженного драйвера.
     Функция  GetМахХ -  возвращает для текущего графическо-
го драйвера и режима самую правую колонку (разрешение по х).
     Функция  GetМахY -  возвращает для текущего графическо-
го драйвера и режима самую нижнюю строку (разрешение по у).
     Процедура GetPalette - возвращает текущую палитру и  ее
размер.
     Функция  GetPaletteSize  -  возвращает  размер  таблицы
просмотра палитры.
     Функция GetPixel - возвращает значение элемента изобра-
жения в точке Х,Y.
     Процедура GetТехtSettings - возвращает текущий  тексто-
вый шрифт, направление, размер и выравнивание для  него, ус-
тановленные с помощью процедур SetТехtStyle и SetТехtJustify.
     Процедура GetViewSettings - позволяет  пользователю вы-
дать запрос о текущей области изображения и параметрах отсе-
чения изображения.
     Функция GetХ - возвращает координату Х  текущей позиции
(текущего указателя).
     Функция GetY - возвращает координату Y  текущей позиции
(текущего указателя).
     Функция GraphErrorMsg - для заданного кода ошибки возв-
ращает строку сообщения об ошибке.
     Функция GraphResult - возвращает код ошибки для послед-
ней графической операции.
     Функция ImageSize - возвращает  число  байтов,  которые
требуются для сохранения прямоугольной области экрана.
     Процедура InitGraph - инициализирует графическую систе-
му и переводит аппаратуру в графический режим.
     Функция InstallUserDriver -  устанавливает  добавленный
пользователем драйвер в таблице драйверов устройств BGI.
     Функция  InstallUserFont  -  устанавливает  новый  файл
шрифта, не встроенный в графическую систему.
     Процедура Line - рисует прямую линию из точки (x1,y1) в
(x2,y2).
     Процедура LineRel -  рисует   прямую  линию  до  точки,
представляющей  собой  относительное  расстояние от текущего
указателя.
     Процедура LinеТо - рисует линию из текущего положения в
точку (x,y).
     Процедура МоveRеl -  перемещает  текущий  указатель  на
расстояние, являющееся  относительным расстоянием от текущей
позиции.
     Процедура МоvеТо - перемещает текущий указатель в точку
(x,y).
     Процедура ОutТехt - посылыет строку на устройство выво-
да, начиная с текущего указателя.
     Процедура ОutТехtХY - посылает строку на устройство вы-
вода.
     Процедура РieSlice - рисует сектор; точка (Х,Y) исполь-
зуется в качестве центра, а сектор рисуется от начального до
конечного угла.
     Процедура РutImagе - выводит на экран двоичный образ.
     Процедура РutРiхеl - строит элемент изображения в точке
x,y.
     Процедура Rесtanglе - рисует  прямоугольник,  используя
текущий тип линии и цвет.
     Функция  RegisterBGIDriver  -  регистрирует  допустимый
драйвер (формата BGI) в графической системе.
     Функция RegisterBGIFont -  регистрирует  в  графической
системе допустимый (формата BGI) шрифт.
     Процедура RеstorеСRТ - восстанавливает для Сrt видеоре-
жим, установленный при загрузке.
     Процедура RеstoreСRТМоdе - восстанавливает исходный ре-
жим экрана, который был  установлен при инициализации графи-
ки.
     Процедура SetActivePage - устанавливает для графическо-
го вывода активную страницу.
     Процедура SetAllPalette - изменяет все  цвета  палитры,
как было указано.
     Процедура SetAspectRatio - изменяет принятый по умолча-
нию коэффициент относительного удлиннения.
     Процедура SetВkСоlor - используя палитру, устанавливает
текущий фоновый цвет.
     Процедура SetColor - используя  палитру,  устанавливает
текущий цвет рисунка.
     Процедура SetFillPattern - выбирает  образец  закраски,
заданный пользователем.
     Процедура SetFillStyle - устанавливает образец закраски
и ее цвет.
     Процедура SetGraphBufSize - позволяет  изменить  размер
буфера, используемого для опроса и закраски.
     Процедура SetGraphMode - переключает систему  в  графи-
ческий режим и очищает экран.
     Процедура SetLineStyle - устанавливает  текущий тип ли-
нии и ее ширину.
     Процедура SetPalette - изменяет один цвет  палитры, за-
данный переменными Colornum и Color.
     Процедура SetGRBPalette - позволяет модифицировать  за-
писи палитры для драйверов IBM-8514 и VGA.
     Процедура SetТехtJustify -   с   помощью    ОutТеxt   и
ОutТехтХY устанавливает значения для выравнивания текста.
     Процедура SetТехtStyle -   задает   текущий   текстовый
шрифт, его тип и коэффициент размера символа.
     Процедура SetUserCharSize - позволяет вам для штриховых
шрифтов изменить высоту и ширину символа.
     Процедура SetViewPort - для  графического  вывода уста-
навливает текущую область вывода или окно.
     Процедура SetVisualPage - задает визуальный номер стра-
ницы графики.
     Процедура SetWriteMode - устанавливает режим вывода  на
экран  (копирование  или  с помощью операции XOR) для линий,
вычерчиваемых процедурами DrawPoly, Line,  LineRel,  LineTo,
Rectangle.
     Функция ТехtНеight - возвращает высоту страниц  в  эле-
ментах изображения.
     Функция ТехtWidth - возвращает ширину строки в  элемен-
тах изображения.
------------------------------------------------------------

     Подробное описание каждой процедуры и  функции  дано  в
Главе 16.

                       Модуль Тurbo3

     Каждая программа в этом модуле является повторением или
улучшенным вариантом программ из других стандартных модулей.
Модуль Тurbo3 предусмотрен только в целях обратной совмести-
мости.  С  помощью  модуля  Тurbo3 вы можете добиться лучшей
совместимости с  версией  3.0,  но потеряете при этом прямой
доступ к важным  новым средствам, которые дублируются здесь.
(Заметим,   что вы можете использовать эти стандартные прог-
раммы с  помощью дополнительного синтаксиса блока. Так, нап-
ример,    МемАvail    модуля    Тurbo3    вызывает   функцию
Systтем.МемАvail, даже если в своей программе вы используете
модуль Тurbo3. Более подробно о том, как  использовать прог-
раммы с теми же именами в  других  блоках,  рассказывается в
Главе 4, в разделе "Модули и связанные и ними тонкости".)

      Примечание: Описанные далее  программы  не  описаны  в
      справочном разделе Главы 16.  Более подробная информа-
      ция о программах модуля  Тurbo3 содержится в "Справоч-
      ном руководстве по Турбо-Паскалю, версия 3.0".


                    Интерфейсная секция

     Приведем пример интерфейсной секции модуля Тurbo3:

   unit Turbo3;
   interface
   uses Crt;
   var
     Kbd: Text;
     Cbreak: Boolean absolute CheckBreak;
   function MemAvail: integer;
   function MaxAvail: integer;
   function LongFileSize(var F): real;
   function LongFIlePos(var F): real;
   procedure LongSeek(var F; Pos: real);
   procedure HighVideo;
   procedure NormVideo;
   procedure LowVideo;
   function IOResult : integer;

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

                        Драйвер Кbd

     Этот драйвер предусмотрен для программ версии 3.0,  ко-
торые    считывают    данные    с    клавиатуры   (например,
Rеаd(Кbd,СharVar)). Заметим, что теперь эта функция включена
в модуль Сrt и  называется  RеаdКеy.  Поэтому ее следует ис-
пользовать вместо Rеаd(Кbd,СharVar). Далее следуют две прог-
раммы, которые считывают символ  с  клавиатуры  и  сообщает,
была ли нажата клавиша из  расширенного набора (F1,F2, левая
стрелка и т.д.):

  program TestKbd;
  uses Crt, Turbo3;
  var
    c: char;
  begin
    Read(Kbd, c);
    if (c = #27) and KeyPressed then
    begin
      Read(Kbd, c);
      Writeln('Extended key:', c);
    end
    else
      Writeln(c);
  end;

     Заметим, что драйвер Кbd преобразует клавиши  расширен-
ного набора от (ноль +  символ)  до  (ЕSС +  второй символ).
Поскольку клавиша ЕSС ( 27) - это обычная клавиша, использу-
емая для ввода с  клавиатуры, то для того, чтобы определить,
была ли нажата перой клавиша с кодом  27 из расширенного на-
бора или действительно использовалась клавиша ЕSС, нужно ис-
пользовать функцию  КеyРressed. Если была нажата клавиша ЕSС
и за ней до того, как программа смогла распознать ЕSС, быст-
ро последовал другой символ, то две клавиши были бы ошибочно
распознаны, как клавиши из расширенного набора.
     В версии 5.0 Турбо-Паскаля:

 program TestReadKey;
 uses Crt;
 var
   c : char;
 begin
   c := ReadKey;
   if (c = #0) then
      Writeln('Extended key: ', ReadKey);
   else
      Writeln(c);
   end;

     Исходный код в версии 5.0 имеет меньший объем (и выпол-
няется быстрее) и не содержит двусмысленности по отношению к
нажатию первого символа при использовании расширенного набо-
ра клавиш.  (Невозможно  иначе получить нулевой символ с по-
мощью  клавиатуры,  кроме  как воспользовавшись клавишами из
расширенного набора.)

                     Переменная Сbrеаk

     Переменная   Сbrеаk   в  версии   5.0  переименована  в
СhесkBreak. Обратная совместимость достигается путем присво-
ения переменной Сbreak того же адреса, что и СhесkBreak, ко-
торая описывается в  модуле  Сrt.  Оператор  Сbreak := Falsе
выключает проверку на  нажатие клавиш Сtrl-Вreak, а оператор
Сbreak := Тruе снова ее включает.
     В модуле Тurbо3 имеются следующие процедуры и функции:

------------------------------------------------------------
     Функция МемАvail - возвращает число  свободных парагра-
фов для имеющейся динамически рапределяемой области памяти.
     Функция МахАvail - возвращает размер наибольшего непре-
рывного свободного блока в динамически распределяемой облас-
ти (в параграфах).
     Функция LongFileSize - возвращает объем файла.  Возвра-
щаемое значение представляет собой вещественное число.
     Функция LongFilePos - возвращает для файла  текущую по-
зицию файла.  Возвращаемое значение  представляет  собой ве-
щественное число.
     Процедура LongSeek - перемещает текущую позицию файла к
заданному элементу. Для задания номера элемента используется
параметр, представляющий собой действительное число.
     Процедура HighVideo - устанавливает видеоатрибут в жел-
тый на черном фоне (цветные системы)  белый  на  черном фоне
(черно-белые, монохроматические системы).
     Процедура NormVideo - то же, что и HightVideo. Устанав-
ливает видеоатрибут в желтый на черном  фоне (цветные систе-
мы) белый на черном  фоне  (черно-белые,  монохроматические
системы).
     Процедура LowVideo - устанавливает видеоатрибут в свет-
ло-серый на черном фоне (LigthGray).
     Функция IОRеsult - возвращает целое значение, представ-
ляющее  собой  состояние  последней выполненой операции вво-
да-вывода. Там,  где  это  возможно, функция IOResult модуля
Тurbо3 возвращает коды, совместимые с кодами версии 3.0.
------------------------------------------------------------

                       Модуль Graph3

     Модуль Graph3  -  это  прямая  реализация  графического
драйвера,  использующего только относительные команды, кото-
рый имеется в версии 3.0 Турбо-Паскаля.  В версии  3.0  Тур-
бо-Паскаля драйвер, использующий относительные команды, сос-
тоял из двух файлов -  GRAPH.Р и GRAPH.ВIN.  GRAРН.Р в  дей-
ствительности определяет программы внешнего  машинного кода,
содержащегося в GRAPH.BIN.  Модуль Graph3 объединяет GRAPH.Р
и GRAPH.BIN в один  блок,  сохраняющий  свое  функциональное
назначение. Единственное изменение, которое вы должны внести
в программу, использующую версию 3.0 Турбо-Паскаля  и  драй-
вер, работающий с  относительными  командами,  это  удаление
директивы компилятора {$I GRAPH.Р} и замена ее в предложении
использования (uses) программы ссылками на Сrt и Graph3.

      Примечание:  Приводимые  далее  программы не описаны в
      справочном разделе Главы 16.  Более подробная информа-
      ция по  программам модуля Graph3 содержится в справоч-
      ном руководстве по версии 3.0 Турбо-Паскаля.

             Процедуры и функции модуля Graph3

------------------------------------------------------------
     Процедура GraphColorMode - устанавливает цветной графи-
ческий режим 320х200.
     Процедура GraphMode - устанавливает черно-белый  графи-
ческий режим 320х200.
     Процедура Hires - устанавливает для экрана  графический
режим с разрешением 640х200.
     Процедура Раlette - активизирует заданную  палитру цве-
тов.
     Процедура HiResColor - выбирает  цвета,  использующиеся
для изображений в графике  с  высокой  разрешающей способно-
стью.
     Процедура GraphBackGround -  устанавливает фоновый цвет
экрана.
     Процедура GraphWindow - возволяет вам в любом гарфичес-
ком режиме определить область экрана, как активное окно.
     Процедура Plot - строит точку заданного  цвета с задан-
ными координатами.
     Процедура Draw - рисует  прямую  линию  заданного цвета
между заданными точками.
     Процедура ColorTable -  задает  таблицу  преобразования
цветов, которая позволяет для  текущего цвета в любой задан-
ной точке определить новый  цвет этой точки, когда она будет
заново нарисована.
     Процедура Аrс -  используя  заданные  параметры  рисует
дугу.
     Процедура Circle - рисует окружность.
     Процедура GetPic - копирует содержимое области на экра-
не в буфер.  Это содержимое можно  потом  восстановить с по-
мощью процедуры PutPic.
     Процедура PutPic - копирует содержимое буфера.
     Процедура GetDotColor -  возвращает  значение  цвета  в
точке в указанном месте.
     Процедура FillScreen - заполняет все активное окно ука-
занным цветом.
     Процедура FillShape - заполняет заданным цветом область
любой формы.
     Процедура FillPattern - заполняет прямоугольную область
по текущему образцу, используя указанный цвет.
     Процедура Pattern -  определяет  образец  8х8,  который
должен использоваться в процедуре FillPattern.
     Процедура Васk - [для графики, использующей относитель-
ные команды] перемещает маркер назад на заданное расстояние.
     Процедура Forwd - [для  графики,  использующей  относи-
тельные команды]  перемещает  маркер вперед на заданное рас-
стояние.
     Процедура ClearScreen - [для графики,  использующей от-
носительные команды] очищает активное окно и перемещает мар-
кер в начало экрана.
     Процедура Неаding - [для графики,  использующей относи-
тельные команды] возвращает текущую головку маркера.
     Процедура HideTurtle - [ для графики,  использующей от-
носительные команды] делает маркер невидимым.
     Процедура Номе - [для графики, использующей относитель-
ные команды] помещает маркер в начало (левый верхний угол)
украна.
     Процедура NoWrap - [для графики,  использующей  относи-
тельные команды] запрещает автоматический переход  маркера к
началу следующей строки при достижении границы экрана.
     Процедура РеnDown - [для графики, использующей  относи-
тельные команды] "опускает"  маркер (аналог поднятия пера на
графопостроителе), так что любое перемещение маркера  приво-
дит к вычерчиванию линии.
     Процедура РеnUр - [для  графики,  использующей  относи-
тельные команды] "поднимает" маркер. При этом его можно  пе-
ремещать без вычерчивания линии.
     Процедура SetHeading - [для графики, использующей отно-
сительные команды] поворачивает головку маркера на  заданный
угол.
     Процедура SetPenColor - [для графики,  использующей от-
носительные команды]  устанавливает  цвет,  используемый для
рисунка при перемещении маркера.
     Процедура SetPosition - [для графики, использующей  от-
носительные команды] перемещает маркер в  точку с  заданными
координатами без вычерчивания линии.
     Процедура ShowTurtle - [для графики, использующей отно-
сительные команды] делает маркер видимым.
     Процедура TurnLeft - [для графики, использующей относи-
тельные команды] поворачивает головку  маркера влево (против
часовой стрелки).
     Процедура TurnRight - [для графики,  использующей отно-
сительные команды] поворачивает  головку  маркера вправо (по
часовой стрелке).
     Процедура TurnWindow - [для графики, использующей отно-
сительные команды]  определяет  область экрана, как активную
область.
     Процедура TurtleThere - [для  графики, использующей от-
носительные команды] проверяет,  является ли маркер в актив-
ном окне экрана видимым.
     Процедура TurtleDelay - [для  графики, использующей от-
носительные команды] устанавливает задержку между каждым пе-
ремещением маркера.
     Процедура Wrap - [для графики, использующей относитель-
ные команды] автоматически перемещает маркер к противополож-
ной границе экрана при достижении края экрана.
     Процедура ХСоr - [для графики, использующей относитель-
ные команды] возвращает текущую Х-координату маркера.
     Процедура YСоr - [для графики, использующей относитель-
ные команды] возвращает текущую Y-координату маркера.
------------------------------------------------------------





                          ГЛАВА 13

                          Оверлеи

     Оверлеи (которые называют также перекрытиями или  нало-
жениями)  представляют  собой  части программы, которые сов-
местно используют общую область памяти. В один и тот же  мо-
мент  времени  резидентно  размещаться в памяти может та или
иная часть программы, необходимая  для  выполнения  заданной
функции. В процессе выполнения эти части программы могут за-
мещать друг друга.
     Оверлеи могут значительно сократить объем памяти, необ-
ходимый  для выполнения программы. Фактически, так как в лю-
бой момент времени в памяти  резидентно  размещаются  только
части  программы,  с  помощью  оверлеев  вы можете выполнять
программы, значительно превосходящие по объему доступную па-
мять.
     Турбо-Паскаль управляет оверлеями  на  уровне  модулей,
которые  являются  наименьшей  частью  программы, образующей
оверлей. При компияции программы, имеющей оверлейную  струк-
туру,  Турбо-Паскаль  генерирует наряду с выполняемым файлом
(который имеет расширение  .EXE)  оверлейный  файл  (имеющий
расширение  .OVR) Файл с расширением .ЕХЕ содержит статичес-
кие (не оверлейные) части программы, а  файл  с  расширением
.OVR  содержит все оверлейные модули, которые при выполнении
программы будут подкачиваться в  память  или  выводиться  из
нее на диск.
     За исключением нескольких правил  его  программирования
оверлейный  модуль полностью идентичен неоверлейному модулю.
Фактически, если вы соблюдаете эти правила, у вас нет  необ-
ходимости перекомпилировать модуль, чтобы образовать из него
оверлей. Решение о том, будет  модуль  оверлейным  или  нет,
принимается программой, которая использует данный модуль.
    При загрузке оверлеев в память они помещаются в оверлей-
ный буфер, который размещается в памяти между сегментом сте-
ка и динамически распределяемой областью памяти. По  умолча-
нию  для оверлейного буфера выбирается минимальный возможный
размер, но во время выполнения программы  его  размер  может
быть  легко  увеличен путем выделения дополнительной области
памяти из  динамически  распределяемой  области.  Аналогично
сегменту данных и минимальному размеру динамически распреде-
ляемой области, оверлейный буфер принятого по умолчанию раз-
мера  выделяется при загрузке файла .ЕХЕ. При отсутствии па-
мяти необходимого объема модулем Dos или диалоговой програм-
мной средой будет  выводиться  сообщение  об ошибке (Program
too big to fit in memory -  программа слишком велика,  чтобы
разместиться в памяти) или (Not enough memory to  run  prog-
ram - для запуска программы не хватает памяти).
     Одной из очень важных возможностей подсистемы  управле-
ния  оверлеями является возможность при наличии достаточного
пространства загружать оверлейный файл в расширенную память.
Для этой цели в Турбо-Паскале поддерживается средство расши-
рения  памяти  EMS  (Lotus/Intel/Microsoft  Expanded  Memory
Specification).  При  размещении оверлейного файла в EMS все
последующие загрузки оверлеев сводятся  к  быстрой  передаче
информации из памяти в память.

                     Модуль Overlay

     Подсистема управления оверлеями Турбо-Паскаля  реализу-
ется с помощью стандартного модуля Overlay. В модуле Overlay
используются усовершенствованные методы управления буферами,
что обеспечивает оптимальное выполнение программы в имеющей-
ся области памяти. Например, подсистема управления оверлеями
сохраняет в оверлейном буфере столько оверлеев, сколько воз-
можно. Это позволяет уменьшить частоту считывания оверлев  с
диска. Послу загрузки оверлея вызов одной из его подпрограмм
выполняется также быстро, как обращение к неоверлейной прог-
рамме.  Кроме  того, когда у подсистемы управления оверлеями
возникает необходимость вывести один оверлей, чтобы  освобо-
дить место для другого,  она  сначала  пытается  вывести  те
оверлеи, которые не являются активными (то есть  те, которые
в данный момент времени не содержат активных программ).
     Для реализации улучшенных методов управления  оверлеями
Турбо-Паскаль  требует от вас при написании программы, в ко-
торой используются оверлеи, соблюдать два важных правила:

     1.  Все оверлейные модули  должны  содержать  директиву
         {$O+},  приводящую к тому, что компилятор обеспечи-
         вает гененирование оверлейного кода.
     2.  При каждом  обращении  к  оверлейной процедуре  или
         функции  вы  должны  обеспечить использование всеми
         активными процедурами и функциями вызовов типа  FAR
         (дальний тип вызова).

     Оба правила будут поясняться далее в разделе под  заго-
ловком  "Разработка  оверлейных  программ". Сейчас мы просто
отметим, что вы можете легко удовлетворить эти правила,  по-
местив  в  начале  оверлейных  модулей директиву компилятора
{$O+,F+}, а в начале всех других модулей и основной програм-
мы - директиву {$F+}.

           Примечание: Несоблюдение  требование  обеспечения
      дальнего  типа  вызова  в оверлейной программе вызовет
      непредсказуемые и возможно катастрофические результаты
      при выполнении программы.

     Директива компилятора {$O  имя_модуля}  используется  в
программе  для указания того, какой  из  модулей будет овер-
лейным. Эта директива дожна размещаться за предложением  ис-
пользования  программы,  в котором перед именами всех других
оверлейных модулей должно указываться имя стандартного моду-
ля Overlay. Приведем следующий пример:

  program Editor;
  {F+}              { Все процедуры и функции будут
 использовать
                      дальний тип вызова }
  uses
   Overlay, Crt, Dos, EdInOut, EdFormat, EdPrint, EdFind,
 EdMain
  {$O EdInOut }
  {$O EdFormat }
  {$O EdPrint }
  {$O EdFind }
  {$O EdMain }

           Примечание: Если вы пытаетесь  использовать,  как
      оверлейный,  модуль,  при  компиляции которого не была
      указана директива {$O+}, то компилятор выведет сообще-
      ние  об  ошибке.  Что касается стандартных модулей, то
      оверлейным может быть только модуль Dos. Другие  стан-
      дартные  модули  (System, Crt, Overlay, Graph, Turbo3,
      Graph3) не могут использоваться в качестве оверлейных.
      К  тому  же  программы,  содержащие оверлейные модули,
      должны компилироваться на диск. Если вы пытаетесь  вы-
      полнить компиляцию таких программ в память,  то компи-
      лятор выводит сообщение об ошибке.

                   Константы и переменные

     В этом разделе кратко описываются константы и  перемен-
ные, определенные в модуле Overlay.

                    Переменная OvrResult

     Перед возвратом управления каждая  процедура  в  модуле
Overlay   сохраняет   свой   код   результата  в  переменной
OvrResult.

     var OvrResult : integer;

     Возможные коды возврата определены в описании  констант
в следующем разделе. В общем случае нулевое значение говорит
об успешном завершении.
     Переменная  OvrResult  напоминает  стандартную  функцию
IOResult,  за исключением того, что переменная OvrResult при
обращении к ней не устанавливается в значение 0. Таким обра-
зом,   отпадает   необходимость   в  копировании  переменной
OvrResult перед ее проверкой в локальную переменную.

                      Коды результата

     Ошибки, возникающие в модуле Overlay, сообщаются с  по-
мощью переменной OvrResult. Определены следующие коды:

  const
    ovrOk = 0;           { успешное завершение }
    ovrError = -1;       { ошибка подсистемы управления
                           оверлеями }
    ovrNotFound = -2;    { не найден оверлейный файл }
    ovrNoMemory = -3;    { не хватает памяти для оверлей-
                           ного буфера }
    ovrIOError = -4;     { ошибка ввода-вывода оверлейно-
                           го файла }
    ovrNoEMSDriver = -5;  { не установлен драйвер EMS }
    ovrNoEMSMemory = -6;  { не хватает расширенной памяти }

                    Процедуры и функции

     В  оверлейном  модуле  Overlay   определены   процедуры
OvrInit,  OvrInitEMS, OvrSetBuf и OvrclearBuf, а также функ-
ция OvrGetBuf. Далее приведено краткое  описание  каждой  из
них. Более подробная информация дается в Главе 8 ("Процедуры
и функции").

                     Процедура OvrInit

     procedure OvrInit(имя_файла : string);

     Эта  процедура  инициализирует  подсистему   управления
оверлеями   и   открывает  оверлейный  файл.  Если  параметр
"имя_файла" не задает дисковод или  каталог,  то  подсистема
управления оверлеями выполняет поиск файла в текущем катало-
ге, каталоге, содержащем файлы .ЕХЕ (при работе в операцион-
ной системе ДОС 3.х) и в каталогах, заданных с помощью пере-
менной операционной среды ДОС PATH. Возможными кодами  возв-
рата  по  ошибке  являются  коды ovrError или ovrNotFound. В
случае ошибки подсистема управления оверлеями остается неус-
тановленной,  и попытка вызывать оверлейную программу приве-
дет к ошибки времени выполнения 208.

           Примечание: Процедура OvrInit  должна  вызываться
      перед  любой  другой  процедурой подсистемы управления
      оверлеями.

                    Процедура OvrInitEMS

     procedure OvrInitEMS;

     Данная процедура, если это возможно, загружает оверлей-
ный файл в расширенную память (EMS).  При этом все последую-
щие загрузки оверлеев сводятся к быстрой передаче информации
из памяти  в память.  Возможными кодами  возврата по  ошибке
являются     ovrError,     ovrIOError,     ovrNoEMSError   и
ovrNoEMSMemory. Подсистема управления оверлеями  будет  про-
должать работу, но оверлеи будут считываться с диска.

           Примечание: Использование для размещения оверлеев
      в  памяти  процедуры OvrInitEMS не устраняет необходи-
      мости работы с оверлейным буфером. Оверлеи тем не  ме-
      нее перед их выполнением должны копироваться из памяти
      EMS в обычную память  (в  оверлейный  буфер).  Однако,
      поскольку  передача  из памяти в память осуществляется
      значительно быстрее, чем чтение с диска, необходимость
      увеличения размера оверлейного буфера становится менее
      очевидной.

                    Процедура OvrSetBuf

     procedure OvrSetBuf(размер : longint)

     Данная процедура задает размер оверлейного буфера. Ука-
занный размер должен быть больше или равен начальному разме-
ру оверлейного буфера  и  быть  больше  или  равен  значению
MemAvail,  плюс текущий размер оверлейного буфера. Если ука-
занный размер больше текущего размера, то с  начальной  гра-
ницы динамически распределяемой области памяти отводится до-
полнительное пространство (таким образом, размер динамически
распределяемой области уменьшается). Если же заданный размер
меньше текущего размера, то избыточное пространство  возвра-
щается в динамически распределяемую область памяти. Процеду-
ра OvrSetBuf требует, чтобы динамически  распределяемая  об-
ласть  памяти  была  пустой. Если с помощью процедур New или
GetMem уже были образованы динамические переменные, то возв-
ращается  ошибка. Возможными кодами возврата по ошибке явля-
ются ovrError и ovrNoMemory. Если процедура OvrSetBuff возв-
ращает ошибку, то подсистема управления оверлеями будет про-
должать работу, однако размер оверлейного  буфера  останется
неизмененным.

                    Процедура OvrGetBuf

     function OvrGetBuf:longint;

     Возвращает текущий размер оверлейного буфера.  Первона-
чально  оверлейный  буфер имеет наименьший возможный размер,
соответствующий размеру наибольшего оверлея. При  выполнении
оверлейной программы буфер такого размера выделяется автома-
тически. (Примечание: Начальный размер буфера  может  превы-
шать  64К,  так  как он включает в себя код и дополнительную
информацию для самого большого оверлея.)

                   Процедура OvrClearBuf

     procedure OvrClearBuf;

     Данная процедура очищает оверлейный буфер.  Все  загру-
женные  в  настоящий момент оверлеи удаляются из оверлейного
буфера, вынуждая при  всех  последующих  вызовах  оверлейных
программ  выполнять  загрузку  оверлеев из оверлейного файла
(или из памяти EMS). Если процедура  OvrClearBuf  вызывается
из  оверлея, то этот оверлей будет немедленно загружен, пока
не завершится выполнение процедуры  OvrClearBuf.  Подсистема
управления оверлеями никогда не требует от вас вызова проце-
дуры OvrClearBuf. Фактически, обращение к  данной  процедуре
уменьшит производительность вашей прикладной задачи, так как
это приводит к перезагрузке оверлеев. Поэтому данная  проце-
дура  предназначена для использования в особых случаях, нап-
ример для временного освобождения памяти,  занимаемой  овер-
лейным буфером.

              Разработка программ с оверлеями

     В этом разделе дается наиболее  важная  информация  про
разработке программ с оверелями. Просмотрите ее внимательно:
для хорошей работы прикладных программ, в которых  использу-
ются  оверлеи,  многие обсуждаемые вопросы являются жизненно
важными.

                 Генерация оверлейного кода

     Турбо-Паскаль допускает использование модуля в качестве
оверлейного только в том случае, если он генерировался с ди-
рективой {$O+}. Когда задана эта директива, генератор выпол-
няемого  кода при передаче строки из одной оверлейной проце-
дуры в другую и задании постоянных параметров  предпринимает
особые  меры  предосторожности.  Например, если модуль UnitA
содержит процедуру со следующим заголовком:

  procedure WriteStr(s: string);

и модуль UnitB содержит оператор:

  WriteStr('Hello word...');

то  Турбо-Паскаль  помещает   строковую   константу   'Hello
word...' в сегмент кода модуля UnitB и передает указатель на
него процедуре WriteStr. Однако, если  оба  модуля  являются
оверлейными, то это работать не будет, поскольку при обраще-
нии в WriteStr сегмент кода модуля UnitB может быть перекрыт
модулем UnitA, и ссылка на строку окажется недопустимой. Для
того, чтобы избежать эти  проблемы,  используется  директива
{$O+}. Каждый раз, когда Турбо-Паскаль встречет обращение из
одного модуля, скомпилировнного с директивой {$O+}, к друго-
му  модулю, скомпилированному с директивой {$O+}, компилятор
перед передачей ссылок на них обеспечивает временное копиро-
вание всех размещенных в сегменте кода констант в стек.
     Использование в модуле директивы {$O+} не обязывает вас
использовать  этот модуль, как оверлейный. Она просто указы-
вает Турбо-Паскалю на необходимость  обеспечения,  если  это
нужно,  использования данного модуля в качестве оверлейного.
Если вы разрабатываете модули, которые планируете  использо-
вать  как  в  оверлейных,  так  и  в неоверлейных прикладных
программах, то компиляция их с директивой {$O+} обеспечивает
использование одной версии модуля для обоих случаев.

       Требование использования дальнего типа вызовов

     Как уже упоминалось ранее, при любом обращении к  овер-
лейной  процедуре  или  функции  из другого модуля вы должны
обеспечить для всех активных процедур и функций вызовы  типа
FAR (дальний тип вызова).
     Это можно хорошо проиллюстрировать на следующем  приме-
ре.  Предположим,  что  OvrA  представляет собой процедуру в
оверлейном модуле, а процедуры MainC и MainD -  процедуры  в
основной  программе. Если основная программа вызывает MainC,
которая вызывает процедуру MainB, которая в свою очередь об-
ращается к процедуре OvrA, то во время обращения к процедуре
OvrA процедуры MainC и MainB являются активными (они еще  не
выполнили  возврат управления), поэтому необходимо использо-
вать для них дальний тип вызова. Описанные в основной  прог-
рамме, процедуры MainC и MainB в обычной ситуации используют
ближний тип вызовов (NEAR). С помощью директивы  компилятора
{$F+} необходимо задать дальний тип вызовов.
     Самый легкий способ удовлетворения требования использо-
вания  дальнего  типа  вызовов состоит в размещении в начале
основной программы  и  в  начале  каждого  модуля  директивы
{$F+}. Альтернативный способ состоит в изменении принятой по
умолчанию установки $F на {$F+} с помощью  директивы  коман-
дной  строки  /$F+  (ТРС.ЕХЕ)  или  с  помощью  меню  команд
O/C/Force Far Calls в среде интерактивного  компилятора.  По
сравнению со смешанным  использованием  вызовов  ближнего  и
дальнего типа использование вызовов только типа FAR не  при-
водит к особенно большим дополнительным затратам памяти: для
этого требуется одно дополнительное слово пространства стека
на активную процедуру и один дополнительный  байт на  каждый
вызов.

       Инициализация подсистемы управления оверлеями

     Здесь мы рассмотрим некоторые примеры того, как инициа-
лизируется  подсистема управления оверлеями. Код инициализа-
ции должен быть помещен перед первым обращением к оверлейной
программе. Инициализацию обычно следует делать в операторной
части программы.
     Следующая часть программы показывает, как немного  тре-
буется  для того, чтобы инициализировать подсистему управле-
ния оверлеями.

  begin
    OvrInit('EDITOR.OVR');
  end;

     Проверка на ошибки не делается. Поэтому если для  овер-
лейного буфера не хватает памяти или оверлейный файл не най-
ден, то при попытке вызова оверлейной  программы  произойдет
ошибка  208  (Overlay manager not installed - подсистема уп-
равления оверлеями не установлена).
     Приведем другой небольшой пример, являющийся расширени-
ем предыдущего.

  begin
    OvrInit('EDITOR.OVR');
    OvrInitEMS;
  end;

     В этом случае, если предположить, что  для  оверлейного
буфера  имеется достаточно памяти и что можно найти оверлей-
ный файл, подсистема управления оверлеями проверяет, имеется
ли  память  EMS, и если это так, загружает оверлейный файл в
расширенную память.
     Как уже упоминалось ранее, начальный размер оверлейного
буфера  выбирается  минимально  возможным или, иначе говоря,
настолько большим, чтобы вместить оверлей наибольшего разме-
ра.  Для  некоторых прикладных задач этого может быть доста-
точным, однако представим  ситуацию,  при  которой  одна  из
функций программы реализуется с помощью двух или более моду-
лей, каждый из который является оверлейным. Если общий  раз-
мер таких модулей больше, чем размер наибольшего оверлея, то
частое обращение модулей друг к другу  приведет  к  большому
свопингу.
     Очевидно, решение заключается в  том,  чтобы  увеличить
размер  оверлейного  буфера таким образом, чтобы в любой за-
данный момент времени имелось достаточно  памяти  для  того,
чтобы  содержать в себе все оверлеи, часто обращающиеся друг
к другу. Следующая часть программы показывает  использование
для   увеличения   размера   оверлейного   буфера  процедуры
OvrSetBuf:

  const
    OvrMaxSize = 80000;
  begin
    OvrInit('EDITOR.OVR');
    OvrInitEMS;
    OvrSetBuf(OvrMaxSize);
  end;

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

           Примечание:  Использование  процедуры  OvrInitEMS
      для  размещения оверлейного файла в расширенной памяти
      не устраняет необходимости работы с  оверлейным  буфе-
      ром.  Ведь  оверлеи  перед  выполнением  тем  не менее
      должны копироваться из расширенной  памяти  в  обычную
      (то  есть в оверлейный буфер). Однако, поскольку такие
      передачи из памяти в  память  выполняются  значительно
      быстрее, чем чтение с диска, то необходимость увеличе-
      ния размера оверлейного буфера становится  менее  оче-
      видной.  Нужно  также  помнить  о  том,  что процедура
      OvrSetBuf увеличивает  размер  оверлейного  буфера  за
      счет уменьшения размера динамически распределяемой об-
      ласти памяти. Таким образом, динамически  распределяе-
      мая   область  должна  быть  пустой,  иначе  процедура
      OvrSetBuf не окажет никакого действия. Если вы исполь-
      зуете  модуль  Graph, убедитесь в том, что вы обращае-
      тесь к процедуре  OvrSetBuf  перед  вызовом  процедуры
      InitGraph, которая выделяет память в динамически расп-
      ределяемой области.

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

  const
    OvrMaxSize = 80000;
  var
    OvrName: string[79];
    Size: Longint;
  begin
    OvrName:='EDITOR.OVR';
    repeat
      OvrInit(OvrName);
      if OvrResult=ovrNotFound then
      begin
        WriteLn('Оверлейный файл не найден');
        WriteLn('Введите правильное имя оверлейного
 файла:');
        ReadLn(OvrName);
      end;
     until OvrResult<>ovrNotFound;
     if OvrResult<>ovrOk then
     begin
       WriteLn('Ошибка опдсистемы управления оверлеями.')
       Halt(1);
     end;
     OvrInEMS;
     if OvrResult<>OvrOk then
     begin
       case OvrResult of
         ovrIOError:      Write('Ошибка ввода-вывода
                                 оверлейного файла');
         ovrNoEMSDriver:  Write('Драйвер EMS не
                                 установлен');
         ovrNoEMSMemory:  Write('Не хватает расширенной
                                 памяти');
     end;
     Write('. Нажмите клавишу Enter...');
     ReadLn;
   end;
   OvrSetBuf(OvrMaxSize);
  end;

     Сначала, если принятое  по  умолчанию  имя  оверлейного
файла было неверным, пользователю будет выводиться подсказка
на введение правильного имени файла.
     Далее проверяются другие ошибки, которые могут произой-
ти  при инициализации. В случае обнаружения ошибки программа
останавливается, так как ошибки в OvrInit являются фатальны-
ми.  (Если они игнорируются, то при первом обращении к овер-
лейной программе во время выполнения произойдет ошибка.)
     Если предположить, что инициализация проходит  успешно,
далее  для  загрузки  оверлейного файла в расширенную память
(если  это  возможно)  выполняется  обращение  к   процедуре
OvrInitEMS. В случае ошибки на экран выводится диагностичес-
кое сообщение, однако программа не  останавливается.  Вместо
этого она просто продолжает считывать оверлеи с диска.
     Наконец, для задания значения размера оверлейного буфе-
ра,  определенного с помощью анализа или эксперимента с кон-
кретной   приклажной   программой,   вызывается    процедура
OvrSetBuf.  Ошибки,  которые могут возникнуть при выполнении
данной процедуры, игнорируются, хотя OvrResult может возвра-
щать  код  возврата  по ошибке -3 (OvrNoMemory). Если памяти
недостаточно, подсистема управления оверлеями  будет  просто
продолжать использовать буфер минимального размера, выделен-
ный при запуске программы.

         Разделы инициализации в оверлейных модулях

     Аналогично статическим модулям оверлейные модули  могут
содержать  раздел инициализации. Хотя оверлейный код инициа-
лизации не отличается от обычного кода  инициализации,  под-
система  управления оверлеями должна быть первоначально ини-
циализирована таким образом, чтобы она могла загружать и вы-
полнять оверлейные модули.
     Взяв в качестве примера ранее  рассмотренную  программу
Editor,  предположим,  что  модули EdInOut и EdMain содержат
код  инициализации.  При  этом  требуется,  чтобы  процедура
OvrInit вызывалась перед кодом инициализации модуля EdInOut,
и единственный способ осуществить это  состоит  во  введении
дополнительного  неоверлейного модуля, который следует перед
EdInOut и вызывает в своем разделе  инициализации  процедуру
OvrInit.

  unit EdInit;
  interface
  implementation
  uses Overlay;
  const
    OvrMaxSize = 80000;
  begin
    OvrInit('EDITOR.OVR');
    OvrInitEMS;
    OvrSetBuf(OvrMaxSize);
  end.

     В предложении  использования  программы  модуль  EdInit
должен следовать перед всеми оверлейными модулями:

  program Editor;
  {$F}
  uses
   Overlay,Crt,Dos,EdInit,EdInOut,EdFormat,EdPrint,EdMain;
  {$O EdInOut }
  {$O EdFormat }
  {$O EdPrint }
  {$O EdFind }
  {$O EdMain }

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

      Что не должно использоваться в качестве оверлеев

     Отдельные модули не могут использоваться, как  оверлей-
ные. В частности, не пытайтесь использовать в качестве овер-
лейных модулей следующие:

     1.  Модули, скомпилированные с директивой  {$O-}.  Если
         вы  пытаетесь  использовать  как оверлейный модуль,
         который не был скомпилирован с директивой {$O+}, то
         компилятор  выдает сообщение об ошибке. Такими нео-
         верлейными модулями являются модули  System,  Over-
         lay, Turbo3 и Graph3.
     2.  Модули, которые содержат драйверы прерываний. Из-за
         того,  что сама операционная система ДОС имеет нео-
         верлейную структуру, модули, реализующие  процедуры
         прерываний (interrupt), не должны быть оверлейными.
         В качестве примера  такого  модуля  можно  привести
         стандартный  модуль  Crt, реализующий драйвер обра-
         ботки прерывания, возникающего при  нажатии  клавиш
         Ctrl-Break.

     Подсистемой управления оверлеями Турбо-Паскаля  полнос-
тью поддерживается вызов оверлейных процедур с помощью  ука-
зателей процедур. В качестве примеров использования указате-
лей процедур можно привести процедуры завершения и драйверы
устройств для текстовых файлов.
     Аналогично, полностью поддерживается передача  оверлей-
ных  процедур  и  функций в качестве параметров процедурного
типа и присваивание оверлейных процедур и функций переменным
процедурного типа.

                      Отладка оверлеев

     Большинство отладчиков  обладают  весьма  ограниченными
возможностями отладки оверлеев, если они вообще обладают та-
кими средствами.  Этого нельзя  сказать  о  Турбо-Паскале  и
Турбо-отладчике.  Интергированный отладчик полностью поддер-
живает при работе с оверлеями пошаговый режим и точки  оста-
нова,  используя  при  этом  метод, полностью прозрачный для
пользователя. С помощью оверлеев вы легко можете конструиро-
вать и отлаживать прикладные пакеты большого объема. Все это
можно делать как с помощью Турбо-отладчика, так и  из  инте-
рактивной интерактивной среды компилятора.

                Внешние программы в оверлеях

     Аналогично обычным процедурам и функциям  Турбо-Паскаля
при  искользовании  внешних программ на языке ассемблера для
обеспечения корректной работы подсистемы управления оверлея-
ми должны соблюдаться определенные правила программирования.
     Если в программе на языке ассемблера осуществляется об-
ращение к любой оверлейной процедуре или функции, то в прог-
рамме ассемблера должен использоваться дальний тип вызова  и
с помощью регистра ВР должны быть установлены границы стека.
Например, предположим,  что  OtherProc  является  оверлейной
процедурой   в   другом   модуле  и  ее  вызывает  программа
ExternProc на языке ассемблера. Тогда  программа  ExternProc
должна иметь дальний тип вызова и устанавливать границы сте-
ка следующим образом:

  ExternProc      PROC       FAR
        PUSH      bp         ; сохранить регистр ВР
        mov       bp,sp      ; установить границы стека
        SUB       sp,LocalSize ; выделить локальные
                             ;   переменные
        ...
        CALL      OtherProc  ; вызвать другой оверлейный
                             ; модуль
        ...
        mov       sp,bp      ; отменить локальные переменные
        pop       bp         ; восстановить регистр ВР
        RET       ParamSize  ; возврат управления
  ExternProc      ENDP

где LocalSize представляет собой размер  локальных  перемен-
ных,   а   ParamSize  -  размер  параметров.  Если  значение
LocalSize равно 0, то две строки,  в  которых  выделяются  и
уничтожаются локальные переменные, можно опустить.
     Если в программе ExternProc имеются косвенные ссылки на
оверлейные  процедуры  и функции, то эти требования остаются
теми же. Например, если процедура OtherProc  вызывает  овер-
лейные  процедуры  или функции, но сама не является оверлей-
ной, то программа ExternProc должна,  тем  не  менее,  иметь
дальний тип вызова и устанавливать границы стека.
     В том случае, если в программе на языке ассемблера  от-
сутствуют прямые или косвенные ссылки на оверлейные процеду-
ры или функции, то никаких специальных требований соблюдать-
ся  не должно: программа на языке ассемблера может использо-
вать ближний тип вызова и не устанавливать границ стека.
     Оверлейные программы на языке ассемблера не должны соз-
давать переменных в сегменте кода, поскольку при уничтожении
оверлея любые изменения, внесенные в оверлейный сегмент  ко-
да,  теряются. Аналогично, не следует считать, что указатели
на размещенные в оверлейном сегменте кода объекты  останутся
действительными  при  вызове других оверлеев, поскольку под-
система управления оверлеями  может  свободно  перемещать  и
уничтожать оверлейные сегменты кода.


                          ГЛАВА 25

              Использование сопроцессора 8087

     В Турбо-Паскале вы можете работать с двумя типами чисел
- целыми  (короткими целыми, целыми, длинными целыми, целыми
длиной в  байт, целыми длиной в слово) и  вещественными (ве-
щественными, вещественными одинарной точности, вещественными
двойной точности, повышенной точности, сложными). Веществен-
ные числа называют  также  числами с  плавающей запятой. Для
облегчения работы с целыми числами создан процессор 8086, но
для работы с вещественными числами на этом процессоре затра-
чивается гораздо больше времени и усилий. Для семейства про-
цессоров 8086 предназначено соответствущее семейство вспомо-
гательный  специализированных процессоров для математических
вычислений (сопроцессоров) 8087.
     Процессор 8087 - это специальный процессор для обработ-
ки чисел, который может входить в  состав вашего  компьютера
РС. С помощью него операции с плавающей запятой  выполняются
очень быстро. Поэтому если вы собираетесь использовать боль-
шой объем вычислений с плавающей запятой,  то вам, вероятно,
понадобится сопроцессор.
     Турбо-Паскаль построен таким образом,  что он обеспечи-
вает оптимальное выполнение операций с плавающей запятой не-
зависимо от наличия процессора 8087.

     1.  Для программ, работающих на  компьютере РС, незави-
         симо от  того,  оснащен  он  сопроцессором 8087 или
         нет, в  Турбо-Паскале  предусмотрено  использование
         вещественных  чисел  и  соответствующая  библиотека
         программ, которые предназначены для выполнения опе-
         раций с плавающей запятой. Числа вещественного типа
         занимают 6  байтов памяти.  При этом обеспечивается
         представление  чисел  в диапазоне от 2,9х10**-39 до
         1,7х10**38 с 11-12  значащими  цифрами. Программы в
         библиотеке программ для работы с плавающей запятой
         оптимизированы по скорости и по размеру и использу-
         ют самые новейшие средства процессора 8087.
     2.  Если вы пишете программы, использующиеся  только на
         компьютерах, оснащенных  сопроцессором  8087, то вы
         можете указать Турбо-Паскалю на необходимость полу-
         чения  выполняемого  кода,  в  котором используется
         плата процессора 8087. Это даст вам возможность ис-
         пользования четырех дополнительных типов веществен-
         ных чисел (одинарной и двойной точности, повышенной
         точности,  сложного  типа)  и  расширенный диапазон
         представления  чисел  с  плавающей  запятой  -   от
         1,9х10***-4951 до 1,1х10**4943  с  19-20  значащими
         цифрами.

      Примечание: При компиляции с режимом числовой обработ-
      ки, то есть с директивой {$N+},  возвращаемые програм-
      мыми  модуля  Systем  (Sqrt, Рi, Sin и т.д.)  значения
      представляют собой не действительные числа, а  числа с
      повышенной точностью.

       {$N+}

       begin
         Writeln(Pi); { 3.14159265358979E+0000 }
       end.

       {$N-}

       begin
         Writeln(Pi); { 3.1415926536E+00 }
       end.

           Вы можете выбирать одну из двух возможных моделей
      генерации  кода для операций с плавающей запятой.  Это
      делается с помощью директив компилятора $N  или с  по-
      мощью записи О/С/Numeric  из  меню  режимов обработки.
      Директива {$N-}  указывает,  что  операции с плавающей
      запятой  будут выполняться   с   помощью   программных
      средств, а {$N+} - на выполнение этих  операций с  по-
      мощью аппаратных средств.

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

                Типы данных процессора 8087

     В дополнение к вещественному типу для программ, исполь-
зующих средства процессора  8087,  предусматривается  четыре
новых действительных типа:

     1.  Тип с одинарной точностью, представляющий собой на-
         именьший формат, который вы можете использовать для
         чисел  с плавающей запятой. Он занимает 4 байта па-
         мяти  обеспечивает  диапазон представления чисел от
         1,5х10**-45 до 3,4х10**48 с 7-8 значащими цифрами.
     2.  Тип с двойной точностью, занимающий 8 байтов памяти
         и обеспечивающий представление чисел в диапазоне от
         5,0х10**-334 до 1,7х10**308 с 15-16 значащими  циф-
         рами.
     3.  Тип с повышенной точностью представляет собой  наи-
         больший формат представления чисел с плавающей  за-
         пятой, обеспечиваемый процессором 8087. Он занимает
         10 байтов памяти и обеспечивает диапазон  представ-
         ления чисел  от  1,9х10**-4952  до  1,1х10**4932  с
         19-20 значащими цифрами. Любые арифметические  опе-
         рации, в которых участвуют  числа вещественного ти-
         па,  выполняются с точностью и диапазоном представ-
         ления,  соответствующими  типу  с  повышенной  точ-
         ностью.
     4.  Числа сложного типа используются для предварительно
         объединенных значений в 8 байтах памяти,  обеспечи-
         вая при этом диапазон представления от -2**63+1  до
         2**63-1,   что    составляет    приблизительно   от
         -9,2х10**18 до 9,2х10**18. Сложный тип можно  срав-
         нить с длинным целым типом  (двойная точность),  но
         он считается вещественным типом, поскольку при опе-
         рациях с числами этого типа используется  сопроцес-
         сор 8087. Сложный тип хорошо подходит для представ-
         ления значений денежных единиц, представляющих  со-
         бой сотни и тысячи, которые используются в приклад-
         ных коммерческих программах.

     Независимо от того, используете вы сопроцессор 8087 или
нет,  6-битовый  вещественный тип является допустимым. Таким
образом,  при переходе к использованию сопроцессора 8087 вам
не потребуется изменять исходный текст программы и вы можете
использовать  файлы  данных,  созданные программами, которые
работают с программно обеспечиваемыми операциями с плавающей
запятой.
     Отметим, однако, что аппаратные вычисления с переменны-
ми вещественного типа выполняются несколько медленнее, чем с
переменными другого типа. Это связано с тем, что сопроцессор
8087 не может непосредственно обрабатывать вещественный фор-
мат. Вместо этого, перед  выполнением операций, для преобра-
зования вещественных значений в числа с повышенной точностью
требуются обращения к библиотечным программам. Если вы заин-
тересованы в максимальной скорости выполнения и не  собирае-
тесь использовать свою программу на системах без сопроцессо-
ра 8087, то возможно вы захотите использовать  одинарный ве-
щественный, вещественный с двойной точностью, вещественный с
повыщенной точностью и сложный типы явным образом.

       Арифметические операции с повышенной точностью

     При использовании сопроцессора 8087  тип  с  повышенной
точностью является основой всех  операций с  плавающей запя-
той. В Турбо-Паскале тип с повышенной точностью используется
для представления  всех  нецелых  числовых констант, а также
при  вычислении  всех  выражений нецелого типа.  Например, в
следующих операциях присваивания все правые части  выражений
будут вычисляться, как выражения с  повышенной  точностью, а
затем их тип будет преобразован к типу соответствующей левой
части:

 var
   X, AA, B, C : real;
 begin
   X := (B + Sqrt(B*B - A*C))/A;
 end;

     Турбо-Паскаль выполняет вычисления с точностью и диапа-
зоном представления чисел,  соответствующими типу с повышен-
ной точностью, без  дополнительных усилий программиста.  До-
полнительная точность приводит к меньшим ошибкам округления,
а дополнительный диапазон означает, что ситуации  переполне-
ния и потери значимости будут встречаться в программах реже.
     Вы можете обойтись и без дополнительных  автоматических
возможностей вычислений в повышенной точностью  Турбо-Паска-
ля. Например, вы можете описать  переменные,  использующиеся
для  промежуточных  вычислений,  как переменные с повышенной
точностью.  В следующем примере вычисляется сумма произведе-
ний:

  var
    Sm : single;
    X,Y array[1..100] of single;
    I : integer;
    T : extended;   { для промежуточных результатов }
  begin
    T := 0.0;
    for I := 1 to 100 do T := T + X[I] * Y[I]
    Sum := T;
  end;

     Если бы переменная Т  была  описана,  как  переменная с
одинарной точностью, то при каждом цикле операции присваива-
ния для переменной Т были бы выполнены с ошибкой  округления
и ограничениями,  соответствующими  одинарной точности.  Но,
поскольку переменная Т является переменной с повышенной точ-
ностью,  то все ошибки округления (кроме операции, при кото-
рой значение переменной Т присваивается переменной Suм) име-
ют ограничения, соответствующие повышенной точности. Меньшие
ошибки округления означают более точный результат.
     Для значений формальных параметров и результата функции
вы  также можете задать повышенную точность. Это поможет из-
бежать ненужных преобразований типов чисел, приводящих к по-
тере точности. Например:

  function Area(Radius: extended): extended;
  begin
    Area := Pi * Radius * Radius;
  end;

                Сравнение вещественных чисел

     Поскольку значения  вещественного типа являются прибли-
зительными, результат  сравнения значений различного вещест-
венного типа не всегда можно предсказать. Например, если Х -
переменная  вещественного типа с одинарной точностью, а  Y -
переменная вещественного типа с двойной  точностью,  то  ре-
зультатом выполнения  следующих  операторов  будет  значение

False:

 X := 1/3;
 Y := 1/3;
 Writeln(X = Y);

     Причина этого состоит в том, что Х имеет точность толь-
ко до 7-8 цифр,  а Y -  точность  до 15-16 цифр, и когда оба
значения  преобразуются к  типу с  повышенной  точностью, то
после  первых 7-8 цифр остальные цифры будут различаться.
Аналогично, результатом выполнения операторов:

 X := 1/3;
 Writeln(X = 1/3);

будет  значение False, результат 1/3 в операторе Writeln вы-
числяется с точностью до 20 значащих цифр.

             Стек вычислений сопроцессора 8087

     У сопроцессора 8087 имеется внутренний стек вычислений,
который может быть глубиной до восьми уровней. Доступ к зна-
чению, находящемуся в стеке сопроцессора 8087 осуществляется
намного быстрее,  чем  доступ к переменной в памяти, поэтому
для достижения  максимально  возможной  производительности в
Турбо-Паскале внутренний стек сопроцессора 8087 используется
для хранения временных результатов и для передачи параметров
процедурам и функциям.
     При  использовании стека сопроцессора 8087 для передачи
параметров подразумевается что  процедура или функция не мо-
жет иметь больше  восьми  значений  параметров с типами, ис-
пользующимися в сопроцессоре 8087 (одинарной точности, двой-
ной  точности,  повышенной точности или сложного типа).  При
попытке описать большее число параметров компилятор не выда-
ет сообщения об ошибке, но во время выполнения программа при
вызове подпрограммы завершит свою работу с ошибкой. На число
параметров вещественного типа, которые вы  можете  использо-
вать, ограничений не накладывается.  Вы можете также описать
любое число параметров var.

      Примечание: В выполняемом  коде  при входе в процедуры
      или функции  любые параметры с типами, использующимися
      в сопроцессоре 8087, сохраняются во временных отведен-
      ных им ячейках.  Параметры могут занимать пространство
      стека  сопроцессора 8087  только во время вызова, а не
      во время выполнения процедуры или функции.

     Теоретически слишком  сложные  выражения  вещественного
типа могут вызвать переполнение стека сопроцессора 8087. Од-
нако этого не может случиться, поскольку для  этого потребо-
валось бы, чтобы в выражении получалось более  восьми проме-
жуточных результатов.
     Более весомая  опасность  таится  во  вложенных вызовах
функций.  Если такие  конструкции составлены некорректно, то
они, вполне  вероятно,  могут  привести к переполнению стека
сопроцессора 8087.

     Предположим, что функция Теst является функцией с повы-
шенной с точностью и у  нее  имеется три  параметра-значения
с повышенной точностью. Тогда выражение:

 X := Test(A,B,Test(C,D,Test(E,F,Test(X,Y,Z))));

вызовет переполнение стека сопроцессора 8087. Это произойдет
потому, что при самом внутреннем обращении к  функции Теst в
стек сопроцессора 8087 уже помещено 6  значений  с плавающей
запятой и осталось место только для двух.  Правильной конст-
рукцией в данном случае будет:

 X := Test(X,Y,Z);
 X := Test(E,F,X);
 X := Test(C,D,X);
 X := Test(A,B,X);

     Аналогичная  ситуация может возникнуть в рекурсивно вы-
полняющихся функциях. Рассмотрим, например, следующую проце-
дуру, в которой с помощью рекурсии вычисляются  числа  Фибо-
наччи:

 function Fib(N: integer): extended;
 begin
   if N = 0 then Fib := 0.0 else
   if N = 1 then Fib := 1.0 else
   Fib := Fib(N-1) + Fib(N-2);
 end;

     Обращение к  данной версии процедуры Fib приведет к пе-
реполнению стека сопроцессора 8087, так как значений N боль-
ше, чем 8. Причина заключается в том, что последний оператор
присваивания требует временного сохранения результата выпол-
нения процедуры  Fib(N-1) в стеке сопроцессора 8087.  Каждое
рекурсивное обращение выделяется одна ячейка стека и  на де-
вятом обращении произойдет  переполнение  стека.  Корректной
конструкцией в этом случае будет:

 function Fib(N : integer) : extended;
 var
   F1,F2 : extended;
 begin
   if N = 0 then Fib := 0.0 else
   if N = 1 then Fib := 1.0 else
 begin
   F1 := Fib(N-1); F2 := Fib(N-2);
   Fib := F1 + F2;
 end;
 end;

     Временные результаты теперь сохраняются  в  переменных,
для которых отводится стек процессора 8086. (Стек процессора
8086 конечно тоже может переполниться, но это обычно требует
гораздо большего числа рекурсивных вызовов).

              Запись действительных чисел при
              использовании сопроцессора 8087

     Если была указана директива  {$N+}, то стандартные про-
цедуры Write и Writeln для того,  чтобы обеспечить представ-
ление в расширенном диапазоне, выводят в строке с десятичны-
ми числами с плавающей  запятой  четыре цифры для экспоненты
вместо двух. Аналогично, стандартная процедура Str при выбо-
ре формата с плавающей запятой возвращает значение экспонен-
ты, состоящее из четырех цифр.

      Модули, в которых используется сопроцессор 8087

     Модули, в которых  используется сопроцессор 8087, могут
вызываться другими модулями  или  программами  только в  том
случае, если эти модули или программы  были скомпилированы с
директивой {$N+}.То, что модуль использует сопроцессор 8087,
определяется тем, содержатся ли в нем инструкции сопроцессо-
ра 8087, а не директивой $N во время их компиляции. Это поз-
воляет компилятору быть  более  "снисходительным",  когда вы
случайно компилируете модуль (в котором используется  сопро-
цессор 8087), не указав директиву {$N+}.

              Распознавание сопроцессора 8087

     Исполняющая библиотека Турбо-Паскаля, встроенная в вашу
программу  (скомпилированную  с директивой {$N+}) включает в
себя код инициализации, который автоматически распознает на-
личие в системе микросхемы сопроцессора 8087. Если сопроцес-
сор 8087 имеется, то программа будет его  автоматически  ис-
пользовать.  В случае  же его отсутствия программа будет ис-
пользовать эмулирующую библиотеку исполняющей системы.  Если
программа  компилировалась с директивой {$E-} и по время на-
чала ее работы сопроцессор не обнаруживается,  то  программа
завершает  работу  с сообщением Numeric coprocessor required
(требуется сопроцессор арифметических вычислений).
     Есть несколько случаев, когда вы возможно захотите  из-
менить  такую  принятую  по умолчанию логику автообнаружения
сопроцессора. Например, в вашей системе может присутствовать
сопроцессор  8087, но вы захотите проверить, как будет рабо-
тать программа, предназначенная для функционирования на сис-
темах  без  сопроцессора.  Или же потребуется запустить вашу
программу на системе, совместимой с компьютером  РС,  но  на
этой  системе при работе алгоритма автообнаружения будет вы-
водиться некорректная информация (например, будет сообщаться
о наличие сопроцессора, когда на самом деле его нет, или на-
оборот).
     В Турбо-Паскале предусмотрена возможность отмены приня-
той  по  умолчанию логики автоматического распознавания. Эта
возможность задается переменной операционной среды 87.
     Вы можете установить переменную операционной среды 87 в
ответ на подсказку ДОС с помощью команды SET, например, сле-
дующим образом:

     SET 87=Y

или

     SET 87=N

     Установка для переменной операционной среды 87 значения
N  (нет)  указывает коду инициализации, что вы не хотите ис-
пользовать сопроцессор 8087, хотя он может и присустствовать
в  системе. И наоборот: установка для переменной 87 значения
Y (да) означает, что сопроцессор имеется и вы хотите,  чтобы
ваша  программа его использовала. Однако при этом нужно пом-
нить о том, что установка для переменной 87 значения  Y  при
отсутствии  в системе сопроцессора 8087 приведет к тому, что
ваша программа аварийно завершит работу или зависнет.
     Если переменная операционной среды 87 определена, а  вы
хотите,  чтобы  она  стала неопределенной, то можно ввести в
ответ на подсказку ДОС:

     SET 87=

и нажать клавишу Enter.
     Если в операционной среде ДОС присутствует запись 87=Y,
или  если  код инициализации успешно распознает сопроцессор,
то далее код инициализации выполняет  последующие  проверки,
чтобы  определить,  какой  это  сопроцессор (8087, 80287 или
80387). Это необходимо для  того,  чтобы  Турбо-Паскаль  мог
корректно  работать  с отдельными несовместимостями, которые
имеются между сопроцессорами различных типов.
     Резальтат автоматического распознавания наличия  сопро-
цессора  и его модели сохраняется в переменной Test8087 (ко-
торая описывается в модуле System). Для нее определены  сле-
дующие значения:

     0 - сопроцессор не обнаружен;
     1 - обнаружен сопроцессор 8087;
     2 - обнаружен сопроцессор 80287;
     3 - обнаружен сопроцессор 80387.

     Чтобы определить характеристике системы, на которой ра-
ботает  раша  программа, вы можете в программе проверить со-
держимое переменной Test8087. В  частности,  эту  переменную
можно  проанализировать для того, чтобы определить, эмулиру-
ются инструкции работы с плавающей запятой, или они действи-
тельно выполняются.

                  Использование эмуляции
           сопроцессора 8087 на языке ассемблера

     Когда компоновка объектных файлов выполняется с  дирек-
тивой {$L имя_файла}, необходимо обеспечить, чтобы эти файлы
компилировалить с разрешением  эмуляции  сопроцессора  8087.
Например,  если  вы используете инструкции сопроцессора 8087
во внешних процедурах на языке ассемблера,  необходимо  убе-
диться,  что  при  ассемблировании  файлов .ASM в файлы .OBJ
эмуляция разрешена. В противном случае инструкции  сопроцес-
сора 8087 не могут эмулироваться на машинах без сопроцессора
8087. Для разрешения эмуляции используйте переключатель  ко-
мандной строки Турбо-Ассемблера /Е.



