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



 

Часть 1



B-Tree Filer 5.0
----------------

Руководство пользователя
------------------------

Авторские права (с) 1989, TurboPower Software.
Все права сохраняются.

Первое издание март 1989.


P.O.Box 66747
Scotts Valley, CA 95066
Служба технической поддержки: 408-438-8608
Compuserve: 724572131
с 9 утра до 5 дня по среднетихоокеанскому времени,
с понедельника до пятницы.


Упоминаемые торговые марки
--------------------------

     TurboPower Software   и  отдельный  логотип  TurboPower  это
торговые марки фирмы TurboPower Software.

     Turbo Professional  это  зарегистрированная  торговая  марка
фирмы Sunny  Hill  Software,  используемая по лицензии TurboPower
Software.

     B-Tree Filer это торговая марка фирмы TurboPower Software.

     BTREE-ISAM это торговая марка фирмы  Enz  EDV-Beratung  Gmbh
(Западная Германия).

     Turbo Pascal,  Turbo  Assembler,  Turbo  Database  Toolbox и
Turbo Editor Toolbox  это  торговые  марки  и  зарегистрированные
торговые марки фирмы Borland International.

     MS-DOS, MS-NET  и  Macro  Assembler это торговые марки фирмы
Microsoft Corporation.

     IBM PC,  XT,  AT,  PS/2,  IBM PC LAN и NetBIOS это  торговые
марки или зарегистрированные торговые  марки  фирмы International
Buisiness Machines Corporation.

     Novell, NetWare,  SFT,  TTS и International Packet  Exchange
(IPX) это  торговые  марки  или зарегистрированные торговые марки
фирмы Novell Inc.

     Arcnet это зарегистрированная торговая марка фирмы Datapoint
Corporation.

     3Com это торговая марка фирмы 3Com Corporation.

     Network-OS это торговая марки фирмы CBIS, Inc.

     PC-NET это торговая марка фирмы Orchid Technology, Inc.

     PC-MOS/386 это торговая марка фирмы Software Link, Inc.

     Ethernet, Internetwork  Packet  Protocol  и Sequenced Packet
Protocol это торговые марки фирмы Xerox Corporation.

     Btrieve это зарегистрированная торговая марка SoftCraft, Inc.

     WordStar это  зарегистрированная  торговая  марка   MicroPro
International Corporation.



Содержание
----------
     
1. Введение  ...............................................
     A. Требования к системе ...............................
     В. Поставляемые файлы .................................
     С. Как приступить к работе.............................
     D. Соглашение о приобретении...........................

2. Принципы работы .........................................
     A. Данные и ключи......................................
     В. Организация B-дерева................................
     С. Управление ключами..................................

3. Использование B-Tree Filer...............................
     A. Файловые блоки......................................
     В. Организация программы...............................
     С. Примеры программирования............................
     D. Управление файловым блоком..........................

4. Идентификаторы B-Tree Filer..............................
     A. Константы...........................................
     В. Типы................................................
     С. Переменные..........................................
     D. Процедуры и функции.................................

5. Введение в B-Tree Net....................................
     A. Требования к системе................................
     В. Задание сети........................................
     С. Номера рабочих станций..............................
     D. Сетевой интерфейс...................................

6. Использование B-Tree Net.................................
     A. Организация программы...............................
     В. Степени запирания...................................
     С. Преобразование однопользовательских программ........
     D. Примеры программирования............................

7. Идентификаторы B-Tree Net................................

8. Утилиты B-Tree Filer.....................................
     A. Записи переменной длины.............................
     В. Экранный просмотр...................................
     С. Перепостроение поврежденного файлового блока........
     D. Реорганизация файлового блока.......................
     E. Сортировка..........................................
     F. Числовые ключи......................................

9. Сетевые утилиты..........................................
     А. Novell NetWare......................................
     B. NetBios.............................................
     C. SHARE...............................................
     D. Сетевые демонстрационные программы..................

10. Приложения..............................................
     A. Коды ошибок.........................................
     В. Краткие описания процедур и функций.................
     С. Преобразование из Borland Database Toolbox..........
     D. Преобразование из Softcraft Btrieve.................
     E. Использование B-Tree Filer с Turbo Professional.....
     F. Исходный код B-Tree Filer...........................
     G. Оверлеи и B-Tree Filer..............................


                                                            

1. Введение
-----------

     Хранение и  управление  данными  представляют  собой одну из
центральных проблем в  электронной  обработке  данных.  Не  будет
преувеличением, если   сказать,  что  многие  программисты  имеют
основной доход именно от работы с базами данных.  До сих  пор  не
существовало достаточного   числа  программных  средств,  которые
позволяли бы быстро и эффективно писать программы в Turbo Pascal,
работающие с базами данных. И тут на сцену выходит B-Tree Filer.

     B-Tree Filer  предлагает  вам  высококачественную библиотеку
для простого и эффективного управления базами данных. Он включает
в себя многие средства, делающие его вне конкуренции:

     - Интегральная поддержка многопользовательских,  сетевых баз
данных.

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

     - Он  написан на Turbo Pascal,  причем обеспечивается полный
исходный код продукта.

     - Поддержка записей фиксированной и переменной длины.

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

     - Отдельные  файлы  данных и файлы индексов для максимизации
целостности данных.

     - Во время  выполнения  не  требуется  иметь  резидентных  в
оперативной памяти программ (TSR-программ).

     - Мощные  модули  с  утилитами для полноэкранного просмотра,
реорганизации и сортировки файлов данных.

     - Поддержка сетей Novell, MS-NET, а также всех прочих сетей,
совместимых по NetBIOS.

     - Модули доступа к сети,  обеспечивающие управление файлами,
управление принтерами и передачу сообщений в сети.

     B-Tree Filer  основан   на   улучшенной   версии   алгоритма
сбалансированного B-дерева,   который   зарекомендовал  себя  как
лучший метод доступа к данным в  больших  базах  данных.  Емкость
базы данных,  поддерживаемая B-Tree Filer,  настолько велика, что
вам практически не нужно об этом беспокоиться:

     - Максимальное число записей данных: 2,147,483,647

     - Максимальное число ключевых элементов: 2,147,483,647

     - Длина ключа: от 1 до 255, по умолчанию 30 символов максимум

     - Максимальное число индексов на одну базу данных: 750,
по умолчанию 100

     - Диапазон длины записи данных:  от 21 до 2,147,483,647 (DOS
и архитектура 8086 ограничивают эту величину значением 65,535)

     - Максимальное число рабочих стпнций:  32,767 (по  умолчанию
50)

     Как вы уже, наверное, знаете, B-Tree Filer существует в двух
версиях. Однопользовательская версия позволяет  вам  писать  базы
данных, работающие     на     отдельных     PC,     тогда     как
многопользовательская версия  включает  в   себя   средства   для
запирания записей и доступа к сети.  Для различения этих версий в
данном руководстве мы используем фразу "B-Tree Net",  когда  речь
идет о  средствах,  специфичных  для  сетевой  версии,  и "B-Tree
Filer", когда данное  средство  работает  независимо  от  версии.
Каждый раздел  настоящего  руководства  поясняет,  какие средства
обеспечивает каждая из версий.  Отметим, однако, что B-Tree Filer
разработан таким  образом,  что  вы  можете  писать с его помощью
простые однопользовательские прикладные программы,  которые затем
легко можно модифцировать для работы в сети.

     B-Tree Filer  является версией TurboPower Software солидного
и респектабельного продукта  из  Западной  Германии:  BTREE-ISAM.
Этот продукт появился в Европе два года назад и имеет заслуженную
репутацию благодаря высокому быстродействию и  надежности.  Кроме
перевод на   английский,   фирма   TurboPower  Software  улучшила
исходный пакет,  включив  в  него   новые   утилиты   виртуальной
сортировки и доступа к сети. Мы обеспечиваем тот же самый высокий
уровень обслуживания и поддержки  данного  продукта,  к  которому
наши пользователи привыкли по предыдущим продуктам нашей фирмы.

А. Требования к системе
-----------------------

     Для того,  чтобы  использовать B-Tree Filer,  вам необходимо
иметь следующее:

     1. IBM PC,  XT,  AT (или близко  совместимую  машину),  либо
PS/2, работающую  в операционной системе DOS 2.0 или старше.  При
использовании B-Tree Net сама сеть может потребовать  наличия DOS
3.1 или старше.

     2. Turbo Pascal версии 4.0 или 5.0.

     3. Два дисковода для гибких дисков.  Безусловно,  желательно
иметь и жесткий диск.

     4. Используемый размер оперативной памяти сильно  зависит от
длины ключа и выделенных буферов.  Обычно B-Tree Filer использует
50К или 100К оперативной памяти.

Необязательные средства:

     5. Borland  Turbo  Assembler  (TASM)  или  Microsoft   Macro
Assembler (MASM).     Требуется     тоько    при    необходимости
модифицировать исходный код  на  языке  ассемблера  в  конкретных
участках B-Tree Filer.

     6. Сетевое  аппаратное  обеспечение  и операционная система,
совместимые с B-Tree Filer.  Сюда входят Novell, 3Com, PC-Net, PC
LAN, MS-NET,   Network-OS,   PC-MOS/386  и  другие.  Любая  сеть,
поддерживающая вызовы  DOS  3.x  для  запирания  записей,   может
работать совместно с B-Tree Filer.

     Существуют также и определенные требования к программисту. B
-Tree Filer  представляет  собой  полную   реализацию   алгоритма
индексации Байера-Баума (обычно известного как В-дерево). Хотя B-
Tree Filer и содержит реализацию данного  алгоритма,  программист
должен быть  знаком  с  основами произвольного доступа к файлам и
использованием модулей,  к которым  обращается  компилятор  Turbo
Pascal. Для   полного   понимания   многих   из   кодов   ошибки,
генерируемых B-Tree  Filer,  рекомендуется  также  знакомство   с
файловой системой MS-DOS.

B. Поставляемые файлы
---------------------

     B-Tree Filer  поставляется  на  одной   дискете   в   случае
однопользовательской версии,  либо  на  двух  дискетах  в  случае
версии, поддерживающей работу в  сети.  Прежде  чем  пользоваться
этими дискетами,  рекомендуется сделать их запасные копии.  Файлы
на дискетах не защищены от копирования.

     На дискете(дискетах) вы найдете следующин файлы:

     Диск FILER (одно- и многопользовательские версии):
     --------------------------------------------------

     READ.ME

     Если вы обнаружите на дискете файл с этим  именем,  прочтите
его, прежде  чем  продолжить  работу.  Этот  файл  содержит самые
последние дополнения к типографски изданной документации.

     NETDEMO.EXE

     ADDRESS.DAT

     ADDRESS.IX

     Обеспечивают полную демонстрацию свойств B-Tree Filer. Более
подробную информацию  о  том,  как использовать данную программу,
см. в разделе  1.С,  "Как  приступить  к  работе".  Отметим,  что
NETDEMO компилируется  для  работы в однопользовательскй системе.
Для активации    многопользовательских     средств     необходимо
разархивировать и   перекомпилировать   исходный   код,   который
находится в   FILER.ARC.   NETDEMO    использует    преимущества,
предоставляемые библиотекой  Turbo  Professional фирмы TurboPower
для ввода данных и редактирования  поля  памяти  (memo).  Вторая,
более простая версия,  называемая SIMPDEMO, также включена только
в исходной форме;  для компиляции этой версии Turbo  Professional
не требуется.

     BIGSORT.EXE

     Пример использования  модуля виртуальной сортировки,  MSORT.
Сортирует текстовые файлы любых размеров.  Для  получения  списка
опций сортировки просто наберите BIGSORT.

     GETFILER.BAT

     Командный файл для извлечения из архива FILER.ARC конкретных
модулей B-Tree  Filer.  Инструкции   по   использованию   данного
команднного файла см. в Приложении F.

     ARCX.COM

     Малая версия  утилиты ARC,  выполняющая только разархивацию.
Данная утилита  извлекает  несжатые  файлы  из   FILER.ARC.   Для
получения краткой  справки  по  работе  программы наберите ARCX и
затем . Для разархивации исходных текстов B-Tree Filer без
использования GETFILER.BAT  просто скопируйте FILER.ARC в рабочую
директорию, где имеется еще как минимум 700К свободной  памяти  и
введите ARCX FILER.ARC, находясь в этой директории. По завершении
разархивации FILER.ARC можно удалить из этой директории.

     FILER.ARC

     Данный архив    содержит    полный    исходный    код    для
однопользовательской версии  B-Tree Filer,  включая модули FILER,
BROWSER, VREC, REBUILD, REORG, VREORG, VREBUILD, MSORT и NUMKEYS,
а также  исходные  коды  NETDEMO  и SIMPDEMO.  Этот архив следует
раскрыть для  использования  указанных  модулей  при   компиляции
B-Tree Filer  как  одно-,  так и многопользовательской версии.  В
архив включен также файл FILER.MAK.


     Диск NET (только для многопользовательской версии)
     --------------------------------------------------

     NETINFO.EXE

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

     NSEND.EXE

     NRECEIVE.EXE

     Демонстрация техники пересылки сообщений в  сети; использует
правила NetWare  или NetBios,  в зависимости от того,  что именно
доступно. Более подробную информацию см.  в разделе 9.D, "Сетевые
демонстрационные программы".

     GETNET.BAT

     Командный файл   для   извлечения   из  архива  NETFILER.ARC
конкретных модулей B-Tree Net.  Использование данного  командного
файла описано в Приложении F.

     ARCX.COM

     Вторая копия  утилиты  для  разархивации.  Для  разархивации
многопользовательского исходного    кода    без     использования
GETNET.BAT просто скопируйте NETFILER.ARC в рабочую область с как
минимум 500К свободной дисковой памяти и введите ARCX NETFILER.

     NETFILER.ARC

     Этот архив хранит полный исходный  код многопользовательской
версии B-Tree  Filer,  включая  сетевую поддержку модулями FILER,
NETWARE, NETBIOS и SHARE,  а также исходные коды демонстрационных
программ. Вы  должны  раскрыть  данный архив,  чтобы активировать
многопользовательские средства модуля FILER. В архив также входит
файл NETFILER.MAK.


C. Как приступить к работе
--------------------------

     Для того,  чтобы  прочувствовать свойства B-Tree Filer,  вы,
вероятно, захотите   запустить   программу    NETDEMO.    Версия,
поставляемая на      дискете     FILER,     компилируется     для
однопользовательского режима и содержит небольшие файлы  данных и
индексов, готовые  для  просмотра  и  внесения  изменений.  Чтобы
воспользоваться ими,  скопируйте   NETDEMO.EXE,   ADDRESS.DAT   и
ADDRESS.IX в  рабочую  директорию.  (Если  вы  хотите попробовать
запустить сетевую  версию  NETDEMO,   вам   потребуется   сначала
перекомпилировать ее с соответствующими определениями. Информацию
по этому вопросу см. в разделе 5.B, "Задание сети".)

     NETDEMO демонстрирует различные свойства B-Tree Filer, в том
числе:

     - Одно-  или многопользовательские действия в одной и той же
программе.

     - Множественные типы ключей в одном индексном файле.

     - Режим сохранности, защищающий целостность данных.

     - Записи переменной длины.

     - Полноэкранное редактирование баз данных.

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

     NETDEMO.EXE включает  также  средства  библиотеки TurboPower
Turbo Professional  -  экраны  вводы  данных   с   контролем   их
достоверности, а  также  редактирование полей памяти (memo).  Для
перекомпиляции NETDEMO.EXE вы  должны  иметь  Turbo  Professional
версии 5.02  или  старше.  Если у вас нет этой версии,  вы можете
поэкспериментировать с поставляемым исходным файлом SIMPDEMO.PAS,
который также  заархивирован  в  FILER.ARC.  Он  работает подобно
NETDEMO, но в нем отсутствуют средства записей переменной длины и
экранов ввода с контролем достоверности.

     NETDEMO работает  с файлом адресов,  который имеет следующие
поля:

     FirstName : String[15];
     LastName  : String[15];
     Company   : String[25];
     Address   : String[25];
     City      : String[15];
     State     : String[02];
     Zip       : String[10];
     Telephone : String[12];
     MemoLen   : Word;
     Memo      : variable length buffer of 1-1200 bytes

     Для быстрого  поиска  записей  используются индексные ключи.
Первичный ключ (не позволяющий наличия  дубликатов)  представляет
собой комбинацию  полей  LastName  и FirstName.  Вторичным ключем
является поле Zip.

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


B-Tree Filer Demo Program     Modify           Key: Last Name
========================================================================
| Zip   Name               ======= Modifying Record #4 =============== |
|02100 Dukakis, Michael    |  First name [Philippe       ]           | |
|10016 Dvorak, John C.     |  Last name  [Kahn           ]           | |
|95066 Folks at, The       |  Company    [Borland International    ] | |
|98073 Gates, Bill         |  Address    [1800 Green Hills Road    ] | |
|67890 Goeshere, Your Name |  City       [Scotts Valley  ]           | |
|60123 Jackson, Jesse      |  State      [CA]                        | |
|95999 Jobs, Stehpen       |  Zip        [95066-0001]                | |
|95066 Kahn, Philippe      |  Telephone  [408-438-8400]              | |
|95555 Lucas, George       |  Notes      [ ]                         | |
|97520 Mace, Paul          =========================================== |
|02142 Manzi, Jim          ================ Notes ==================== |
|12121 North, Oliver       |Sure, Microsoft's bigger, but they don't | |
|90403 Norton, Peter       |have a horns section                     | |
|84057 Petersen, Paul      |                                         | |
|03458 Pournelle, Jerry    |                                         | |
|77071 Presley, Elvis      |                                         | |
|11111 Quayle, J. Danforth |                                         | |
|23456 Swaggart, Jimmy     |                                         | |
|30311 Turner, Ted         |                                         | |
|56789 Tyson, Mike         ==Line:1  Column:1  7%  Insert Indent Wrap= |
========================================================================
ModAddDelFindKeyPrnInfoPurgeQuit

     Поскольку программа   NETDEMO   предназначена   для   сетевых
операций, она  должна  быть  способна  определить уникальный номер
рабочей станции,  который нужен для B-Tree Filer.  Если ваша опция
поддержки сети  определена как NoNet (по умолчанию компилируется в
поставляемом .EXE-файле),  Novell или MsNetMachName,  вам не о чем
беспокоиться, так  как  в  этом  случае номер станции определяется
автоматически. Однако,  если была задана сетевая опция  MsNet,  вы
должны передать  NETDEMO  в  командной  строке  одну опцию - номер
рабочей станции. Например,

     NETDEMO 10

зарегистрирует вас на рабочей сстанции номер 10.

     Затем NETDEMO спросит у вас, желаете ли вы работать в "Режиме
сохранности данных"  ("Save  Mode").  В  этом  режиме B-Tree Filer
всегда может восстановить данные в случае системного  или сетевого
сбоя. Такая  надежность обеспечивается за счет скорости выполнения
программ, но в случае интерактивного ввода данных  потери скорости
будут неощутимы для пользователя.

     NetDemo пытается  открыть  существующий набор данных в файлах
ADDRESS.DAT и  ADDRESS.IX.  Если  эти   файлы   найдены,   NETDEMO
продолжает работу.   В   противном  случае  программа  спрашивает,
желаете ли вы создать новый (пустой) наор данных.  Для того, чтобы
вам было легче исследовать работу программы NETDEMO, мы поставляем
некоторый набор адресов в указанных файлах.

     Если вы создаете новый набор данных,  NETDEMO сперва направит
вас к экрану ввода записей. Введите соответственные поля записи, а
затем нажмите  ,  чтобы  выйти  из  редактора  записи.
Помните, что   ключ,   образуемый  комбинацией  полей  LastName  и
FirstName, должен  быть  уникальным  во   всем   наборе   записей.
(использование в   качестве  первичного  ключа  только  имени  как
правило не  годится,  поскольку  при  этом   относительно   велика
вероятность дублирования   записей.   NETDEMO   избегает  создания
искусственного поля типа "номер клиента" или другого  такого поля.
В случае  появления  дублирующихся  ключей  в  NETDEMO  вы  должны
специально изменить одно из входящих в ключ имен.)

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

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

ModAddDelFindKeyPrnInfoPurgeQuit

     Ниже приводится краткое описание каждой команды:

       Модификация

     Редактирование содержимого   текущей   выбранной  записи.  По
окончании редактирования   NETDEMO   перестроит   индекс   записи.
Помните, что   запись  должна  иметь  уникальный  первичный  ключ.
Закончив редактирование,  нажмите ,  чтобы подтвердить
правильность внесенных изменений,  либо , чтобы отменить их и
вернуться к предыдущей  версии.  Вы  можете  также  модифицировать
данную запись,  нажав Enter>,  когда высвеченная линейка находится
на данной записи.

       Добавление

     Добавление новой  записи.  Для  подтверждения   необходимости
добавления новой  записи нажмите затем ,  а для отмены
добавления - .

       Удаление

     Удаление текущей выбранной записи. NETDEMO позволит вам затем
подтвердить или отменить решение об удалении записи.

       Поиск

     поиск записи.  NETDEMO  предоставит  вам полноэкранный шаблон
поиска, в котором вы сможете  ввести  параметры  поиска  по  любым
интересующим вас  полям.  Поиск  в  NETDEMO производится без учета
регистра, и  соответствие  не  обязательно  должно  быть   полным.
Например, введение   "IB"   в  имени  компании  будет  при  поиске
соответствовать записям вида "IBM"  или  "Ibsen  Baking  Company".
Если вводимые  вами  поля  поиска  являются частью индексных полей
NETDEMO (LastName и Zip),  то NETDEMO выполнит  быстрый  поиск  по
индексу, чтобы  найти  исходное  соответствие,  за  которым  может
следовать последовательный    поиск    для    просмотра    других,
не-индексных полей   поиска.   Если  NETDEMO  не  находит  полного
соответствия, она пытается поместить курсор в  окне полноэкранного
редактирования в   позицию,   как   можно   ближе  соответствующую
заданному критерию поиска.

       Выбор ключа

     По умолчанию NETDEMO представляет записи,  отсортированные по
первичному ключу   (LastName).   При  помощи  клавиши    можно
переключиться на любой другой ключ, когда записи будут выведены по
ключу Zip.  Текущий  активный  ключ  сортировки  всегда  указан  в
верхней строке экрана.

       печать

     Печать всех записей. При нажатии  NETDEMO сначала выводит
на дисплей  небольшое  меню.  вы  можете  выбрать печать записей в
последовательности ключей LastName или Zip,  либо вообще  отменить
запрос печати.  Если  вы  выбрали  печать,  NETDEMO записывает все
записи (одна строка на каждую запись) на принтер PRN по умолчанию.
Когда NETDEMO  печатает,  вы в любой момент нажатием любой клавиши
можете снять печать.

       Информация

     В нижней строке экрана выводится информация о  текущем наборе
данных с адресами. Сюда входит общее число записей в файле данных,
число удаленных записей, режим работы базы данных (Save или Normal
- повышенной  защиты  или обычный),  а также текущий номер рабочей
станции. для продолжения работы после  вывода  информации  нажмите
любую клавишу. (При использовании записей переменной длины счетчик
записей может сбиваться.  Вместо числа логических записей  в  базе
данных он    будет   показывать   число   "секций"   для   записей
фиксированной длины. Более подробную информацию см. в разделе 8.A)

       Очистка

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

       Выход

     Эта команда  служит  для  выхода  в  DOS.  NETDEMO  даст  вам
возможность изменить решение о выходе в DOS.


Устройство программы NETDEMO
----------------------------

     NETDEMO спользует    простой   метод   запирания   данных   в
многопользовательской среде.  Когда  ей  требуется   гарантировать
доступ к  конкретной  записи,  NETDEMO  просто  запирает  всю базу
данных целиком  (при  помощи  )  на   самый
короткий, насколько это возможно,  промежуток времени.  При чтении
записей она  сначала  проверяет,  не  заперты   ли   они   другими
пользователми. Если запись заперта,  NETDEMO запрашивает, нужно ли
повторить попытку,  либо отменяет операцию,  если таков ваш выбор.
(Фактически процесс запирания более сложен,  нежели описано здесь.
Полное описание его см. в разделе 6.B).

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

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

Использование модулей B-Tree Filer
----------------------------------

     Поскольку B-Tree  Filer  работает либо в Turbo Pascal 4.0 или
5.0, и поскольку многопользовательская версия  требует,  чтобы  вы
задали директиву компиляции, специфичную для вашей сети, мы решили
не гадать,  какие  именно   прекомпилированные   файлы   TPU   вам
понадобятся. Вместо  этого вы просто разархивируете исходные файлы
BTree Filer в  рабочей  директории,  а  остальную  работу  за  вас
сделает компилятор.

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

     ARCX.COM      Программа разархивации с дискеты FILER
     FILER.ARC     Однопользовательское В-дерево с дискеты FILER
     NETFILER.ARC  Сетевые коды с дискеты NET, только в случае
                   приобретения вами многопользовательской
                   версии B-Tree Filer

     Затем на приглашение DOS введите:

     ARCX FILER
     ARCX NETFILER

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

     для выбора конкретной сетевой опции вы должны отрежактировать
исходный файл BTDEFINE.INC и изменить директиву  $DEFINE,  которая
находится в верхней части этого файла. Выберите нужное определение
из числа  приведенных  после  существующего   определения.   Более
подробную информацию о сетевых опциях см. в разделе 5.B.

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

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

     program Myprogram;
       Uses ..., FILER, ...;

     Еще примеры находятся в NETDEMO.PAS или  SIMPDEMO.PAS.  Кроме
того, см.  разделы  3.B,  "Организация  программы" и 3.C,  "Прмеры
программирования", где находится дополнительная вводная информация
о написании программ с использованием B-Tree Filer.

     В каждом  исходном  архиве  находится  .MAK-файл,  который вы
можете использовать с утилитой MAKE фирмы  Borland  (но  не  фирмы
Microsoft). Если  вы приобрели многопользовательскую версию B-Tree
Filer, соответствующим файлом является NETFILER.MAK.  В случае  же
однопользовательской версии  это  файл  FILER.MAKE.  Использование
этих файлов не является обязательным,  поскольку компилятор  Turbo
Pascal имеет соответствующее встроенное средство. Тем не менее, мы
поставляем эти файлы,  поскольку они полностью задают  зависимости
между всеми   файлами  B-Tree  Filer.  Для  чтения  и  модификации
.MAK-файлов можно использовать любой  текстовый  редактор.  Каждый
файл включает в себя полные инструкции о работе с файлом.  Если вы
пожелаете более подробно углубиться в исходный код  B-Tree  Filer,
обратитесь к Приложению F,  где содержимое каждого исходного файла
описано более подробно.


D.  Соглашение о приобретении
-----------------------------

     Данное программное обеспечение и  сопутствующая  документация
защищены законом  об авторских правах Соединенных Штатов,  а также
положениями Международного Договора.  Любое использование  данного
программного обеспечения  в  нарушение  закона об авторских правах
или в нарушение положений данного Соглашения  будут преследоваться
нами в силу наших возможностей.

     Большие части  данного  программного обеспечения представляют
собой авторское право (c) 1986,87,88  Дипломированного  математика
Ральфа Найгеля (Dipl.Math.  Ralf Nagel). другие части программного
обеспечения представляют собой  авторское  право  (c)  1989  фирмы
TurboPower Software. TurboPower Software распространяет защищенные
авторским правом работы Ральфа Найгеля  по  эксклюзивной  лицензии
Enz EDV-Beratung Gmbh из Западной Германии.

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

     Вы можете  распространять,  без  платы  за   версию   времени
выполнения или    любых    других   лицензий,   ваши   собственные
скомпилированные программы,  основанные  на  любом  исходном  коде
B-Tree Filer.  Вы  не  имеете  право распространять любые исходные
коды B-Tree Filer,  скомпилированные модули  или  скомпилированные
примеры программ без письменного разрешения TurboPower Software.

     Отметим, что   предыдущие   ограничения   не   запрещают  вам
распространять ваши  собственные   исходные   коды   или   модули,
зависящие от B-Tree Filer.  Однако, тот, кто получает от вас такие
исходные коды или  модули,  должен  приобрести  собственную  копию
B-Tree Filer,  чтобы  на законном основании компилировать исходный
код или писать  программы,  использующие  модули,  обращающиеся  к
B-Tree Filer.

     Поставляемое программное  обеспечение может быть использовано
только одним лицом на стольких компьютерных системах,  сколько это
лицо использует.   Мы   расчитываем,   что   группы  разработчиков
программного обеспечения будут приобретать  у  нас  индивидуальные
копии программного обеспечения и документации по числу сотрудников
такой группы.  По вопросам скидки с  общего  объема  и  по  поводу
соглашений о  лицензировании рабочих мест обращайтесь к TurboPower
Software.

     Относительно физических экземпдяров  дискет  и  документации,
поставляемых с  B-Tree  Filer,  TurboPower Software гарантирует их
исправность и отсутствие в них дефектов материала  и  изготовления
на период  в  30  дней  с  момента  получения покупателем.  Если в
гарантийный срок вы уведомили  нас  о  таком  дефекте,  TurboPower
Software заменит   дефектную   дискету(дискеты)  или  документацию
бесплатно.

     TurboPower Software гарантирует,  что программное обеспечение
будет работать,  как  описано в данной документации,  в течение 30
дней от даты получения.  При обнаружении  программной  ошибки  или
дефектности нам потребуется подробный отчет о возникших проблемах,
который позволит нам  найти  и  зафиксировать  проблему.  Если  вы
правильно уведомите   нас   о   такой   проблеме   с   программным
обеспечением в течение  гарантийного  срока,  TurboPower  Software
заменит дефектное программное обеспечение бесплатно.

     TurboPower Software   гарантирует   также,   что   покупатель
останется полностью удовлетворен нашим продуктом  весь  период  30
дней со   дня   получения.   Если   по   какой-то  причине  вы  не
удовдетворены, а  TurboPower  Software  не   может   решить   вашу
проблему, обратитесь   к   стороне,  у  которой  была  произведена
покупка, за разрешением на возврат.  Если продукт  был  приобретен
непосредственно у   TurboPower  Software,  мы  вернем  вам  полную
стоимость покупки данного программного  продукта  после  получения
исходной дискеты    (дискет)    с   программным   обеспечением   и
документации в неповрежденном виде. TurboPower Software практикует
возврат продуктов от своих официальных дилеров, но не поддерживает
прямого возврата   платежа   тем,   кто   не   приобрел    продукт
непосредственно на нашей фирме.

     TurboPower Software   не   предполагает   ответственности  за
использование B-Tree Filer в сумме, превышающей исходную стоимость
приобретения данного программного обеспечения. TurboPower Software
ни  в  коем  случае  не   может   быть   ответственна   за   любой
дополнительный   ущерб,  включая  потерянные  прибыли,  потерянную
экономию,  либо любой другой  случайный  или  закономерный  ущерб,
возникший вследствие использования или невозможности использования
данных программ,  даже если TurboPower  Software  предупреждала  о
возможности такого ущерба.

     При использовании     данного     программного    обеспечения
предполагается, что   вы   согласны   с   положениями   настоящего
раздела. Если  вы не согласны с ними,  вы должны немедленно верную
весь пакет B-Tree Filer для получения возвращаемого платежа.

     TurboPower Software предлагает  телефонную  поддержку  B-Tree
Filer при  технической возможности без дополнительных платежей. Мы
приглашаем вас звонить нам по телефону поддержки с понедельника по
пятницу с  9  утра  до  5  вечера  (по тихоокеанскому времени),  и
обращаться за  помощью.   Мы   также   абонируем   для   поддержки
пользователя код CompuServe. Этот код и номера телефонов приведены
на титульном листе данного руководства.

     Мы верим в поддержку наших клиентов  и  сделаем  все  от  нас
зависящее, чтобы  наше  программное  обеспечение делало ту работу,
для которой мы его разрабатывали!



2. Принципы работы
------------------

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

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

A. Данные и ключи
-----------------

     Существует два  базовых  метода   поиска   в   базе   данных
конкретной информации:

     - последовательный доступ к данным;
     - индексно-последовательный доступ к данным, также известный
как прямой доступ.

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

     Информация, которая  необходима  для  поиска  записи данных,
доступна благодаря информации  об  индексном  ключе,  хранимой  в
B-Tree Filer.  Записи  данных и ключи хранятся в двух независимых
файлах, файле данных и индексном файле.

     Файл данных  состоит  из   записей   данных   фиксированного
размера, хранимых   одна   за   другой.   Каждая   запись  данных
соответствует некоторому  номеру,  являющемуся   адресом   записи
данных, и  определяющему  позицию  записи  данных в файле данных.
Например, адрес 0 ссылается на самую первую запись  файла  данных
(в B-Tree  Filer резервируется для внутреннего использования),  а
адрес 1   определяет   первую   запись   файла,   доступную   для
пользователя. Когда  запись  вводится  в  файл  данных при помощи
подпрограммы B-Tree Filer  ,  возвращается  адрес  записи
данных в  файле  данных,  который  затем  может  быть  добавлен в
индексный файл с соответствующим ключом.  Индексный файл содержит
ключи и  значения адресов соответствующих записей в файле данных.
(Термины "адрес записи данных"  и  "номер  записи"  чередуются  в
документации).

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

B. Организация В-дерева
-----------------------

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

Терминология В-дерева
---------------------

     Термин "древовидная структура" происходит от  аналогии  этой
общей структуры   данных   и  изображения  перевернутого  дерева.
"Узел" В-дерева представляет собой совокупность одного  или более
индексных ключей.    "Ветви",    соединяющие   узлы,   определяют
последовательность поиска  для  того,  чтобы   найти   конкретное
значение ключа.  Ветви дерева направлены вниз, начиная с "корня",
и кончая узлами,  из которых уже новые ветви  не  выходят.  Такие
узлы называются "листьями" дерева. (См. Рис.1 ниже.)

     Высота дерева определяется максимальным числом ветвей, через
которое нужно "пройти" от корня до  любого  листа.  Корень  имеет
уровень  1,  его прямые ветви имеют уровень 2,  в свою очередь их
прямые потомки имеют уровень 3,  и т.д. Все узлы-листья, т.е. все
узлы,   не   имеющие   потомков,   в  случае  структуры  В-дерева
заканчиваются на одном и том же уровне.


  ^                   ---------------
  |                   |   Корень    |
  |                   ---------------
  |                   /             \      <------- Ветвь
  |                  /               \
  |              --------          --------
Высота           | Узел |          | Узел |
  |              --------          --------
  |               /    \            /     \
  |              /      \          /       \
  |         --------  --------  --------  --------
  \/        | Лист |  | Лист |  | Лист |  | Лист |
            --------  --------  --------  --------

     Рис. 1:  В-дерево порядка 2 и высоты 3

     Число ветвей,   выходящих   из   данного   узла,  называется
"степенью" узла;  максимальная степень определяет степень дерева.
Например, двоичное  дерево  имеет  степень два,  поскольку каждый
узел имеет две  ветви.  Деревья  со  многими  ветвями,  например,
В-дерево, имеет степень выше двух.  В B-Tree Filer степень дерева
устанавливается неявно,  через константу ,  в  значение
+1.

     "Порядок" дерева  определяется  как минимальное число ветвей
для любого узла.  Каждый узел  В-дерева,  за  исключением  корня,
должен быть   как  минимум  наполовину  заполнен;  следовательно,
каждый узел,  кроме корня,  должен иметь не менее  /2+1
ветвей. Это приводит к эффективному использованию памяти.

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

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

В-деревья для баз данных
------------------------

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

     Элементарные индексы   хранятся  в  каждом  узле  в  порядке
возрастания.  Первый элементарный индекс содержит наименьший ключ
для   данного   узла;   последний  элементарный  индекс  содержит
максимальный ключ для данного узла.

     Элементарные индексы  определяются  как  записи,  содержащие
следующие поля:

     - соответствующий ключ
     - ссылка (адрес) к записи данных
     - ссылка к узлу вперед

     Ссылка к  узлу (указатель в прямом направлении) указывает на
узел, содержащий ключ,  имеющий большее  значение,  чем  то,  что
хранится в текущем элементе инжекса. (См. Рис.2 ниже.)


                                         =======
                                    ---> | 'A' |
     ==========================    |     | 'B' |
  ---| Счетчик                |    |     | 'C' |
 |   | Указатель назад        |----      |  x  |
 |   |========================|          -------
 |   |                    'D' |          =======
 |   |                        |     ---> | 'E' |
 |   |                        |    |     | 'L' |
 |   |                        |----      |  x  |
 |   |------------------------|          |  x  |
 |   |                    'M' |          -------
 |   |                        |          =======
 |   |                        |     ---> | 'N' |
 |   |                        |    |     | 'P' |
 |   |                        |----      | 'Q' |
 |   |------------------------|          | 'S' |
  -->| Ключ               'X' |          -------
     | Ссылка (адрес) к данным|          =======
     | Указатель вперед       |--------> | 'Y' |
     |                        |          | 'Z' |
     |                        |          |  x  |
     |------------------------|          |  x  |
     |xxxxxxxxxxxxxxxxxxxxxxxx|          -------
     |xxxxxxxxxxxxxxxxxxxxxxxx|
     |xxxxxxxxxxxxxxxxxxxxxxxx|
     ==========================

     Рис.2:  Внутренняя структура В-дерева


     Сам узел объявлен как запись и содержит:

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

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

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

     Каждый узел  содержит  минимум      и   максимум
 элементарных индексов.  Корень составляет единственное
исключение в  том  смысле,   что   он   может   содержать   менее
 элементарных индексов.

     Выбор значения    требует  некоторого компромисса.
Поиск ключей в  больших  страницах  требует  меньше  обращений  к
диску, и  следовательно,  работает быстрее,  чем в случае меньших
страниц. поиск в странице идет сравнительно быстрее, чем загрузка
страницы с диска. Однако, большее значение  увеличивает
требования B-Tree Filer  к  памяти,  а  также  увеличивает  время
чтения страницы. Значение  по умолчанию 62 было выбрано
на основе тщательных  экспериментов  и  гарантирует  оптимум  для
времени доступа и использования памяти.

     B-Tree Filer  также  определяет максимальную высоту В-дерева
константой .  При значении по умолчанию 8 В-дерево  не
будет заполнено,  пока  туда  не  будет  добавлено  10^14 ключей*
Поскольку 2^32 ключей меньше, чем 10^10, опасности переполнения В
-дерева не существует!

Ключи в индексном файле
-----------------------

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

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

     Индексные ключи должны иметь тип  String  ().
Если в  качестве  ключа  должно использоваться число,  оно должно
сначала быть преобразовано в строку символов.  (Подпрограммы  для
таких преобразований находятся в модуле NUMKEYS, который описан в
разделе 8.F).  Значение  каждого  элемента  в   строке   является
величиной ASCII.  При  построении  строк  следует быть осторожным
(например, при использовании заглавных и  строчных  букв),  чтобы
обеспечивалось правильное сравнение ключей.

     Существует два  типа  ключей,  которые различаются следующим
образом:

     - первичные ключи: ключи, уникальные в базе данных
     - вторичные ключи: ключи, которые можно вводить многократно.

     Первичные ключи  не могут быть дублированы в индексном файле
(это требование устанавливается подпрограммами  индексации B-Tree
Filer). В  качестве  первичных  ключей  могут  быть  использованы
уникальные номера клиентов, счетов и т.д.

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

     Максимальная длина     ключа     определяется     константой
, которая  может  лежать  в  диапазоне  от  1  до  255
(значение по   умолчанию   30).   Длина   и   тип  каждого  ключа
определяются значениями полей  и , задаваемыми в
переменной B-Tree Filer типа .

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

C. Управление ключами
---------------------

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

Поиск ключа
-----------

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

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

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

     В-дерево позволяет  также  доступ  к  записям  базы данных в
отсортированном последовательном  порядке.  Начиная  с   заданной
стартовой точки  прямой  указатель  текущего  индексного элемента
ведет к следующему ключу  в  отсортированной  последовательности.
При достижении  узла-листа  алгоритм  возвращается  на предыдущий
уровень узла и  продолжает  со  следующего,  большего  индексного
элемента. Это  эквивалентно  первому  по  глубине траверсированию
В-дерева. Для   обозначения   конкретного   адреса   в   В-дереве
используется термин   "последовательный   указатель".  Фактически
последовательный указатель  представляет  собой  массив  записей,
каждая из  которых  содержит  одно  число,  определяющее узел,  и
второе, указывающее на активный элемент в  узле. Последовательный
указатель можно  рассматривать  как  маршрут,  ведущий от корня к
узлу, содержащему текущий элемент. Конкретные подпрограммы B-Tree
Filer инициализируют    последовательный    указатель   известным
значением. Другие    подпрограммы    переопределяют    указатель,
присваивая ему временное значение.  Описания подпрограмм содержат
и описание воздействие их на последовательный указатель.

Добавление ключа
----------------

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

     Требуемая область  хранение  создается  расщеплением данного
узла на  два.  Индексные  элементы,  меньшие  чем   /2,
остаются в  старом  узле,  а  большие  помещаются  в  новый узел.
Средний индексный элемент, меньший, чем индексные элементы нового
узла, используется  для указания на этот новый узел,  путем ввода
его в узел на предыдущем уровне дерева.

     Если узел, в который должен вводиться этот средний индексный
элемент, также полон,  то происходит расщепление следующего узла.
Рекурсивные применения этого метода могут  привести  к  "делению"
всех узлов до корневого уровня. Даже сам корень при необходимости
может быть расщеплен. В таком случае средний индексный элемент из
последнего деления станет новым корнем, а дерево вырастет на один
уровень. Это   единственный   случай,   когда    высота    дерева
увеличивается. Данное  правило добавления ключей сохраняет четкую
характеристику В-дерева,  состоящую в том,  что  все  узлы-листья
должны лежать на одном уровне.


                      -------------
                      |  J  |     |
                      -------------
                     /       \               Исходное состояние
               -------------  -------------
               |  J  |     |  |  M  |     |
               -------------  -------------

                      -------------
                      |  J  |     |
                      -------------
                     /       \               Добавление P
               -------------  -------------
               |  J  |     |  |  M  |  P  |
               -------------  -------------

                      -------------
                      |  J  |  P  |
                      -------------
                     /      |       \        Добавление Q
       -------------  -------------  -------------
       |  F  |     |  |  M  |     |  |  Q  |     |
       -------------  -------------  -------------

     Рис.3: Добавление ключей в В-дерево

     При реализации расщепления  узлов  B-Tree  Filer  предлагает
дпльнейшее усовершенствование базовой теории В-дерева.

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

     Этот метод лучше в том плане, что он позволяет заполнить все
узлы ключами,  экономя  тем  самым  память.  Это  дает  следующие
преимущества:

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

     При использовании     непрерывно      растущих,      имеющих
последовательные значения  ключей  (номеров клиентов,  например),
размер индексного файла может быть уменьшен на 30-50%.

Удаление ключа
--------------

     Если ключ должен быть удален,  сначала должен быть определен
адрес ключа в дереве. Это выполняется описанным выше способом.

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

     Если после удаления узел имеет менее  /2 индексных
элементов ("недостача"), можно предпринять одно из двух действий.
Либо  из  соседнего  узла  туда  могут  быть  помещены  индексные
элементы  ("баланс  страницы"),  как  описано выше для добавления
новых ключей.  Либо, в случае, когда соседний узел также страдает
от  "недостачи",  две  страницы  могут  быть  объединены  в  одну
("слияние узлов",  операция,  обратная  расщеплению).   Страница,
являющаяся родительской    для    объединившихся   узлов,   также
уменьшается на один  индексный  элемент.  Если  она  также  будет
страдать от  "недостачи",  а балансировка страниц невозможна,  то
опять повторится объединение с соседней страницей.  При некоторых
обстоятельствах этот  процесс  дойдет  до корня.  Если произойдет
удаление единственного индексного элемента, составляющего корень,
то дерево сожмется до одного уровня. Это единственный путь, когда
В-дерево может потерять высоту.

     Снова отметим,  что  файлы  индексов   и   данных   хранятся
раздельно. Если   индексный   элемент   удаляется   без  удаления
соответственной записи   данных,   то   такая   запись   остается
"сиротой" в   файле  данных,  т.е.  ее  больше  нельзя  найти  по
индексной ссылке.

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



3. Использование B-Tree Filer
-----------------------------

     По сравнению с плотным концептуальным  изложением  Главы  2,
данная глава  более  затрагивает  практические вопросы.  Здесь мы
покажем, как  использовать  B-Tree  Filer  при  разработке  ваших
прикладных программ. Примеры программ в разделе С помогут быстрее
войти в курс дело тем, кто лучше обучается на примерах.

A. Файловые блоки
-----------------

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

     B-Tree Filer   может  организовывать  любое  число  файловых
блоков, ограниченное  исключительно   числом   открытых   файлов,
допустимое в  данной  операционной  системе.  Для  каждого  файла
данных существует только один индексный файл, независимо от числа
определенных для  него ключей.  Следовательно,  если одновременно
должно быть открыто пять однопользовательских файловых блоков, то
операционная система  должна  разрешать десять различных открытых
файлов. Если  должно  быть  открыто   три   многопользовательских
файловых блока,  то  операционная система должна допускать девять
открытых файлов DOS.

     (MS-DOS для каждого  процесса  может  максимально  управлять
числом файлов,    заданным   параметром   FILES=ЧИСЛО   в   файле
CONFIG.SYS. Поскольку первые пять файлов всегда используются DOS,
учтите это  при  подсчете  общего  числа  файлов  в запросе.  Без
расширений DOS  позволяет  иметь  в  данной   программе   до   20
одновременно открытых   файлов.  B-Tree  Filer  включает  в  себя
процедуру ,  которая при  работе  в  DOS  3.3  или
старше дает возможность увеличивать это число.)

     Обращения к  базам  данных  B-Tree  Filer  происходит  через
указатель к  файловому  блоку.  Это  минимизирует   распределение
статических данных  за  счет  использования  "кучи"  для хранения
информации файлового блока,  которая должна находиться в  памяти.
Прикладная программа   объявляет   для  каждого  файлового  блока
переменную-указатель типа   ,   занимающуювсего
четыре байта в сегменте данных.

В. Организация программы
------------------------

     Для доступа  к  подпрограммам   B-Tree   Filer   используйте
оператор USE  с именем модуля FILER в вашей главной программе и в
любых других модулях,  где это необходимо.  Программа должна быть
организована в следующую последовательность действий:

Макет программы
---------------

     1. Создание страничного буфера вызовом 
     2. Открытие  или создание нескольких файловых блоков вызовом
,  или 
     3. Использование  процедур  или  функций  B-Tree  Filer  для
открытых файловых блоков
     4. Закрытие   всех   открытых  файловых  блоков  при  помощи

     5. Освобождение       страничного       буфера       вызовом


     Данная последовательность может быть повторена  столько раз,
сколько это нужно. Кроме того, в промежутке между пунктами один и
пять файлы могут открываться и закрываться столько  раз,  сколько
потребуется.

     Еще один  важный  аспект  работы  программы,  который должен
обрабатываться на верхнем уровне программы,  связан с  обработкой
ошибок. B-Tree  Filer  экспортирует  на  верхний  уровень  булеву
переменную ,  которая устанавливается в значение True при
успешном завершении  и  в  False в случае ошибки.  Далее доступна
целочисленная переменная         ,         позволяющая
классифицировать ошибку.  Почти  каждый вызов подпрограммы B-Tree
Filer следует завершать проверкой .

Режим сохранности или нормальный режим?
---------------------------------------

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

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

     Совершенно понятно,   что   протокол,   ведущийся  в  режиме
сохранности, существенно   увеличивает   затраты    времени    на
обновление файлов  B-Tree  Filer.  Прежде  чем использовать режим
сохранности, рассмотрите следующие вопросы:

     - Режим  сохранности  следует  использовать   только   когда
описанный выше  процесс  реконструкции неприемлем.  Реконструкция
5000 записей данных с 4 ключами занимает от 5 до 20 минут.

     - Успешное   завершение   процедур       или
 независимо  друг  от друга гарантирует,  что
все данные будут записаны на физический диск.

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

     - Данные,  используемые только одним пользователем, не столь
критичны, как  например,  данные,  доступные  через   файл-сервер
многим пользователям сети.

     Файловый блок,   используемый  в  сети,  является  идеальным
случаем, когда  желателен  режим  сохранности.  Более   подробная
информация находится в Главе 6.

Подготовка к использованию сетевых средств
------------------------------------------

     Многие однопользовательские  прикладные  программы  в  конце
концов переносятся в сетевую среду. Для упрощения этой задачи все
вызовы процедур   и   функций   B-Tree   Net   доступны    и    в
однопользовательской версии.   Эти   подпрограммы   не  выполняют
фактических обращений   к   сети,   а   вызывают   вместо   этого
соответственные однопользовательские    подпрограммы.    Если   в
однопользовательской среде   выполняемые    ими    действия    не
определены, то  такие  подпрограммы  просто  не выполняют никаких
действий. См.    Главу    5,    где    находится    введение    в
сете-ориентированные подпрограммы B-Tree Filer.

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

С. Примеры программирования
---------------------------

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

     Следующие примеры кодов можно найти в файле  EXAMPLES.PAS на
дискете FILER.  (EXAMPLES.PAS  фактически  не служит ни для каких
целей, но  он   может   оказаться   полезным   с   точки   зрения
использования его фрагментов в ваших программах).

Определения данных
------------------

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

type
  PersonDef =
    record
      Del : LongInt;
      FirstName : String[20];
      LastName : String[25];
      Street : String[30];
      City : String[30];
      State : String[2];
      ZipCode : String[5];
      Telephone : String[15];
      Comments : String[70];
      Age : Integer;
    end;

     Первое поле,  , типа LongInt, должно инициализироваться
прикладной программой  в  нулевое  значение.  Хотя  это  поле  не
является обязательным  требованием  B-Tree Filer,  мы рекомендуем
вам начинать  такими  полями  все  записи  данных.  B-Tree  Filer
переопределяет значение  этих  первых четырех байтов при удалении
записи, чтобы  организовать   связный   список   свободного   для
повторного использования  пространства  в  файле  данных.  Многие
свойства B-Tree Filer, в частности перепостроения и реорганизации
файловых блоков, определяют достоверность данной записи, проверяя
для этого,  содержат  ли  первые  четыре  байта  записи   нулевое
значение. (Удаленные  записи  всегда имеют ненулевое значение,  а
достоверные - нулевое). Если поле  не определено, то все эти
средства работать не будут.

     Остальные поля  относятся  к  предметной  области программы.
Единственное накладываемое B-Tree  Filer  ограничение  состоит  в
том, что  запись  должна  иметь  размер в 21 байт или более.  Это
ограничение является следствием того,  что первая  запись  любого
файла данных  содержит  информацию,  описывающую  базу  данных  в
целом, позволяя  B-Tree  Filer  открывать  ее  без  использования
дополнительных файлов.

     Для доступа  к  соответственному файловому блоку должна быть
объявлена переменная  типа  ,  как  описано   в
разделе 3.B,   "Организация  программы".  Обычно  эта  переменная
должна являться глобальной по отношению ко всей программе.

var
  PF : IsamFileBlockPtr; {Символическое имя для доступа к базе данных}

Распределение страничных буферов
--------------------------------

     B-Tree Filer использует страничные  буферы  для  хранения  в
оперативной памяти  стольких узлов В-дерева,  сколько поместится,
оптимизируя тем самым время поиска. Его алгоритм требует, чтобы в
оперативной памяти    одновременно    находилось    как   минимум
 узлов.  Для  распределения  памяти  этим   страничным
буферам используется  подпрограмма .  Она позволяет
зарезервировать область кучи для другого использования,  а  затем
выделить оставшуюся часть кучи буферам.

  procedure AllocatePageBuffer(HeapToRemain : LongInt);
  var
    NumberOfPages : Word;
  begin
    NumberOfPages := GetPageStack(HeapToRemain);
    if not IsamOK then begin
      {Не хватает памяти}
      Halt;
    end;
  end;

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

     Для того,  чтобы  избежать избыточного расходования ресурсов
во многих подпрограммах нижнего уровня B-Tree Filer не проверяет,
была ли  вызвана  .  Это должны обеспечить вы сами:
если об этом забыть, возможен сбой программы.

     Дальнейшие детали  относительно  страничных  буферов  см.  в
разделе с описанием .

Создание файлового блока
------------------------

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

const
  NrKeys = 3;                     {Число ключей}
  Key1Len = 30;                   {Имя и фамилия}
  Key2Len = 5;                    {Почтовый код}
  Key3Len = 15;                   {Телефон}

  function CreateFile : Boolean;
  var
    IID : IsamIndDescr;
  begin
    IID[1].KeyL := Key1Len; IID[1].AllowDupK := False;
    IID[2].KeyL := Key2Len; IID[2].AllowDupK := True;
    IID[3].KeyL := Key3Len; IID[3].AllowDupK := True;
    MakeFileBlock(PF, 'TEST', SizeOf(PersonDef), NrKeys, IID);
    CreateFile := IsamOK;
  end;

     CreateFile создаст   необходимые  файлы  данных  для  нового
файлового блока.  В  вашем  примере    присваивает
 PF  файлу данных 'TEST.DAT' и индексному файлу
'TEST.IX'. Функция Паскаля SizeOf дает длину записи  данных, т.е.
размер записи.

     Параметр, описывающий ключи, определен в переменной IID типа
. IID перед  вызовом    должен  быть
инициализирован. В   данном  примере  для  каждой  записи  данных
существует три ключа.  (B-Tree  Filer  позволяет  определить  для
каждой записи до 100 ключей,  каждый ключ до 30 символов в длину.
Эти значения могут  быть  изменены  путем  изменения  констант  в
FILER.PAS. Подробности   см.   в   разделе  4.А).  
описывает каждый ключ,  задавая максимальную длину каждой троки и
то, является  ли  этот  ключ первичным (уникальным) или вторичным
(допускающим существование дубликатов).  Ключи могут  создаваться
из любых данных;  они не ограничиваются данными из одного поля. В
нашем примере   первичный   ключ   буде   являться    результатом
конкатенации фамилии  и имени.  Вторичными ключами будут почтовый
код и номер телефона.

Открытие файлового блока
------------------------

  function OpenFile : Boolean;
  begin
    OpenFileBlock(PF, 'TEST');
    if not IsamOK then begin
      OpenFile := False;
      {Здесь может находиться часть программмы для  сообщения  об
       ошибке на основе  и .
       Могут следовать действия по исправлению ошибки, например
       реконструкция запорченного индексного файла,
       как описано в разделах 3.D и 8.С.}
      Exit;
    end else
      OpenFile := True;
  end;

     OpenFile показывает,  каким образом может выглядеть  функция
для открытия  существующего  файлового блока.  Она содержит вызов
процедуры ,  которая  открывает  файловый  блок  в
нормальном режиме. (Вызов  приведет к открытию
в режиме  сохранности.)   Использование   глобальных   переменных
 и    позволяет  обнаруживать ошибки,  которые
могут произойти при открытии файлов.  Отметим,  что информация  о
длине записи  или ключах для открытия уже существующего файлового
блока не нужна.  B-Tree Filer считывает эту информацию  из  файла
данных и хранит ее в соответствующем файловом блоке в памяти.

Закрытие файлового блока
------------------------

  function CloseFile : Boolean;
  begin
    CloseFileBlock(PF);
    if not IsamOK then begin
      CloseFile := False;
      {Обработка ошибки}
      Exit;
    end else
      CloseFile := True;
  end;

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

Операции с файлами индексов и данных
------------------------------------

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

  function CreateKey(P : PersonDef; KeyNr : Integer) : IsamKeyStr;
  begin
    with P do
      case KeyNr of
        1 : CreateKey := StUpcase(Copy(LastName, 1, 20)+Copy(FirstName, 1, 10));
        2 : CreateKey := ZipCode;
        3 : CreateKey := Telephone;
      else
        CreateKey := '';
      end;
  end;

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

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

Добавление данных в файловый блок
---------------------------------

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

  procedure UndoAdd(P : PersonDef; RefNr : LongInt; LastKey : Integer);
  var
    KeyNr : Integer;
    Key : IsamKeyStr;
  begin
    for KeyNr := 1 to LastKey do begin
      Key := CreateKey(P, KeyNr);
      DeleteKey(PF, KeyNr, RefNr, Key);
      if not IsamOK then begin
        {Abort: слишком много ошибок}
        Halt;
      end;
    end;
  end;

  function AddRecord(P : PersonDef) : Boolean;
  var
    KeyNr : Integer;
    RefNr : LongInt;
    Key : IsamKeyStr;
  begin
    AddRecord := False;
    AddRec(PF, RefNr, P);
    if not IsamOK then begin
      {Обработка ошибки}
      Exit;
    end;
    for KeyNr := 1 to NrKeys do begin
      Key := CreateKey(P, KeyNr);
      AddKey(PF, KeyNr, RefNr, Key);
      if not IsamOK then begin
        {Удаление до сих пор добавленных ключей}
        UndoAdd(P, RefNr, KeyNr-1);
        {Удаление новой записи}
        DeleteRec(PF, RefNr);
        {Обработка ошибки}
        Exit;
      end;
    end;
    AddRecord := True;
  end;


     После того,  как новая запись данных была успешно введена  в
файл при  помощи  ,  в цикле FOR один за другим создаются
ключи и  добавляются  в  индексный  файл  при  помощи   .
Переменная RefNr  содержит  адрес,  по  которому  записана  новая
запись данных.  Если во  время  операций  с  ключами  встретились
ошибки (например,  =10230,  что  означает дублирование
ключей), функция UndoAdd пытается удалить добавленные до  сих пор
ключи, поэтому  выход  AddRecord  может  произойти аккуратно,  не
испортив файловый блок.  Однако,  если при удалении произошли еще
ошибки, то  дальнейшие  попытки  восстановления могут дать больше
проблем, чем решить6 поэтому программа должна  быть абортирована.
AddRecord возвратит True, если все операции завершились успешно.

Удаление данных из файлового блока
----------------------------------

     Функция DeleteRecord аналогична Addrecord.

  procedure UndoDel(P : PersonDef; RefNr : LongInt; LastKey : Integer);
  var
    KeyNr : Integer;
    Key : IsamKeyStr;
  begin
    for KeyNr := 1 to LastKey do begin
      Key := CreateKey(P, KeyNr);
      AddKey(PF, KeyNr, RefNr, Key);
      if not IsamOK then begin
        {Abort: слишком много ошибок}
        Halt;
      end;
    end;
  end;

  function DeleteRecord(P : PersonDef; RefNr : LongInt) : Boolean;
  var
    KeyNr : Integer;
    Key : IsamKeyStr;
  begin
    DeleteRecord := False;
    {Убедиться, что эта запись не является уже удаленной}
    if P.Del <> 0 then
      Exit;
    for KeyNr := 1 to NrKeys do begin
      Key := CreateKey(P, KeyNr);
      DeleteKey(PF, KeyNr, RefNr, Key);
      if not IsamOK then begin
        {Добавить ключи, удаленные к тому моменту}
        UndoDel(P, RefNr, KeyNr-1);
        {Обработка ошибки}
        Exit;
      end;
    end;
    DeleteRec(PF, RefNr);
    if IsamOK then
      DeleteRecord := True;
  end;

     Для того,   чтобы  предупредить  разрушительные  последствия
попытки удаления уже удаленной записи,  проверяется  поле  P.Del,
чтобы убедиться, что эта запись данных не была удалена ранее. При
удалении записи данных  действия  в  точности  обратны  тем,  что
выполняются при   добавлении  записи.  сначала  делается  попытка
удаления ключей,  а  затем  записи  данных.  Делать  ли   попытку
отменить удаление  в  случае  ошибки  -  это  спорный вопрос.  Мы
показали здесь UndoDel,  однако вы можете решить, что имеет смысл
продолжать удаление   ключей   даже   при   неудачном  завершении
.

Модифицирование записей
-----------------------

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

  function CheckRecord(P, POld : PersonDef) : Boolean;
  begin
    {Проверить, что: новая запись содержит достоверные ключи,
                     новая запись отлична от старой}
    CheckRecord := True;
  end;

  procedure UndoMod(P, POld : PersonDef; RefNr : LongInt; LastKey : Integer);
  begin
    {Удалить все новые ключи}
    UndoAdd(P, RefNr, LastKey);
    if not IsamOK then begin
      {Abort: слишком много ключей}
      Halt;
    end;
    {Вернуть старые ключи}
    UndoDel(POld, RefNr, LastKey);
    if not IsamOK then begin
      {Abort: слишком много ошибок}
      Halt;
    end;
    {Вернуть старую запись}
    PutRec(PF, RefNr, POld);
    if not IsamOK then begin
      {Abort: слишком много ошибок}
      Halt;
    end;
  end;

  function ModifyRecord(P, POld : PersonDef; RefNr : LongInt) : Boolean;
  var
    KeyNr : Integer;
  begin
    ModifyRecord := False;
    if not CheckRecord(P, POld) then
      Exit;
    PutRec(PF, RefNr, P);
    if not IsamOK then begin
      {Обработка ошибки}
      Exit;
    end;
    for KeyNr := 1 to NrKeys do begin
      {Обновить модифицированные ключи}
      if CreateKey(P, KeyNr) <> CreateKey(POld, KeyNr) then begin
        DeleteKey(PF, KeyNr, RefNr, CreateKey(POld, KeyNr));
        if IsamOK then
          AddKey(PF, KeyNr, RefNr, CreateKey(P, KeyNr));
        if not IsamOK then begin
          UndoMod(P, POld, RefNr, KeyNr-1);
          {Обработка ошибки}
          Exit;
        end;
      end;
    end;
    ModifyRecord := True;
  end;

     Подпрограмма CheckRecord  проверит,  что  новая  запись,  Р,
генерирует допустимые ключи (т.е.  ее первичные ключи должны быть
непустыми). CheckRecord  также  проверит,  чтобы  новая  и старая
записи не были идентичными,  так как  при  этом  только  теряется
время.

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

 Переход к следующей или предыдущей записи данных
-------------------------------------------------

     NextPrevRecord показывает,   каким   образом   может    быть
реализована функция  для  сканирования  файла  данных  в  порядке
индексов. "Последовательный  указатель   доступа"   должен   быть
спозиционирован за  известным  ключом,  прежде чем NextPrevrecord
может быть вызвана в первый раз.  Это можно  сделать  при  помощи
любой из   функций,   ,   ,  ,
 или .

  function NextPrevRecord(var P : PersonDef;
                          var RefNr : LongInt;
                          KeyNr : Integer;
                          var Key : IsamKeyStr;
                          Next : Boolean) : Boolean;
  begin
    NextPrevRecord := False;
    if Next then begin
      NextKey(PF, KeyNr, RefNr, Key);
      if not IsamOK and (IsamError = 10250) then
        {Следующего ключа не было. Переход к первому ключу в файле}
        NextKey(PF, KeyNr, RefNr, Key);
    end else begin
      PrevKey(PF, KeyNr, RefNr, Key);
      if not IsamOK and (IsamError = 10260) then
        {Следующего ключа не было. Переход к последнему ключу в файле}
        PrevKey(PF, KeyNr, RefNr, Key);
    end;
    if not IsamOK then
      Exit;
    GetRec(PF, RefNr, P);
    if not IsamOK then begin
      {Обработка ошибки}
      Exit;
    end;
    NextPrevRecord := True;
  end;

Поиск записей данных
--------------------

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

  function FindRecord(var P : PersonDef;
                      var RefNr : LongInt;
                      KeyNr : Integer;
                      var Key : IsamKeyStr) : Boolean;
  begin
    FindRecord := False;
    SearchKey(PF, KeyNr, RefNr, Key);
    if not IsamOK then begin
     {Определение причины неудачного завершения SearchKey,например:
        IsamError = 10210 Не найдено ни заданного, ни большего ключей.
        IsamError = 10175 Параметр KeyNr содержит неверное число.
                          Это ошибка программирования, которая не
                          может встречаться в законченной программе.}
      Exit;
    end;
    GetRec(PF, RefNr, P);
    if not IsamOK then begin
      {Обработка ошибки}
      Exit;
    end;
    FindRecord := True;
  end;

     Подпрограмма абортируется,  если    имеет   значение
False после  вызова    из-за  того,  что запись данных
недоступна или произошла ошибка.  возвращает True даже
если соответствия  ключа найдено не было,  если при этом доступна
следующая запись,  с большим значением  ключа.  Фактический  ключ
возвращается в  вызывающую  программу  через  переменную-параметр
FindRecord, Key.  Если соответствия ключа не найдено, 
также возвращает  в  RefNr  относительный  номер  записи (адрес в
файле). По  этому  номеру    считывает  запись  данных  и
возвращает в Р.  Процедура  должна использоваться вместо
, если требуется точное соответствие ключей.

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

  function MatchedRecord(P, Q : PersonDef) : Boolean;
  begin
    {Возврат True, если P и Q соответствуют
     по некоторому критерию, например...}
    MatchedRecord := (StUpcase(P.City) = StUpcase(Q.City));
  end;

  function ScanForRecord(var P : PersonDef;
                         KeyNr : Integer;
                         var RefNr : LongInt) : Boolean;
  var
    Done : Boolean;
    Goal : PersonDef;
    Key : IsamKeyStr;
  begin
    ScanForRecord := False;
    Goal := P;
    Done := False;
    repeat
      NextKey(PF, KeyNr, RefNr, Key);
      if not IsamOK then
        {Возможно, достигнут наибольший ключ}
        Done := True
      else begin
        GetRec(PF, RefNr, P);
        if not IsamOK then begin
          {Обработка ошибки}
          Done := True;
        end else if MatchedRecord(P, Goal) then begin
          {Найдено соответствие}
          Done := True;
          ScanForRecord := True;
        end;
      end;
    until Done;
  end;

     В данном   примере   выполняется   поиск   записи,   которая
"соответствует" исходной записи,  переданной в параметре Р. Поиск
начинается с записи,  следующей за той,  что  связана  с  текущим
последовательным указателем,  и  продолжается до записи,  имеющей
наибольший ключ типа KeyNr. Подпрограмма MatchedRecord сравнивает
текущую запись  с  целью  поиска,  и  если  соответствие найдено,
ScanForRecord возвращает номер записи (в RefNo) и  ее  содержимое
(в Р).

     В этих  небольших  примерах  мы  представили наиболее важные
операции B-Tree Filer.  Эти подпрограммы были написано достаточно
просто, чтобы  дать  ясную иллюстрацию концепции.  Более обширные
примеры можно найти в демонстрационной  программе NETDEMO.

D. Управление файловым блоком
-----------------------------

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

     Для восстановления   прикладная   программа   или  отдельная
утилита должна вызывать процедуру    из  модуля
REBUILD. (См. раздел 8.С).

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

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

     - Используя  режим  сохранности  (для  этого  файловый  блок
должен быть открыт при помощи ).

     - Вызывая в нужное время .

     Использование      может     быть    также
желательным, когда из файлового блока было удалено много записей,
а ввод вместо них новых в ближайшем будущем не ожидается.

     Сетевые файловые  блоки  также  могут  быть реконструированы
этой процедурой.  Во время реконструкции доступ к файловому блоку
другим рабочим станциям не разрешен.

4. Идентификаторы B-Tree Filer
------------------------------

     Данная глава описывает  большинство  идентификаторов  модуля
FILER пакета  B-Tree  Filer.  Функции  и процедуры организованы в
алфавитном порядке.  Приложение  В  содержит  список  процедур  и
функций, организованный по их назначению.

     Некоторые идентификаторы здесь не описаны. Они предназначены
для внутреннего использования в  модуле  и  служат  для  связи  с
другими модулями,   поставляемыми   в   составе   B-Tree   Filer.
Подробности см. в исходном коде.

А. Константы
------------

     DatExtension = 'DAT';
     IxExtension = 'IX';
     DiaExtension = 'DIA';

     Расширения файлов данных, индексов и диалога, соответственно.

     MaxHeight = 8;

     Задает самый глубокий уровень В-дерева.

     MaxKeyLen = 30;

      содержит  максимально  допустимую глубину ключа.
Более длинные ключи усекаются до этого значения. Допустимая длина
лежит вообще  в  диапазоне  от  1  до  255  с умолчанием 30.  Эту
константу можно  модифицировать,  отредактировав  соответствующим
образом FILER.PAS и перекомпилировав модуль FILER.

     MaxNrOfKeys = 100;

      определяет   максимальное   число  ключей  для
одного файлового блока.  Допустимые значения лежат в диапазоне от
1  до 750,  с умолчанием 100.  Непосредственное увеличение данной
константы увеличит память, требуемую для хранения переменной типа
.     Эту     константу    можно    модифицировать,
отредактировав    соответствующим     образом     FILER.PAS     и
перекомпилировав модуль FILER.

     MaxNrOfWorkStations = 50;

      содержит  максимальное  число  рабочих
станций,  используемое в сети.  Обычно для типовой установки сети
достаточно значения 50,  хотя многие современные сети могут иметь
до 100 и более станций.  Допустимый диапазон имеет значения от  1
до  32767,  но  неоправданно  увеличивая  значение этой константы
повысит время доступа для всех сетевых  операций.  Эту  константу
можно   модифицировать,  отредактировав  соответствующим  образом
FILER.PAS и перекомпилировав модуль FILER.

     PageSize = 62;

     Задает максимальное число ключей на странице В-дерева. Более
подробная информация  об  этой  константе  находится  в  описании
. Значение  62  близко  к  оптимуму   характеристик
быстродействия файловых блоков на обычном жестком диске.

     SearchForSequentialDefault : Boolean = False;

     Состояние по   умолчанию   метода   поиска,  применяемого  в
операциях  и .  Этот  метод  полезен  для
восстановления из  состояния ошибки типа "последовательный доступ
не разрешен",  которое может возникнуть при модификации файлового
блока несколькими рабочими станциями.  Более подробную информацию
см. в описании  в Главе 7.

В. Типы
-------

     IsamFileBlockName = string[64];

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

     IsamKeyStr = string[MaxKeyLen];

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

     IsamFileBlockPtr = ^IsamFileBlock;

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

  IsamIndDescr = array[1..MaxNrOfKeys] of
    record
      KeyL : 1..MaxKeyLen;
      AllowDupK : Boolean;
    end;

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

     1. Первичные ключи:  AllowDupKey =  False.  Например,  номер
клиента, который    всегда    уникален.    В   пределах   данного
 может  быть  определено  более  одного  первичного
ключа. Помните,   что   B-Tree   Filer  не  допускает  добавления
дублирующихся первичных ключей при помощи .

     2. Вторичные ключи:  AllowDupK = True. Например, фамилия или
почтовый код,  которые  не обязательно уникальны.   будет
всегда добавлять вторичные ключи.  Она делает их уникальными   во
внутреннем представлении,  включая в качестве неявной части ключа
относительный номер (адрес) записи данных.

  NetSupportType = (NoNet, Novell, MsNet, MsNetMachName, CBISNet,
                    PCMOS386);

     Этот тип  описывает  текущую  активную  опцю поддержки сети.
Функция   возвращает  значение  данного  типа.  Для
однопользовательской версии   B-Tree  Filer  всегда  возвращается
значение NoNet ("Нет  сети").  В  противном  случае  возвращаемое
значение зависит  от  того,  как  был  компилирован модуль FILER.
Подробности см. в разделе 5.В.

С. Переменные
-------------

  IsamOK : Boolean;

     Данная переменная   устанавливается   каждой   подпрограммой
B-Tree Filer.  Если ее значение равно True,  то желаемая операция
была выполнена успешно. В противном случае переменная 
будет содержать код,  конкретизирующий  происшедшую  ошибку.  Для
того, чтобы  реализовать правильную обработку ошибок,  гарантируя
тем самым  надежность   прикладного   программного   обеспечения,
 следует   проверять  после  вызова  каждой  подпрограммы
B-Tree Filer.

  IsamError : Integer;

     Эта переменная устанавливается каждой  подпрограммой  B-Tree
Filer. При  удачном  завершении  операции эта переменная получает
нулевое значение;  в  противном  случае  она  получает  ненулевое
значение. Если  переменная    имеет  значение  False,  то
 соответствует типу происшедшей  ошибки. Классификация
ошибки верхнего  уровня  может  быть  получена посредством вызова
функции . Полный список кодов ошибок приводится в
Приложении А.

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

     Некоторые процедуры   и   функции   не   описаны   здесь   в
подробностях.  Они  используются  в основном для взаимодействия с
другими модулями B-Tree Filer,  такими как REORG и REBUILD.  Если
вы работаете с B-Tree Filer на нижнем уровне,  вы можете найти их
полезными для себя.  Более подробную информацию см. в их исходном
коде.

   procedure IsamAssign(var F : IsamFile; FName : IsamFileBlockName);
     { Присваивает имя DOS  переменной  типа IsamFile }

   procedure IsamBlockRead(var F : IsamFile; var Destination; Len : Word);
     { Читает  байтов из файла  начиная с текущей позиции указателя
       файла в  }

   procedure IsamBlockWrite(var F : IsamFile; var Source; Len : Word);
     { Записывает  байтов в файл  начиная с текущей позиции указателя
       файла из  }

   procedure IsamClose(var F : IsamFile);
     { Закрывает файл  }

   procedure IsamDelete(var F : IsamFile);
     { Удаляет неоткрытый файл  }

   function IsamExists(Name : IsamFileBlockName) : Boolean;
     { Проверяет существование файла DOS }

   function IsamForceExtension(Name, Ext : IsamFileBlockName) :
                                           IsamFileBlockName;
     { Возвращает маршрут  с заданным расширением }

   procedure IsamGetBlock(var F : IsamFile; Ref, Len : LongInt;
                          var Destination);
     { Читает  байтов из файла  начиная с позиции 
       в  }

   procedure IsamLongSeek(var F : IsamFile; Ref : LongInt);
     { Устанавливает указатель позиции файла  в адрес  }

   procedure IsamLongSeekEOF(var F : IsamFile);
     { Ищет конец файла  }

   procedure IsamPutBlock(var F : IsamFile; Ref, Len : LongInt;
                          var Source);
     { Записывает  байтов в файл  начиная с позиции 
       из  }

   procedure IsamRename(var F : IsamFile; FName : IsamFileBlockName);
     { Переименовывает неоткрытый файл  в  }

   procedure IsamReset(var F : IsamFile; Mode : Byte);
     { Открывает файл  в режиме доступа  }

   procedure IsamRewrite(var F : IsamFile);
     { Создает файл  (стирая любой существующий файл с этим именем }

     Ниже следуют подробные описания остальных подпрограмм:


AddKey
-----------------------------------------------------------------
Объявление
----------

     procedure AddKey(IFBPtr : IsamFileBlockPtr;
                      Key : Integer;
                      UserDatRef : LongInt;
                      UserKey : IsamKeyStr);

Параметры
---------

     IFBPtr        Указатель файлового блока
     Key           Номер ключа, как в параметре , передаваемом
                   в 
     UserDatRef    Номер записи данных, полученный из предыдущего
                   вызова 
     UserKey       Добавляемый ключ

Описание
--------

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

     Отметим, что все ключи должны иметь  форму  строки  символов.
Поставляемый модуль    NUMKEYS   обеспечивает   подпрограммы   для
преобразования всех числовых типов Turbo Pascal  в  форму  строки,
поддерживая правильную последовательность сортировки и минимизируя
длину строки.  NUMKEYS также  обеспечивает  функции  для  упаковки
ASCII-строк, создавая   ключи,  на  38%  короче.  Более  подробную
информацию см. в разделе 8.F.

Ошибки
------

     9900..9906   Ошибки операционной системы

     10003        (Только в режиме сохранности). Операция была
                  абортирована вследствие суровой ошибки ввода/
                  вывода. Реконструкция файловых блоков не нужна,
                  поскольку "ремонт" был выполнен успешно.

     10178        Параметр "Key" содержит неверный параметр.

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

Примечания
----------

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


AddRec
-----------------------------------------------------------------
Объявление
----------

     procedure AddRec(IFBPtr : IsamFileBlockPtr;
                      var RefNr : LongInt;
                      var Source);

Параметры
---------

     IFBPtr        Указатель файлового блока.
     RefNr         Позиция в файле данных, куда была записана запись
                   данных (относительный номер записи в файле);
                   используется для добавления индекса при помощи
                   .
     Source        Добавляемая запись данных.

Описание
--------

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

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

Ошибки
------

     9900..9906   Ошибки операционной системы

     10001        (Только в режиме сохранности). Операция была
                  абортирована вследствие суровой ошибки ввода/
                  вывода. Реконструкция файловых блоков не нужна,
                  поскольку "ремонт" был выполнен успешно.


ClearKey
-----------------------------------------------------------------
Объявление
----------

     procedure ClearKey(IFBPtr : IsamFileBlockPtr; Key : Integer);

Параметры
---------

     IFBPtr        Указатель файлового блока
     Key           Номер ключа, как в параметре , передаваемом
                   в 

Описание
--------

      сбрасывает   последовательный  указатель  ключа  с
номером .   Это   позволяет      возвратить   первый
(наименьший) ключ,  - последний (наибольший) ключ.

Ошибки
------

     10171       Параметр  содержит неверный номер.


CloseFileBlock
-----------------------------------------------------------------
Объявление
----------

     procedure CloseFileBlock(var IFBPtr : IsamFileBlockPtr);


Параметры
---------

     IFBPtr   Указатель закрываемого файлового блока.

Описание
--------

     Закрывает файловый   блок    и  освобождает  память,
выделенную ,                     или
.

Ошибки
------

     9900..9906   Ошибка операционной системы.
     10080        Файловый блок не был открыт.
     10160        Файловый блок не мог быть правильно закрыт.

Примечания
----------

     Этот вызов   важет  с  точки  зрения  сохранения  целостности
файлового блока.  Если  не вызывать,  то следующий
раз при   запуске   программы   может   понадобиться  пересоздание
индексного файла. Это очень важно при тестировании программы: если
программа сбивается,   когда   файлы   открыты  и  были  выполнены
индексные операции, то индексный файл должен быть регенерирован. B
-Tree Filer  реализует  процедуру  выхода  Turbo  Pascal,  которая
автоматически закрывает все открытые файловые блоки при завершении
программы, как  нормальном,  так  и  аварийном,  с ошибкой времени
выполнения. При "зависании" программы этого не происходит.

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


DatRecordSize
-----------------------------------------------------------------
Объявление
----------

     function DatRecordSize(IFBPtr :IsamFileBlockPtr) : LongInt;

Параметры
---------

     IFBPtr      Указатель файлового блока.
     Результат   Длина записи данных файлового блока .

Описание
--------

     Если запись данных должна быть добавлена при помощи ,
и   возвращает  ноль,    возвращает число
байтов, которое будет записано  на диск.


DeleteFileBlock
-----------------------------------------------------------------
Объявление
----------

     procedure DeleteFileBlock(FName : IsamFileBlockName);

Параметры
---------

     FName     Имя DOS, включающее необязательные имена дисковода и
               маршрута, но без расширения.

Описание
--------

     Удаляет все файлы DOS, принадлежащие файловому блоку с именем
, т.е.  все файлы с именем   и  расширением  '.DAT',
'.IX' и '.DIA'.

Ошибки
------

     9900..9906   Ошибки операционной системы.


DeleteKey
-----------------------------------------------------------------
Объявление
----------

     procedure DeleteKey(IFBPtr : IsamFileBlockPtr;
                      Key : Integer;
                      UserDatRef : LongInt;
                      UserKey : IsamKeyStr);

Параметры
---------

     IFBPtr        Указатель файлового блока
     Key           Номер ключа, как в параметре , передаваемом
                   в 
     UserDatRef    Номер записи данных, позволяющий различать вторичные
                   ключи. Для вторичного ключа этот параметр должен
                   быть корректным, а для первичного параметра
                   он игнорируется.
     UserKey       Удаляемый ключ

Описание
--------

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

Ошибки
------

     9900..9906   Ошибки операционной системы

     10004        (Только в режиме сохранности). Операция была
                  абортирована вследствие суровой ошибки ввода/
                  вывода. Реконструкция файловых блоков не нужна,
                  поскольку "ремонт" был выполнен успешно.

     10179        Параметр "Key" содержит неверный параметр.

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

Примечания
----------

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


DeleteRec
-----------------------------------------------------------------
Объявление
----------

     procedure DeleteRec(IFBPtr : IsamFileBlockPtr; RefNr : LongInt);

Параметры
---------

     IFBPtr        Указатель файлового блока.
     RefNr         Номер удаляемой записи.

Описание
--------

      удаляет из файла  запись  данных.  Запись  данных
фактически помечается  как  свободная,  что  позволяет последующим
вызовам  заполнять "пустоту".

Ошибки
------

     9900..9906   Ошибки операционной системы

     10002        (Только в режиме сохранности). Операция была
                  абортирована вследствие суровой ошибки ввода/
                  вывода. Реконструкция файловых блоков не нужна,
                  поскольку "ремонт" был выполнен успешно.

Примечания
----------

     Удалены могут   быть   только   существующие  записи  данных.
Удаление уже удаленной записи запортит внутренний  связный  список
удаленных записей   данных,   что   приведет   к   непредсказуемым
результатам. Когда  запись  удалена,  B-Tree  Filer  устанавливает
первые четыре  байта  записи  в  ненулевое  значение.  Если первые
четыре байта  каждой  записи   данных   резервируются   и   обычно
установлены в ноль, это позволит легко различить удаленные записи.


ExtendHandles
-----------------------------------------------------------------
Объявление
----------

     procedure ExtendHandles(NumHandles : Byte);

Параметры
---------

     NumHandles    Число допустимых логических номеров файлов.

Описание
--------

     Данная процедура увеличивает число логических номеров файлов,
доступных программе.  Она  использует   служебную   функцию   DOS,
существующую начиная  с  версии MS-DOS 3.3 и старше.  Поскольку по
умолчанию DOS  предоставляет  программе  20  логических   номеров,
минимальным имеющим  смысл  значением    является  21.
( в   случае,   если      меньше    21,
завершается, не  выполнив никаких действий.) Максимальным является
значение 255,  однако  собственная  ошибка  DOS   3.3   фактически
ограничивает это число до 254.

     Файл CONFIG.SYS    системы,    где   выполняется   прикладная
программа, должен также иметь параметр FILES=,  равный как минимум
значению .

     При вызове      распределяется  новая  таблица
логических номеров  файлов.  Требуемое  количество  памяти   равно
+47 байтов.  Чтобы  получить эту память,  подпрограмма
либо использует существующую свободную память  DOS,  либо  сжимает
область "кучи"  Turbo  Pascal,  чтобы  сделать доступной некоторое
количество памяти  DOS.  при  завершении  программы   эта   память
автоматически освобождается.

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

Ошибки
------

     10190   Поддерживается только DOS версии 3.3 и старше.
     10191   Недостаточная область памяти "кучи" или ошибка
             DOS SetBlock.
     10192   Невозможность получить больше логических номеров.

Примечания
----------

     DOS всегда  резервирует  первые  пять  логических номеров для
стандартных устройств.    Следовательно,     при     использовании
стандартной аблицы   логических   номеров   для  остальных  файлов
доступны только 15 номеров.  B-Tree Filer требуется два логических
номера для    каждого   однопользовательского   файлового   блока,
открытого в нормальном  режиме.  В  защищенном  режиме,  либо  при
открытии для  сетевого  доступа,  для файлового блока требуетсятри
логических номера файлов.

      использует   документированный   вызов   DOS,
поддерживаемый только  в  версиях  3.3  и  старше.  Для прикладных
программ, которые планируется использовать в более ранних версиях,
мы рекомендуем  публичный модуль EXTEND,  который можно получить у
различных поставщиков и  через  форум  BPROGA  CompuServe.  EXTEND
работает с  версиями  2.0  и  старше,  используя другие методы,  в
зависимости от версии  DOS.  Учтите,  однако,  что  многие  версии
Novell NetWare   содержат   программные   ошибки,  не  позволяющие
использовать EXTEND. Novell опубликовала способ обойти эти ошибки.
Прежде чем  использовать  EXTEND  в  локальной  сети  NetWare LAN,
обратитесь к последним версиям технической документации Novell.


FileLen
-----------------------------------------------------------------
Объявление
----------

     function FileLen(IFBPtr : IsamFileBlockPtr) : LongInt;

Параметры
---------

     IFBPtr     Указатель файлового блока.
     Результат  Общее число записей в файловом блоке.


Описание
--------

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

     Физическая длина файла данных может быть вычислена как

     DatRecordSize(IFBPtr) * FileLen(IFBPtr)

Ошибки
------

     9900..9906   Ошибка операционной системы.

Примечания
----------

     Эта подпрограмма    поставляется    главным    образом    для
совместимости с  DataBase Toolbox.  Для определения индивидуальных
компонентов общего    количества,     возвращенного     ,
используйте  и .


FindKey
-----------------------------------------------------------------
Объявление
----------

     procedure FindKey(IFBPtr : IsamFileBlockPtr;
                      Key : Integer;
                      var UserDatRef : LongInt;
                      UserKey : IsamKeyStr);

Параметры
---------

     IFBPtr        Указатель файлового блока
     Key           Номер ключа, как в параметре , передаваемом
                   в 
     UserDatRef    Номер записи данных, который в случае успешного
                   поиска используется в последующем вызове
                   .
     UserKey       Ключ поиска.

Описание
--------

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

Ошибки
------

     9900..9906   Ошибки операционной системы

     10174        Параметр "Key" содержит неверный параметр.

     10200        Ключ  не найден.

Примечания
----------

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


FindKeyAndRef
-----------------------------------------------------------------
Объявление
----------

     procedure FindKeyAndRef(IFBPtr : IsamFileBlockPtr;
                      Key : Integer;
                      var UserDatRef : LongInt;
                      var UserKey : IsamKeyStr
                      NotFoundSearchDirection : Integer);

Параметры
---------

     IFBPtr        Указатель файлового блока
     Key           Номер ключа, как в параметре , передаваемом
                   в 
     UserDatRef    Номер записи данных для ;
                   найденный номер возвращается через эту переменную.
     UserKey       Ключ поиска;
                   найденный ключ возвращается через эту переменную.
     NotFoundSearchDirection      Определяет, нужно ли и как
                   продолжать работу, если пара ключ/адрес записи
                   не найдена.

Описание
--------

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

Ошибки
------

     9900..9906   Ошибка операционной системы.
     10170        Параметр "Key" содержит неверный номер.
     10200        Ключ  не найден.
     10210        Ключ  не найден, и ключа с большим
                  значением не существует.
     10250        Большего ключа не существует.
     10255        Последовательный доступ не разрешен.
     10270        Ключ с таким адресом недоступен.

Примечания
----------

     Данная процедура не предназначена для возврата  адрес  записи
данных по конкретному ключу;  это вы уже должны были понять.  Она,
что более  важно,   позволяет   позиционировать   последовательный
указатель в   середине  блока  идентичных  вторичных  ключей.  Это
особенно полезно при экранном просмотре или создании списков.


FlushAllFileBlocks
-----------------------------------------------------------------
Объявление
----------

     procedure FlushAllFileBlocks;

Описание
--------

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

Ошибки
------

     9900..9906   Ошибка операционной системы

Примечания
----------

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


FlushFileBlock
-----------------------------------------------------------------
Объявление
----------

     procedure FlushFileBlock(IFBPtr : IsamFileBlockPtr);

Параметры
---------

     IFBPtr Указатель файлового блока,  данные из которого должны
быть сброшены на диск.

Описание
--------

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

Ошибки
------

     9900..9906   Ошибка операционной системы

Примечания
----------

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


ForceWritingMark
-----------------------------------------------------------------
Объявление
----------

     procedure ForceWritingMark(FWM : Boolean);

Параметры
---------

     FWM    Значение True форсирует запись метки; по умолчанию
            действует значение False.

Описание
--------

     B-Tree Filer организует небольшую область данных, хранимую в
начале файла  данных каждого файлового блока.  Когда B-Tree Filer
замечает, что в буфер памяти была записана  новая  информация  (в
PageStack или  буфер  DOS),  он  записывает  в эту область данных
флаговый байт, обозначающий, что "данные буферизованы". Этот флаг
остается установленным    до    вызова    ,   что
гарантирует сброс  на  диск  всех  буферов   данных.   Если   при
последующей попытке  открыть файловый блок обнаруживается,  что в
файле данных флаг установлен,  то этот вызов возвратит код ошибки
10010, означающий, что целостность индексного файла сомнительна.

     К сожалению, метка "данные буферизованы" сама может остаться
в буфере DOS,  и следовательно, данная проверка целостности может
оказаться неэффективной.  Это  в  конечном  итоге  подводит нас к
назначению .   Вызов        с
параметром , установленном в значение True, разрешает режим,
в котором метка записи немедленно  сбрасывается  сбрасывается  на
диск, как только она записана.


Примечания
----------

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


FreeRecs
-----------------------------------------------------------------
Объявление
----------

     function Freerecs(IFBPtr : IsamFileBlockPtr) : LongInt;

Параметры
---------

     IFBPtr      Указатель файлового блока.
     Результат   Число свободных записей данных.

Описание
--------

      возвращает число удаленных записей данных ("дыр")
в файловом  блоке  .  Физическая  длина   файла   данных
вычисляется как:

     DatRecordSize(IFBPtr)*(UsedRecs(IFBPtr)+FreeRecs(IFBPtr)+1)

Ошибки
------

     9900..9906   Ошибка операционной системы




GetPageStack
-----------------------------------------------------------------
Объявление
----------

     function GetPageStack(Free : LongInt) : Integer;


Параметры
---------

     Free       Минимальное число байтов свободной памяти,
                которое должно быть зарезервировано.

     Результат  IsamOK = True  : Число выделенных страниц.
                IsamOK = False : Число страниц, которое при данных
                                 условиях может быть выделено.

Описание
--------

     Выделяет область  "кучи"  для   буферов   В-дерева.   Данная
подпрограмма должна вызываться до любых других подпрограмм B-Tree
Filer, за исключением предназначенных для инициализации  сети.  В
частности, она    должна   быть   вызвана   до   ,
, либо связанных с ними подпрограмм.

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

      должна иметь возможность выделить  память как
минимум для    страниц.  Как показано ниже,  для этого
требуется как  минимум  20К  байт,  если  использовать   значения
констант по   умолчанию  из  модуля  FILER.  если  
определит, что такой объем памяти при условии,  что  байтов
останется доступными,   выделен  быть  не  может,  то  переменная
 будет  установлена  в  значение  False.  в  этом  случае
результат функции  будет  сообщать,  сколько страниц поместится в
имеющейся области памяти,  но само выделение памяти выполнено  не
будет. В  случае  неудачного завершения  может быть
выполнено одно из вух следующих действий:  может  быть  уменьшено
значение ,  и  функция  вызвана  повторно,  либо может быть
выдано сообщение об ошибке, а программа остановлена.

     При успешном     завершении           
устанавливается в  значение  True,  и  функция  возвращает  чмсло
выделенных страниц В-дерева. Это число страниц не требуется знать
для работы любых других подпрограмм B-Tree Filer:  оно сообщается
вам для информации.  Если  завершилась успешно,  то
больше она  вызываться  не должна,  если только не было выполнено
промежуточных обращений к .

     Итак, каким же  образом  правильно  выбрать  соответствующее
значение для   ?  Ответ  зависит  от  того,  каким  образом
прикладная программа  использует  "кучу".  Даже  если  прикладная
программа не  выполняет  выделение памяти "кучи" непосредственно,
прочие подпрограммы B-Tree Filer сами требуют  выделения  области
"кучи". Например,   вызов      (и   любой   другой
подпрограммы, открывающей файловый  блок)  использует  около  500
байтов области "кучи". Многие подпрограммы, организующие работу с
окнами (например,  подпрограммы  из  Turbo  Professional),  также
свободно используют "кучу".

     Если объем   области   "кучи",  нужный  программе,  известен
заранее,  как в случае использования "кучи" только подпрограммами
FILER,   то   в   параметре    следует  просто  задать  это
количество,  плюс некоторое добавочное количество,  для гарантии.
Например,  если программа будет открывать два файловых блока и не
будет использовать память "кучи" другими способами, то безопасным
значением  для   будет 2000 (два блока по 500 байтов,  плюс
1000 байтов для гарантии).  Тем  самым  вы  максимизируете  число
страничных буферов и обеспечите наилучшее быстродействие операций
с индексами.

     И напротив, может существовать прикладная программа, которая
сама широко  использует  "кучу",  например,  программа  обработки
текстов, хранящая в куче текст.  В этом случае вы можете захотеть
выделить для  страничных  буферов  В-дерева минимально допустимое
количество памяти "кучи",  а остальную часть "кучи" оставить  для
собственно прикладной  программы.  Соответствующее  выражение для
расчета  будет в таком случае иметь  вид  (MemAvail-20000).
Это значение   оставит   доступной   всю  память,  за  исключеним
минимума, необходимого   страничным   буферам.   Если   константы
В-дерева по   умолчанию  были  изменены,  то  нужно  использовать
приведенную нижу формулу,  позволяющую вычислить нужное  значение
между 20000.

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

     procedure ChoosePageStack;
     var
       FreeSpace : LongInt;
       Pages : Integer;
     begin
       { Сначала запрашивается половина кучи }
       FreeSpace := MemAvail div 2;

       { Цикл до успешного выполнения или неудачи }
       while FreeSpace > 0 do begin
         Pages := GetPageStack(FreeSpace);
         if IsamOK then
           { Успешное выделение памяти }
           Exit;
         { Уменьшим свободную память на произвольное значение }
         Dec(FreeSpace, 10000);
       end;

       { Если мы оказались здесь, значит для страничного стека
         памяти недостаточно }
       WriteLn('Недостаточно памяти');
       Halt;
     end;

Ошибки
------

     10000    Размер страничного стека меньше константы ,
              имеющей значение по умолчанию 8.

Примечания
----------

     Использование подпрограмм  B-Tree  Filer без первоначального
вызова данной функции приведет к непредсказуемым  результатам,  и
даже, возможно, к сбою операционной системы.

     Количество памяти,   выделяемой   в   ,  можно
вычислить как:

(Значение,возвращаемое )*(26+*(+9))

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

     Если требование к памяти является критичным,  то  вы  можете
пожелать уменьшить   константу    и  перекомпилировать
FILER.PAS. Если оставить   без  изменений,  то  получим
следующие оценки емкости В-дерева (максимальное число записей):

         Макс. записей
          8             2E14
          7             4E12
          6             6E10     <-- Все еще более 2^32 записей
          5             9E08
          4             1E07

     При = 4 минимальная память "кучи" для страничного
стека падает до 9776 байтов.


GetRec
-----------------------------------------------------------------
Объявление
----------

     procedure GetRec(IFBPtr : IsamFileBlockPtr;
                      RefNr : LongInt;
                      var Destination);

Параметры
---------

     IFBPtr        Указатель файлового блока
     RefNr         Номер читаемой записи
     Destination   Запись данных

Описание
--------

     Читает запись  данных  с  заданным номером .  
обычно получают при помощи предыдущей индексной операции.

Ошибки
------

     9900..9906   Ошибка операционной системы

Примечания
----------

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


InitIsam
-----------------------------------------------------------------
Объявление
----------

     procedure  InitIsam;

Описание
--------

     Данная процедура инициализирует все переменные B-Tree Filer.

Примечания
----------

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

IsamErrorClass
-----------------------------------------------------------------
Объявление
----------

     function IsamErrorClass : Integer;

Параметры
---------

 Результат 0 Нет ошибки.
           1 Диалоговое сообщение (например, поиск неудачен).
           2 Ошибка запирания (только в сетевой среде).
           3 Операция не выполнена (только в режиме сохранности).
           4 Суровая ошибка ввода/вывода (рекомендуется
             абортировать программу).
          99 Неизвестная ошибка.

Описание
--------

     Глобальная переменная  разделена на шесть классов
ошибок. Это обеспечивает менее детальный,  но более простой метод
классификации ошибок.


IsamErrorMessage
-----------------------------------------------------------------
Объявление
----------

     function IsamErrorMessage(ErrorNr : Integer) : String;

Параметры
---------

     ErrorNr    Код ошибки, по которому возвращается сообщение.
     Результат  Сообщение, соответствующее коду ошибки.

Описание
--------

     Возвращает английское сообщение  для  данного  кода  ошибки.
Значение, переданное   в  ,  обычно  представляет  собой
значение глобальной  переменной    после   того,   как
обнаружена ошибка ( равна False).

      не   включает   в   сообщение  имя  файла
соответствующего файлового  блока.  Это   должна   сделать   сама
прикладная программа.  Сообщения в общем соответствуют приводимым
в Приложении А.


KeyExists
-----------------------------------------------------------------
Объявление
----------

     function KeyExists (IFBPtr : IsamFileBlockPtr;
                         Key : Integer;
                         UserDatRef : LongInt;
                         UserKey : IsamKeyStr) : Boolean;

Параметры
---------

     IFBPtr        Указатель файлового блока
     Key           Номер ключа, как в параметре , передаваемом
                   в 
     UserDatRef    Номер записи данных, позволяющий различать
                   вторичные ключи. Этот параметр для вторичного
                   ключа обязательно должен быть задан правильно,
                   тогда как для первичного ключа он игнорируется.
     UserKey       Искомый ключ
     Результат     True, если искомый ключ существует, и False
                   в противном случае.

Описание
--------

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

Ошибки
------

     9900..9906   Ошибка операционной системы

     10176        Параметр  содержит неверный номер.

Примечания
----------

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


KeyRecordSize
-----------------------------------------------------------------
Объявление
----------

     function KeyRecordSize(IFBPtr : IsamFileBlockPtr) : LongInt;

Параметры
---------

     IFBPtr        Указатель файлового блока
     Результат     Размер индексной страницы (узла) В-дерева, включая
                   все ключи.

Описание
--------

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


MakeFileBlock
-----------------------------------------------------------------
Объявление
----------

     procedure  MakeFileBlock(var IFBPtr : IsamFileBlockPtr;
                              FName : IsamFileBlockName;
                              DatSLen : LongInt;
                              NumberOfKeys : Integer;
                              IID : IsamIndDescr);

Параметры
---------

     IFBPtr        Указатель файлового блока, используемый для
                   ссылки к файлам базы данных после их открытия.

     FName         Имя DOS, включая необязательные имена дисковода
                   или маршрута, но без расширения.

     DatSLen       Длина записи данных в байтах, т.е.
                   SizeOf(запись данных).

     NumberOfKeys  Число ключей данного файлового блока.

     IID           Описывает  различных ключей.
                   Более подробную информацию см. описание типа
                   .

Описание
--------

      создает  файлы  данных  и  индексов с именем
 и назначает их файловому блоку,  указываемому  .
 должно  быть  допустимым именем файла DOS,  которое может
включать необязательные имена дисковода  и/или  маршрута.  B-Tree
Filer автоматически    добавляет    к    именам   соответствующие
расширения: '.DAT' для файла данных и '.IX' для  файла  индексов,
заменяя ими  любые  расширения,  если  они  были  явно  заданы  в
. (Расширение,  добавляемые  файлам  по  умолчанию,  можно
изменить, модифицировав соответствующие константы в модуле FILER.
См. раздел А данной главы.) Любые существующие  файлы  с  тем  же
именем и расширением затираются без предупреждения!

     Параметр     содержит    размер    записи   данных.
Рекомендуется, чтобы каждое определение записи  данных начиналось
полем типа LongInt, резервируемым для внутреннего использования B
-Tree Filer.  Прикладная программа  должна  инициализировать  это
поле нулем.   B-Tree   Filer   будет  записывать  туда  ненулевые
значения, помечая записи нак свободные  при  выполнении  операции
. Эти  значения  служат  для идентификации достоверных
(неудаленных) записей во время  перепостроения  файлового  блока,
если будет  поврежден  индекс.  Они  позволяют  использовать файл
данных без ссылок к индексному файлу.  В противном случае  запись
данных рассматривается    как    нетипированный    параметр,    а
пользователь сам отвечает за его содержимое.

     Структура индексного файла  определяется  параметром  .
Обычно параметр      должен   быть  объявлен  как  локальная
переменная и  инициализироваться  непосредственно  перед  вызовом
. Более   подробную   информацию   см.  в  Примере
программирования в  разделе  3.С,  а  также  в  определении  типа
 в данной главе.

      выделяет ((+1)*(32+5*))
+248 байтов  "кучи".  При  вызове     не   забудьте
зарезервировать как минимум это количество памяти "кучи".

Ошибки
------

     9900..9906   Ошибка операционной системы

     10020        Длина записи данных меньше 21 или больше
                  2,147,483,647 байтов.

     10040        Недостаточно памяти для создания поля дескриптора
                  файлового блока.

     10055        Ключ был объявлен длиннее .

     10100        Недостаточно памяти для создания файлового блока.

Примечания
----------

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

MinimumDatKeys
-----------------------------------------------------------------
Объявление
----------

     function MinimumDatKeys(IFBPtr : IsamFileBlockPtr;
                             Space : LongInt) : LongInt;

Параметры
---------

     IFBPtr        Указатель файлового блока

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

Описание
--------

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

Примечания
----------

     Если должно  быть  записано  большее  число записей данных и
ключей, чем число,  возвращаемое ,  то проверить,
можно ли   это   сделать  безопасным  образом,  можно  с  помощью
 и .


NextDiffKey
-----------------------------------------------------------------
Объявление
----------

     procedure NextDiffKey(IFBPtr : IsamFileBlockPtr;
                           Key : Integer;
                           var UserDatRef : LongInt;
                           var UserKey : IsamKeyStr);


Параметры
---------

     IFBPtr        Указатель файлового блока

     Key           Номер ключа, как в параметре , передаваемом
                   в 

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

     UserKey       Ключ для сравнения; через этот параметр возвращается
                   первый ключ, больший данного.

Описание
--------

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


Ошибки
------

     9900..9906   Ошибка операционной системы

     10177        Параметр  содержит неверный номер.

     10240        Ключа, большего, чем данный, не существует.

Примечания
----------

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


NextKey
-----------------------------------------------------------------
Объявление
----------

     procedure NextKey(IFBPtr : IsamFileBlockPtr;
                       Key : Integer;
                       var UserDatRef : LongInt;
                       var UserKey : IsamKeyStr);


Параметры
---------

     IFBPtr        Указатель файлового блока

     Key           Номер ключа, как в параметре , передаваемом
                   в 

     UserDatRef    Номер записи данных, который будет использован в
                   последующем вызове  при успешном поиске
                   при помощи .

     UserKey       Через этот параметр возвращается следующий ключ.

Описание
--------

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

Ошибки
------

     9900..9906   Ошибка операционной системы

     10172        Параметр  содержит неверный номер.

     10250        Большего ключа не существует.

     10255        Последовательный доступ не разрешен.

Примечания
----------

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


OpenFileBlock
-----------------------------------------------------------------
Объявление
----------

     procedure OpenFileBlock(var IFBPtr : IsamFileBlockPtr;
                             FName :IsamFileBlockName);

Параметры
---------

     IFBPtr   Указатель файлового блока, используемый для ссылки к
              файлам базы данных после их открытия.

     FName    Имя DOS, включая необязательные имена дисковода
              или маршрута, но без расширения.

Описание
--------

     Открывает существующую   пару   файлов   данных/индексов   и
назначает их файловому блоку, указываемому ,
                  или произошла ошибка чтения, не распознанная
                  операционной системой.

     10100        Недостаточно памяти для создания файлового блока.

     10180        Попытка "ремонта" файлового блока не удалась.
                  Требуется отдельная реконструкция.

Примечания
----------

     Обычно для  требуется несколько  сотен байтов
"кучи". Гарантируйте  резервирование  этого количества при вызове
. Точную  формулу  для  расчета  требуемой  области
"кучи" см. в описании .


OpenSaveFileBlock
-----------------------------------------------------------------
Объявление
----------

     procedure OpenSaveFileBlock(var IFBPtr : IsamFileBlockPtr;
                                 FName :IsamFileBlockName);

Параметры
---------

     IFBPtr   Указатель файлового блока, используемый для ссылки к
              файлам базы данных после их открытия.

     FName    Имя DOS, включая необязательные имена дисковода
              или маршрута, но без расширения.

Описание
--------

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

Ошибки
------

     9900..9906   Ошибка операционной системы

     10010        Индексный файл не был правильно закрыт в последнем
                  сеансе (См. раздел 3.D, "Управление файловым
                  блоком").

     10030        Недостаточно памяти для создания поля дескриптора
                  файлового блока.

     10060        Вычисленное число ключей превышает ,
                  или произошла ошибка чтения, не распознанная
                  операционной системой.

     10100        Недостаточно памяти для создания файлового блока.

     10180        Попытка "ремонта" файлового блока не удалась.
                  Требуется отдельная реконструкция.

Примечания
----------

     Данный метод открытия файлового блока в частности  полезен в
комбинации с  сетевой  опцией B-Tree Net.  В однопользовательской
среде как  правило  достаточно  вызывать    после
, ,    или    (или любой их
последовательности, чтобы гарантировать целостность данных.

     Обычно для    требуется  несколько  сотен
байтов  "кучи".  Гарантируйте резервирование этого количества при
вызове  .  Точную  формулу  для  расчета  требуемой
области "кучи" см. в описании .


PrevDiffKey
-----------------------------------------------------------------
Объявление
----------

     procedure PrevDiffKey(IFBPtr : IsamFileBlockPtr;
                           Key : Integer;
                           var UserDatRef : LongInt;
                           var UserKey : IsamKeyStr);


Параметры
---------

     IFBPtr        Указатель файлового блока

     Key           Номер ключа, как в параметре , передаваемом
                   в 

     UserDatRef    Номер записи данных, который будет использован в
                   последующем вызове  при успешном поиске
                   при помощи .

     UserKey       Предшествующий ключ.

Описание
--------

      ищет  в  индексном  файле  следующий  ключ  до
,   отличный   от  него.  Соответствующий  номер  записи
возвращается  в  ,  а  отличный  ключ  в   .
  завершается  неудачно  только  если  такой ключ не
существует ( меньше или равен наименьшему ключу).


Ошибки
------

     9900..9906   Ошибка операционной системы

     10177        Параметр  содержит неверный номер.

     10245        Ключа, меньшего, чем данный, не существует.

Примечания
----------

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


PrevKey
-----------------------------------------------------------------
Объявление
----------

     procedure PrevKey(IFBPtr : IsamFileBlockPtr;
                       Key : Integer;
                       var UserDatRef : LongInt;
                       var UserKey : IsamKeyStr);


Параметры
---------

     IFBPtr        Указатель файлового блока

     Key           Номер ключа, как в параметре , передаваемом
                   в 

     UserDatRef    Номер записи данных, который будет использован в
                   последующем вызове  при успешном поиске
                   при помощи .

     UserKey       Через этот параметр возвращается предшествующий
                   ключ.

Описание
--------

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

Ошибки
------

     9900..9906   Ошибка операционной системы

     10173        Параметр  содержит неверный номер.

     10260        Предшествующего ключа не существует.

     10265        Последовательный доступ не разрешен.

Примечания
----------

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


PutRec
-----------------------------------------------------------------
Объявление
----------

     procedure PutRec(IFBPtr : IsamFileBlockPtr;
                      RefNr : LongInt;
                      var Souece);

Параметры
---------

     IFBPtr        Указатель файлового блока

     RefNr         Номер записываемой записи данных.

     Source        Запись данных.


Описание
--------

     Записывает запись   данных   назад,    по    ее    исходному
относительному номеру   в   файле   данных,   например  после  ее
модификации.  был получен предыдущей индексной операцией.

Ошибки
------

     9900..9906   Ошибка операционной системы

Примечания
----------

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


ReleasePageStack
-----------------------------------------------------------------
Объявление
----------

     procedure ReleasePageStack;

Описание
--------

     ReleasePageStack освобождает  память,  выделенную при помощи
.

Примечания
----------

     Перед вызовом  данной  процедуры  все  файловые блоки должны
быть закрыты.  Использование B-Tree Filer  после  этой  процедуры
ведет к непредсказуемым результаты, не исключая сбой операционной
системы.


SearchKey
-----------------------------------------------------------------
Объявление
----------

     procedure SearchKey(IFBPtr : IsamFileBlockPtr;
                         Key : Integer;
                         var UserDatRef : LongInt;
                         UserKey : IsamKeyStr);

Параметры
---------

     IFBPtr        Указатель файлового блока

     Key           Номер ключа, как в параметре , передаваемом
                   в 

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

     UserKey       Ключ поиска; через этот параметр будет возвращен
                   найденный соответствующий ключ.

Описание
--------

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

Ошибки
------

     9900..9906   Ошибки операционной системы

     10175        Параметр "Key" содержит неверный параметр.

     10210        Ключ  не найден, и большег ключа не
                  существует.

Примечания
----------

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


SearchKeyAndRef
-----------------------------------------------------------------
Объявление
----------

     procedure SearchKeyAndRef(IFBPtr : IsamFileBlockPtr;
                               Key : Integer;
                               var UserDatRef : LongInt;
                               var UserKey : IsamKeyStr);

Параметры
---------

     IFBPtr        Указатель файлового блока

     Key           Номер ключа, как в параметре , передаваемом
                   в 

     UserDatRef    Номер записи данных для ;
                   найденный номер возвращается через эту переменную.

     UserKey       Ключ поиска;
                   найденный ключ возвращается через эту переменную.

Описание
--------

     В индексном    файле    ищется   ключ   ,   которому
соответствует номер записи  .  Если  ключ  найден,  то
последовательный  указатель устанавливается на этот элемент.  Если
же он не найден,  ищется "ближайший" ключ, сканированием сперва в
прямом, а   затем   в   обратном   направлении.   В    и
 будут   возвращены    "соответствующие    заданному"
значения.

Ошибки
------

     9900..9906   Ошибка операционной системы.

     10169        Параметр "Key" содержит неверный номер.

     10255        Последовательный доступ не разрешен.

Примечания
----------

     Данная процедура не предназначена для возврата  адрес  записи
данных по конкретному ключу;  это вы уже должны были понять.  Она,
что более  важно,   позволяет   позиционировать   последовательный
указатель в   середине  блока  идентичных  вторичных  ключей.  Это
особенно полезно при экранном просмотре или создании списков.


UsedRecs
-----------------------------------------------------------------
Объявление
----------

     function UsedRecs(IFBPtr : IsamFileBlockPtr) : LongInt;

Параметры
---------

     IFBPtr        Указатель файлового блока

     Результат     Число используемых записей данных.

Описание
--------

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

     DatRecordSize(IFBPtr)*(UsedRecs(IFBPtr)+FreeRecs(IFBPtr)+1)




5. Введение в B-Tree Net
------------------------

     B-Tree Net  представляет собой надстройку над подпрограммами
BTree Filer,  в которой добавлены средства  многопользовательской
сетевой базы  данных.  Почти для каждой подпрограммы B-Tree Filer
существует заменяющая  ее  подпрограмма  сетевой   версии.   Если
соответствующей сетевой  версии  подпрограммы  не существует,  то
можно использовать,  как и раньше подпрограмму B-Tree Filer. Даже
если вы  не  купили  сетевую  версию  B-Tree  Filer,  вы  сможете
использовать все  подпрограммы,  описанные   в   данном   разделе
руководства, но  только  в  режиме "NoNet" (режим эмуляции сети).
Вызывая многопользовательские    версии    подпрограмм     вместо
однопользовательских, вы сэкономите усилия,  которые впоследствие
могут понадобиться для  перевода  вашей  прикладной  программы  в
сетевую среду.

     Свойства баз  данных,  создаваемых  B-Tree  Net,  аналогичны
свойствам однопользовательской  версии.  Например,   максимальное
число записей  и  индексных  полей на один файловый блок остается
неизменным. Прикладные программы используют (в операторе USE) тот
же самый  блок,  FILER,  для  обращения  к сетевым подпрограммам.
Подпрограммы B-Tree  Net  также  работают  во  многом  аналогично
подпрограммам однопользовательской версии.  В частности, механизм
сообщений об ошибках (через переменные  и ), а
также коды ошибок остаются без изменений.

     Отметим, что   из   одной  прикладной  программы  фактически
возмлжен доступ как к локальным,  так  и  сетевым  базам  данных.
Затраты ресурсов  не-сетевыми  подпрограммами B-Tree Filer всегда
несколько ниже,  чем  для  аналогичных  сетевых  версий.  Сетевые
подпрограммы называются   так  же,  как  их  однопользовательские
аналоги, но включают  в  имя  слог  "Net".  Ниже  приводится  ряд
примеров соответствия имен. Полный их список см. в Главе 7.

     Однопользовательская     Многопользовательская
          версия                    версия
     --------------------     ---------------------
     MakeFileBlock            MakeNetFileBlock
     FindKey                  FindNetKey
     NextKey                  NextNetKey
     GetRec                   GetNetRec
     AddKey                   AddNetKey


A. Требования к системе
-----------------------

     Требования к системе  для  B-Tree  Net  те  же,  что  и  для
однопользовательской версии,   но   с  добавлением  требований  к
наличию совместимой сети.  (Однако,  сама сеть уже  может  внести
требования, например, к наличию старших версий DOS, например 3.1,
чего не требуется собственно для B-Tree Filer.

     С фундаментальной точки  зрения,  сеть  нуждается  только  в
одном средстве,    "запирания    физической    записи".   Однако,
практически говоря,  существует три сетевых средства,  от которых
зависит B-Tree Net:

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

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

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

     Третье требование   легко   моделируется   с  использованием
программных средств,  так  что  оно  практически  не  накладывает
дополнительных требований   к   сети.   однако,   если   сеть  не
обеспечивает это  требование,  код  прикладной  программы   может
получиться несколько  более  сложным,  как описано в разделе 5.С,
"Номера рабочих  станций".   B-Tree   Net   не   чувствителен   к
транспортному механизму сети (например,  Ethernet или Arcnet), за
исключеним тех  аспектов  этого  вопроса,   которые   влияют   на
возможности идентифицирования рабочих станций.

     В B-Tree   Net  мы  обеспечиваем  интерфейс  с  большинством
существующих сетей:  в частности,  с Novell,  а  также  со  всеми
сетями, в которых поддерживается вызов DOS для запирания записей.
Кроме того,  легко  написать  подпрограммы   сетевой   поддержки,
которые бы   обеспечили   бы  интерфейс  B-Tree  Net  с  другими,
несовместимыми с описанными, сетями.

В. Задание сети
---------------

     Директива условного определения в BTDEFINE.INC задает, какая
сеть будет поддерживаться модулем FILER.  Поскольку по  умолчанию
определяется значение "NoNet",  то прежде чем пытаться работать с
реальной сетью,  вы должны найти строку "{DEFINE" в BTDEFINE.INC,
модифицировать следующий  за  ним идентификатор и рекомпилировать
модуль. Инструкции  по  разархивированию  исходных  кодов  B-Tree
Filer см. в Главе 1.

     В настоящее  время поддерживаются следующие определения. См.
файл READ.ME, где могут находиться дополнения к этому списку.

     NoNet
     Novell
     MsNet
     MsNetMachName
     CBISNet
     PCMOS386
     DynamicNet

     Ниже приводятся   более   подробные   описания   каждой   из
поддерживаемых сетевых опций.

     NoNet
     -----

     Выполняет "режим эмулируемой сети" на отдельной машине. Сете
-ориентированные вызовы  при  этом не выполняют никаких действий,
но возвращаются успешно.  Вызовы  В-дерева  просто  передаются  в
соответствующие однопользовательские    подпрограммы.   Код   для
эмулированной сети  расположен  в  исходном  файле  DNETISAM.INC,
поставляемом как     с     однопользовательской,    так    и    с
многопользовательской версиями B-Tree Filer.

     Novell
     ------

     Работает на всех сетях,  совместимых с Novell NetWare.  Сюда
входят системы NetWare, Advanced NetWare и ELS (Entry Level). Для
оптимизации быстродействия использует механизм запирания записей,
принятый Novell.  Novell-ориентированный  код  (вместе  с   кодом
сетевого доступа  нижнего  уровня  для всех поддерживаемых сетей)
находится в исходном файле ISNETSUP.INC.

     MsNet
     -----

     Работает на  любой  сети,  совместимой с вызовами запирания,
принятыми Microsoft, которые впервые были реализованы в программе
SHARE, поставляемой  в  MS-DOS 3.1.  Использует вызов функции DOS
5Ch для  запирания  записи.  Поскольку  Microsoft  не  определяет
всеобхий механизм идентификации рабочих станций,  это определение
не может автоматически поддерживать распознавание  номера рабочей
станции. Дополнительную  информацию см.  ниже,  в разделе "Номера
рабочих станций".

     Большинство современных сетей  (включая  Novell)  предлагают
поддержку запирания записей типа Microsoft,  поэтому MsNet хорошо
задавать, когда вы не уверены, какую именно директиву определения
нужно использовать в вашей ситуации.  Однако,  если у вас имеется
сеть, реализующую как запирание  записей  DOS,  так  и  поддержку
NetBios, вероятно,  что  она  также  обеспечивает поддержку имени
машины. Дополнительную  информацию  об  этом   см.   в   описании
MsNetMachName, ниже.

     MsNetMachName
     -------------

     Обеспечивает подпрограммы,  идентичные подпрограммам Ms-Net,
за одним   исключением.   Идентификация   рабочей  станции  здесь
выполняется через   вызов   функции   DOS   5h,    поддерживаемый
большинством эмуляторов   NetBios.   В   частности,   вы   должны
использовать это определение для сетей 3Com,  PC-NET, MS-NET и PC
LAN. Однако,  см.  дополнительную  информацию  в  разделе "Номера
рабочих станций", ниже.

     CBISNet
     -------

     Поддерживает систему  CBIS Network-OS.  Это прямое сочетание
MsNet и Novell,  т.к. здесь используются вызовы DOS для запирания
и подпрограмма идентификации рабочей станции Novell.

     PCMOS386
     --------

     Поддерживает операционную систему PC-MOS/386 (версии  2.01 и
старше) в  многопользовательской  среде.  И снова,  для запирания
записей используются  вызовы,  совместимые  с  MS-DOS  SHARE,   а
идентификация рабочей  станции  реализовано методом,  специфичным
для PC-MOS/386. Номер рабочей станции равен "номеру задачи", плюс
единица. Поскольку PC-MOS/386 имеет по умолчанию большие величины
для счетчика повторных попыток и  задержки,  паузы  на  обработку
ошибок обращения к запертому ресурсу очень заметны.  Возможно, вы
захотите уменьшить эти задержки, вставив в код следующий фрагмент:

     if not SetDosRetry(1, 1) then
       { Обработка ошибки } ;

     DynamicNet
     ----------

     Позволяет прикладной программе выбрать любой  из приведенных
выше сетевых   методов  прямо  во  время  выполнения.  Прикладная
программа сама отвечает за определение типа сети,  на которой она
работает. (См.  Главу  9,  "Сетевые утилиты",  где приводится ряд
подпрограмм для идентификации сети). Определение опции DynamicNet
приводит к  подключению  кода  для  всех  сетей,  что увеличивает
размер кода и данных программы.  Однако, эти издержки меньше, чем
может показаться, поскольку у сетей много общего между собой.

     Опция DynamicNet    используется    как   и   любое   другое
определение, с  одним  добавлением.  При  определении  DynamicNet
модуль FILER   экспортирует   одну   дополнительную  типированную
константу, ,  которая задает  сетевую  опцию  для
использования в текущем сеансе.  Прикладная программа, прежде чем
вызвать ,  должна  установить      в
соответствующее значение.  Детали о  см.  в Главе
7.

С. Номера рабочих станций
-------------------------

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

     Ниже приводится несколько подходов к определению уникального
номера рабочей станции:

     1. Чтение его непосредственно через сервисные средства сети.

     2. Конструирование его  из  сетевого  имени  каждой  рабочей
станции. (Сетевые   имена   существуют   в   большинстве   сетей,
поддерживающих протокол NetBios).

     3. Кодирование  номера  каждой  рабочей  станции  в   копии,
работающей на данной станции.

     4. Чтение  номера  из  переменной  среды  DOS каждой рабочей
станции.

     5. Получение номера из командной строки DOS.

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

     В этом  разделе  рассматриваются   все   возможные   решения
проблемы.

     Модуль FILER   работает   с   двумя   переменными,  имеющими
отношение к настоящей дискуссии.  - это переменная типа
Integer, хранящая    номер,    присвоенный    рабочей    станции.
 -  это  переменная  типа  Integer,  хранящая   число
рабочих станций,  подключенных  в сеть.  FILER также обеспечивает
процедуру, ,   которая   должна    вызываться    для
инициализации B-Tree  Net  для  сетевого  доступа.  
вычисляет   и   ,   когда   это   возможно,
автоматически, а  в  противном  случае проверяет их правильность.
Она также  подготавлтвает  сеть  к   работе   данной   прикладной
программы, инсталлируя соответствующие обработчики ошибок, обычно
подпрограммы для обработки прерывания 24h (критическая ошибка).

      устанавливается  инициализирующим  кодом   модуля
FILER в -1.  Если это значение не было изменено, то 
вернет  со значением 10310.  Следовательно,  в  случае
сетей, которые  не могут автоматически обеспечивать номер рабочей
станции, прикладная программа должна перед  вызовом 
вычислить значение .

      не имеет такого большого значения.  Ее значение
не может   быть   определено    автоматически.    FILER    просто
устанавливает его  в  значение ,  константы,
имеющей по умолчанию значение 50. Это значение управляет размером
таблицы запираний  B-Tree  Net - если таблица слишком велика,  от
этого страдают быстродействие  и  использование  ресурсов  B-Tree
Net, однако   в  пределах  разумного  данное  значение  не  имеет
критического значения.

     Первый подход  -  чтение  номера   рабочей   станции   через
сервисные средства  сети,- является,  очевидно,  идеальным.  Сети
Novell и PC-MOS/386 обеспечивают такие  сервисные  средства.  При
выборе любой  из  этих  сетей  прочие  методы,  рассматриваемые в
данном разделе,  не нужны.  B-Tree Net  вызывает  соответствующие
подпрограммы автоматически.

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

     function WSNrFromName(WSName : string) : Integer;
     var
       N : Integer;
       I : Byte;
     begin
       N := 0;
       for I := 0 to Length(WSName) do
         Inc(N, Byte(WSName[I]));
       WSNrFromName := (N mod MaxNrOfWorkStations) + 1;
     end;

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

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

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

     SET FILERWSNR=001

     Модуль DOS,  поставляемый с Turbo Pascal  5.0,  экспортирует
подпрограмму, позволяющую    читать    строки    среды.    С   ее
использованием мы  можем  сконструировать  подпрограмму,  которая
могла бы строить номер рабочей станции, следующим образом:

     function WSNrFromEnvironment : Integer;
     var
       N : Integer;
       Code : Word;
       S : String;
     begin
       S := GetEnv('FILERWSNR');
       If Length(S) = 0 then
         { Строка среды не была найдена }
         WSNrFromEnvironment := -1;
       else begin
         { Преобразование строки в число }
         Val(S, N, Code);
         if Code <> 0 then
           { Строка среды не содержала правильное число }
           WSNrFromEnvironment := -1;
         else
           WSNrFromEnvironment := N;
       end;
     end;

     Возвращаемое значение -1 действует как сообщение об ошибке.

     Пятая альтернатива - требование,  чтобы  пользователь  задал
номер как  параметр  командной строки,- также работоспособна,  но
тут от пользователя требуются лишние с его точки зрения действия.
Реализация данной   альтернативы   прямолинейна.   Детали  см.  в
листинге NETDEMO.PAS,  где используется этот метод.  Здесь важно,
чтобы прикладная программа проверяла , гарантируя, что
пользователь ввел свой номер.

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

     procedure WSNrLogIn(FName : IsamFileBlockName);

     Рассмотрим суть метода.  В разделяемой директории выбирается
файл, хранящий журнал рабочей станции.  (Это  может  быть  та  же
самая директория,  в  которой  находятся сами файлы базы данных).
Когда регистрируется первая рабочая станция,  этот  файл  еще  не
существует, и  подпрограмма  создает файл и записывает
туда   байтов,  инициализированных   нулями.
Затем она  назначент  номер  первой  рабочей  станции,  записывая
единицу в первый байт файлов. Когда регистрируется вторая рабочая
станция, она  находит  этот файл и берет себе следующий доступный
номер, помечая соответствующий байт в  файле-журнале  регистрации
единицей. Номер  рабочей  станции  присваивается  непосредственно
переменной B-Tree Net .  Разумеется,  все эти  операции
выполняются с   одновременным   запиранием  файла  и  повторением
попыток доступа  к  запертому  файлу,  что   позволяет   избежать
конфликтов между рабочими станциями.

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


D. Сетевой интерфейс
--------------------

     Исходный код всего сетевого  интерфейса  находится  в  файле
ISNETSUP.INC. Активный интерфейс определяется во время компиляции
условной директивой определения компиляции  в  BTDEFINE.INC.  Для
добавления интерфейса с новой сетью выполните три шага:

     1. Выберите неиспользуемое имя, например "MyNet".

     2. Замените верхнюю директиву BTDEFINE.INC на {$DEFINE MyNet}.

     3. Добавьте    имя    новой    сети   в   перечислимый   тип
, который находится в FILER.PAS.

     4. Отредактируйте   NETISAM.INC   и   найдите   подпрограмму
. Добавьте оператор вида:

     {$IFDEF MyNet}
      NetSupported := MyNet;
     {$ENDIF}

     5. Отредактируйте  ISNETSUP.INC,  добавив  туда подпрограммы
сетевого интерфейса.  Поместите  их  между   {$IFDEF   MyNet}   и
{$ENDIF}. Примеры см. в существующих подпрограммах.

     Каждый сетевой  интерфейс  должен  экспортировать  следующие
идентификаторы:

     function IsamLockRecord(Start, Len : LongInt; Handle : Word) :
                             Boolean;

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

     function IsamUnLockRecord(Start, Len : LongInt; Handle : Word) :
                             Boolean;

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

     function IsamChangeAttrToShearable(var  F : IsamFile) : Boolean;

     Данная функция пытается сделать  "разделяемым".
При  успешном  завершении подпрограмма должна возвращать True,  и
False в противном случае.  Она также должна возвращать True, если
файловый  аттрибут "Shearable" ("Разделяемый") недоступен в сети.
В   ранее   рассмотренных   сетях   только   Novell    определяет
"разделяемый"  аттрибут  в  употребляемом  здесь смысле.  (Novell
требует, чтобы файл был явно отмечен как разделяемый, чтобы более
одной рабочей станции имело возможность доступа к нему; напротив,
DOS открывает файлы в режиме разделения по умолчанию.)

     function IsamInitNet(NetExpected : Boolean) : Boolean;

     Данная процедура должна присваивать  значения    и
, которые   являются   глобальными  переменнами  типа
Integer, объявленными в модуле FILER.   должна  иметь
одинаковое значение  на всех машинах сети и лежать в диапазоне от
1 до ,  включительно.  должна быть
другой для  каждой рабочей станции и должна лежать в диапазоне от
1 до .

      используется для управления  режимом  эмуляции
сети B-Tree Net.  Когда ее значение равно False,  B-Tree Filer не
будет выполнять  обращений  к  сети.  Этот  режим   полезен   при
тестировании программ,     при    отключенной    сети.    Функция
 должна  иметь  следующий   вид,   чтобы   правильно
обрабатывать параметр :

     function IsamInitNet(NetExpected : Boolean) : Boolean;
     begin
       if not NetExpected then begin
         IsamNetRequested := False;
         IsamNrOfWS := 0;
         IsamWSNr := 0;
         IsamInitNet := true;
       end else begin
         IsamNetRequested := True;
         { Определить числа рабочих станций, IsamNrOfWS.
           Обеспечить, что 1 <= IsamNrOfWS <= MaxNrOfWorkStations.
           Определить уникальный номер рабочей станции, IsamWSNr.
           Обеспечить, что 1 <= IsamWSNr <= IsamNrOfWS.
           Инициализировать сеть, если необходимо.
           Установить обработчик ошибок (прерывания int 24h),
              если необходимо.
           Возвратить значение True функции IsamInitNet,
              только если все операции прошли успешно.
         }
       end;
     end;

     Как показано,   данная   функция   должна   выполнять  любую
необходимую инициализацию сети.  Например,  в  случае  Novell  мы
должны отменить вывод сообщений об ошибках на экран. Для MsNet мы
должны установить обработчик критических ошибок (int  24h), чтобы
обнаруживать попытки доступа к запертым областям файла.

     Если ваша   сеть  требует  наличие  обработчика  критических
ошибок, то вы,  вероятно, захотите использовать в качестве модели
обработчик, находящийся   в   ISNETSUP.INC.   Обработчик   должен
устанавливать существующую      переменную      типа      Boolean
 в  значение  True,  когда  обнаруживается попытка
доступа к запертому файлу,  и возвращаться в DOS с  установленным
кодом "сбоя" (AL=3).

     Хотя Turbo  Pascal  4.0  и 5.0 имеют собственные обработчики
критических ошибок,  они неадекватны с точки зрения задач  B-Tree
Net. Обработчик   B-Tree   Net  должен  не  только  устанавливать
глобальный флаг,  когда произошла ошибка,  но и вызвать сервисную
функцию DOS  "прием  расширенного  кода ошибки",  чтобы правильно
классифицировать ошибку  как  попытку  неразрешенного  доступа  к
запертому файлу.

     function IsamExitNet : Boolean;

     Данная функция  должна "реверсировать" все действия, которые
перед этим были  выполнены  .  Вектор  int  24h  при
окончании программы  практически восстанавливается дважды - кодом
выхода SYSTEM Turbo Pascal  и  DOS,-  поэтому  вам  не  требуется
самому восстанавливать его в , если только программа
не будет продолжать выполнение после этого  вызова. 
должна возвращать   True  при  успешном  завершении,  и  False  в
противном случае.





6. Использование B-Tree Net
---------------------------

     Если вы  еще  не  прочитали  Главу 3,  "Использование B-Tree
Filer", то сейчас вам пора это сделать.  B-Tree Net  надстраивает
однопользовательскую версию и разделяет описанные там концепции.

А. Организация программы
------------------------

     Для доступа  к  подпрограммам  B-Tree  Net  используйте   (в
операторе USE) модуль FILER в главной программе,  а также в любых
других модулях,  где  это  необходимо.  Программа   должна   быть
организована на основе следующей последовательности действий:

     0. Инициализация  B-Tree Net вызовом .  (Это не
выполняется для вас автоматически.  Дело в  том,  что  вам  может
понадобиться перед этим вызовом сделать дополнительные вызовы для
определения уникального номера рабочей станции).

     1. Создание страничного буфера вызовом .

     2. Открытие или создание одного или  более  файловых  блоков
вызовом ,   ,  ,
,  или .

     3. Использование функций и процедур B-Tree  Filer  и  B-Tree
Net для открытых файловых блоков.

     4. Закрытие    всех   открытых   файловых   блоков   вызовом
 или .

     5. Освобождение       страничного       буфера       вызовом
.

     6. Выход из B-Tree Net вызовом .

     Шаги 0  и  6 требуются в дополнение к обычно необходимым для
однопользовательской версии. Данная последовательность может быть
повторена столько раз,  сколько это нужно.  Кроме того,  файловые
блоки могут быть произвольно открыты и закрыты между  шагами один
и пять.

     Если было  выбрано  определение DynamicNet,  то за установку
переменной   в  значение  желаемой   сети   перед
вызовом  (шаг 0) отвечает сама прикладная программа.

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

     Значение параметра  типа Boolean, передаваемого
в ,  определяет, имеет ли B-Tree Net дело с реальной
сетью,  или эмулирует сеть на одном PC.  Передав в этом параметре
значение False,  выможете разрабатывать на не подключенном к сети
PC прикладную программу,  предназначенную для дальнейшей работе в
сети,  либо программу,  предназначенную для  однопользовательской
работы сегодня,  но которая должна быть перенесена в сеть завтра.
Разумеется,  вы не можете быть уверена, что ваша логика запирания
ресурсов правильна,  пока программа не начнет работать в реальной
сетевой среде.

Режим сохранности или нормальный режим?
---------------------------------------

     Доводы "за"  и "против" использования режима сохранности уже
рассматривались выше.   Однако,   в   сетевой    среде    причины
использовать режим сохранности усиливаются. Поскольку большинство
пользователей занимается обработкой  данных,  целостность  данных
приобретает в  сетевых прикладных программах наивысший приоритет.
Следовательно, мы рекомендуем использовать в  большинстве сетевых
прикладных программ  режим  сохранности.  Несмотря  на  некоторое
уменьшение скорости выполнения по сравнению с  начальным режимом,
различие это  при  работе в сети фактически меньше,  чем в случае
однопользовательской машины (благодаря схеме  кеширования  данных
между диском  и  оперативной памятью,  используемой в большинстве
систем).

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

     Финальный выбор  между  режимом  сохранности  и   нормальным
режимом будет  основан  на  комбинации  измеряемых и субъективных
факторов. Выполняются ли  обновления  данных  в  пакетном  или  в
интерактивном режиме?   Каково   будет  ваше  "самочувствие"  при
интерактивном добавлении и удалении записей при  большой нагрузке
на сеть?  Насколько  много  времени будет занимать перепостроение
данных в  случае  сбоя?  Какая  стратегия  запасного  копирования
выбрана для   данной   сети?   К   счастью,   поочередно  выбирая
подпрограммы   и   ,   вы
можете экспериментально проверить характеристики вашей прикладной
программы, использующей B-Tree Net.

В. Степени запирания
--------------------

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

1-я степень:   и 

     Эти процедуры  действуют  на  все  сетевые  файловые  блоки,
открытые   в   момент   вызова.   После   успешного  возврата  из
 все  сетевые  файловые  блоки  вызывающей
рабочей  станции  доступны  для ее исключительного использования.
Все процедуры записи B-Tree Net (например,  AddNetRec, AddNetKey,
DeleteNetRec  и  DeleteNetKey)  разрешены  до вызова подпрограммы
.

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

     При запирании  1-й  степени  особенно   критичным   является
минимизация времени,  в  течение  которого сетевые файловые блоки
заперты. Следует избегать конкретной ситуации,  когда выполняется
запирание и  затем  интерактивный  ввод  с  клавиатуры,  а  затем
отпирание.

2-я степень:  и 

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

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

3-я степень:  и 

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

4-я степень: в B-Tree Net непосредственно не реализована

     Пользователь обеспечивает подпрограммы,  использующие другие
методы запирания,  действующие  на   запись   данных   (например,
"запирание с разделением" в Novell).  B-Tree Net поддерживает эту
возможность косвенно,   через   процедуру   .   По
заданному открытому  сетевому  файловому  блоку  и  номеру записи
 возвращает логический  номер  файла,  содержащего
эту запись,  а также смещение в файле и длину этой записи.  Этого
достаточно для доступа  к  записи  пользовательской  подпрограммы
запирания.

     Ниже следуют общие комментарии относительно запирания.

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

     
     
     
     
     

     Сетевой файловый   блок   запирается   внутренним    образом
следующим образом:

     - Физически запирается первый байт диалогового файла (вместо
файла данных).

     - Индексный   файл   полностью   запирается   с   физическим
запиранием записи.

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

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

     Запирание степени   3    предназначено    для    обеспечения
исключительного доступа  к  одной записи данных.  Это выполняется
путем запирания  первых  четырех  байтов   записи   данных,   что
предотвращает чтение  и  запись  с  другой  рабочей  станции даже
подпрограммами типа   "InSpiteOfLock"    ("НеСмотряНаЗапирание"),
упомянутыми выше.    Следующая    подпрограмма    B-Tree   Filer,
, позволяет  доступ  даже   в   этом   случае.
 возвращает  запись  как обычно,  но оставляет
первые четыре байта неопределенными,  поскольку они не могут быть
прочитаны. Однако,  если  запись  данных создана в соответствии с
рекомендацией резервирования  первые  четыре  байта  как  маркера
удаления записи, то реальная информация не теряется.

     Важно отметить,  что  если одна рабочая станция использовала
запирания степени 3 и 4,  то другая станция не получит доступа  к
запертой записи даже если она ранее заперла весь сетевой файловый
блок при  помощи  степени  1  или  2.  Следовательно,  программа,
использующая степени 3 или 4,  должна принимать меры для чтения и
записи      при      помощи             и
.


С. Преобразование однопользовательских программ
-----------------------------------------------

     Легко преобразовать     существующую    однопользовательскую
программу для   использования   в    сети    при    использовании
исключительно запирания 1 степени.

     - Изменение  всех  вызовов  B-Tree  Filer на соответствующие
вызовы B-Tree Net.

     - Вызов   перед  каждым  доступом  на
запись, после которого вызов .

     - Добавить  после  каждого  вызова  B-Tree  Net проверки для
обработки дополнительных  ошибок,  которые  могли  там  произойти
(нарушене запирания и т.д.).

     - Для  оптимизации  по  времени следовать двум правилам:  не
выполнять никакого ввода с  клавиатуры  при  активном  запирании;
выполнять в  пределах  каждого  запирания  столько вызовов B-Tree
Net, сколько это возможно.

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

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

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

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

     - Запирание  степеней  1  или  2  всего  файлового  блока не
гарантирует, что рабочая станция может получить  доступ  к  любой
конкретной существующей  записи,  поскольку  другая станция могла
запереть эту запись со степенью 3  или  4.  Решить  эту  проблему
можно соответствующим  использованием   и
.

     В сетевой среде могут  возникнуть  и  другие  сложности,  не
связанные непосредственно   с  запиранием.  Рассмотрим  следующие
сценарии:

     1. Запись,  редактируемая рабочей станцией 1,  тем  временем
удаляется или изменяется станцией 2.

     2. Запись,  которая  должна  быть  удалена  станцией 1,  тем
временем удалена или изменена станцией 2.

     3. Листинг,  печатаемый рабочей станцией 1,  будет неточным,
если во  время  печати  рабочая  станция  2 модифицирует индексы.
(Например, если станция 2 модифицирует  индекс  уже  напечатанной
записи и реиндексирует эту запись таким образом, что она окажется
после текущей  позиции  печати,  так  что  эта  запись   окажется
напечатанной дважды.)

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

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

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

     Редактирование
     --------------

     Чтение записи
     Интерактивное выполнение редактирования
     Запирание записи
     Повторное чтение записи
     Сравнение с исходной записью
     Если они идентичны
       Запирание файлового блока
       Запись назад модифицированной записи
       Если был модифицирован ключ
         Удаление старых ключей
         Добавление новых ключей
       Отпирание файлового блока
       Отпирание записи
     Если они не идентичны (другая станция модифицировала запись)
       Отпирание записи
       Предоставление пользователю новых данных и повторение
             редактирования


     Удаление
     --------

     Чтение записи
     Интерактивный запрос подтверждения удаления
     Запирание записи
     Повторное чтение записи
     Сравнение с исходной записью
     Если они идентичны
       Запирание файлового блока
       Удаление записи и всех ключей
       Отпирание файлового блока
       Отпирание записи
     Если они не идентичны (другая станция модифицировала запись)
       Отпирание записи
       Начать с начала

     Примеры в следующем  разделе  (а  также  программа  NETDEMO)
демонстрируют действующие реализации этих алгоритмов.


D. Примеры программирования
---------------------------

     Поскольку подпрограммы B-Tree Net близко соответствуют своим
однопользовательским аналогам,  мы можем использовать  пример  из
Главы 3   также   и   здесь.   Сначала  все  однопользовательские
подпрограммы заменяются   соответствующими    вызовами    сетевых
подпрограмм.

     В данном  же  разделе мы предлагаем примеры,  иллюстрирующие
некоторые специфические  вопросы,  которые  были  рассмотрены   в
данной главе.Их  исходный код можно найти в файле NETEXAMP.PAS на
дискете NET.

Реакция на запирание
--------------------

     Рассмотрим функцию   FindRecord   из   главы  3.  Существует
несколько способов сделать ее  сетевой.  Во-первы,  можно  просто
добавить соответствующую    обработку    ошибки    после   вызова
существующей подпрограммы:


     if not FindRecord(P, RefNr, KeyNr, Key) then
       if IsamErrorClass = 2 then begin
         {Ошибка запирания}
         WriteLn('Файл или запись заперты');
         {Абортирование операции}
       end;


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

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


  function IsLockError(Ask : Boolean) : Boolean;
  const
    MaxRetries = 10;
    RetryCount : Integer = 0;
  begin
    if IsamOK or (IsamErrorClass <> 2) then begin
      {Ошибки нет, или она не связана с запиранием}
      IsLockError := False;
      {Сброс счетчика повторных попыток}
      RetryCount := 0;
    end else begin
      {Ошибка запирания}
      IsLockError := True;
      inc(RetryCount);
      if RetryCount > MaxRetries then begin
        {Исчерпаны попытки}
        if not Ask then
          {Абортирование операции без запроса}
          IsLockError := False
        else if not YesNo('Ошибка запирания. Попробовать еще раз') then
          {Абортирование операции с запросом пользователя}
          IsLockError := False;
        {Сброс счетчика повторных попыток}
        RetryCount := 0;
      end;
    end;
  end;


     Вместо проверки  после каждой  операции  B-Tree  Net
может быть вызвана IsLockError. Если она вернет False, и 
также имеет значение False,  то произошла ошибка,  не связанная с
запиранием (или   возможно,  был  превышен  счетчик  повторов,  и
пользователь принял решение прервать операцию).

     С использованием IsLockError мы можем  переписать FindRecord
следующим образом:


  function FindRecord(var P : PersonDef;
                      var RefNr : LongInt;
                      KeyNr : Integer;
                      var Key : IsamKeyStr) : Boolean;
  begin
    FindRecord := False;
    repeat
      SearchNetKey(PF, KeyNr, RefNr, Key);
    until not IsLockError(True);
    if not IsamOK then begin
      {Ключ не найден, программная ошибка, или приводящая к
       абортированию операции ошибка запирания}
      Exit;
    end;
    repeat
      GetNetRec(PF, RefNr, P);
    until not IsLockError(True);
    if not IsamOK then begin
      {Обработка ошибки}
      Exit;
    end;
    FindRecord := True;
  end;


     Этот пример может  быть  расширен  всеми  прочими  функциями
чтения из Главы 3.С.


Реакция на модифицированные данные
----------------------------------

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

     Рабочая станция 1 читает запись номер 10.
     Рабочая станция 2 удаляет запись номер 10.
     Рабочая станция 1 удаляет запись номер 10.

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


const
  SevereError = 20;
  ModifiedError = 10;

var
  MaxError : Integer;             {Переменные статуса запирания}
  RecordLocked : Boolean;
  FileBlockLocked : Boolean;

  procedure InitForUpdateLock;
  begin
    MaxError := 0;
    FileBlockLocked := False;
    RecordLocked := False;
  end;

  procedure SetMaxError;
  var
    ErrorClass : Integer;
  begin
    ErrorClass := IsamErrorClass;
    if ErrorClass > MaxError then
      MaxError := ErrorClass;
  end;

  procedure UpdateUnlock(RefNr : LongInt);
  begin
    if FileBlockLocked then begin
      UnlockFileBlock(PF);
      if not IsamOK then
        {Аппаратный сбой? Это не должно случаться}
        MaxError := SevereError
      else
        FileBlockLocked := False;
    end;
    if RecordLocked then begin
      UnlockRec(PF, RefNr);
      if not IsamOK then
        {Аппаратный сбой? Это не должно случаться}
        MaxError := SevereError
      else
        RecordLocked := False;
    end;
  end;

  function UpdateLock(RefNr : LongInt) : Boolean;
  begin
    UpdateLock := False;
    {Запирание записи}
    LockRec(PF, RefNr);
    {Требуется только при использовании прикладной программой
     запирания степени 3}
    if not IsamOK then begin
      {Запись не должна быть заперта}
      SetMaxError;
      UpdateUnlock(RefNr);
      Exit;
    end;
    RecordLocked := True;

    {Запирание файлового блока}
    LockFileBlock(PF);
    if not IsamOK then begin
      {Файловый блок не мог быть заперт}
      SetMaxError;
      UpdateUnlock(RefNr);
      Exit;
    end;
    FileBlockLocked := True;
    UpdateLock := True;
  end;

  function MatchRecord(P1, P2 : PersonDef) : Boolean;
  begin
    {Возвращает true, еслиf P1 и P2 одинаковы}
    MatchRecord := True;
  end;

  function DeleteRecord(P : PersonDef; RefNr : LongInt) : Integer;
  var
    KeyNr : Integer;
    TempP : PersonDef;
  begin
    {В этой точке удаляемая запись уже была считана в запись Р,
     и пользователь проверил, что удаление произойдет}

    DeleteRecord := 0;

    {Подготовка к запиранию}
    InitForUpdateLock;

    {Запереть запись и файловый блок}
    if not UpdateLock(RefNr) then begin
      {Запирание не могло быть выполнено}
      DeleteRecord := MaxError;
      Exit;
    end;

    {Снова взять запись и проверить, продолжает ли она
     соответствовать оригиналу}
    GetNetRec(PF, RefNr, TempP);
    if not IsamOK then begin
      {Этого не должно случиться}
      SetMaxError;
      UpdateUnlock(RefNr);
      DeleteRecord := MaxError;
      Exit;
    end;

    if TempP.Del <> 0 then begin
      {Запись тем временем была удалена.
       Это хорошо, т.к. мы намеревались сделать то же самое}
      UpdateUnlock(RefNr);
      DeleteRecord := MaxError;
      Exit;
    end;

    if not MatchRecord(P, TempP) then begin
      {Запись тем временем была удалена.
       Возврат уникального класса ошибки}
      MaxError := ModifiedError;
      UpdateUnlock(RefNr);
      DeleteRecord := MaxError;
      Exit;
    end;

    {И наконец, выполняется удаление}
    for KeyNr := 1 to NrKeys do begin
      DeleteNetKey(PF, KeyNr, RefNr, CreateKey(P, KeyNr));
      if not IsamOK then
        if IsamError = 10220 then
          {Ключ уже был удален. Этого не должно было произойти,
           но и в этом случае все в порядке}
        else begin
          {Обработка ошибки}
          SetMaxError;
          UpdateUnlock(RefNr);
          DeleteRecord := MaxError;
          Exit;
        end;
    end;
    DeleteNetRec(PF, RefNr);
    if not IsamOK then
      SetMaxError;

    {Отпирание записи и файлового блока}
    UpdateUnlock(RefNr);
    DeleteRecord := MaxError;
  end;


     Глобальные переменные      MaxError,      RecordLocked     и
FileBlockLocked используются таким образом,  что данный код может
разделяться с  другими  подпрограммами,  требующими  аналогичного
запирания, такими  как  ModifyRecord.   Подпрограмма   UpdateLock
запирает обновляемую запись, а затем запирает весь файловый блок,
так что ключи могут быть удалены безопасным образом. UbdateUnlock
отпирает запись  и  файловый  блок,  когда  DeleteRecord готова к
завершению. Отметим,  что DeleteRecord  возвращает  класс  ошибки
вместо простого логического признака ошибки.  Она возвращает любо
один из стандартных классов  ошибки  B-Tree  Net,  либо  один  из
нескольких классов ошибки, определенных пользователем.

     Функция ModifyRecord   может  быть  реализована  аналогичным
образом. Все примеры подпрограмм, соответственно модифицированные
для использования в сети, поставляются в NETEXAMP.PAS.




7. Идентификаторы B-Tree Net
----------------------------

     В данной  главе  описаны  все константы,  типы,  переменные,
процедуры и функции B-Tree Net. Функции и процедуры расположены в
алфавитном порядке.  В  Приложении  В  находится список функций и
процедур, сгруппированный по их функциональному назначению.

     Все идентификаторы однопользовательской версии B-Tree Filer,
описанные в Главе 4, доступны также и в сетевой версии. Здесь они
не повторяются.

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

     Однопользовательская        Многопользовательская
         версия                       версия
     --------------------        ---------------------
     MakeFileBlock               MakeNetFileBlock
     CloseFileBlock              CloseNetFileBlock
     OpenFileBlock               OpenNetFileBlock
     OpenSaveFileBlock           OpenSaveNetFileBlock
     DeleteFileBlock             DeleteNetFileBlock

     UsedRecs                    UsedNetRecs
     FileLen                     NetFileLen
     FreeRecs                    FreeNetRecs
     GetRec                      GetNetRec
     AddRec                      AddNetRec
     PutRec                      PutNetRec
     DeleteRec                   DeleteNetRec

     AddKey                      AddNetKey
     DeleteKey                   DeleteNetKey
     FindKey                     FindNetKey
     SearchKey                   SearchNetKey
     FindKeyAndRef               FindNetKeyAndRef
     SearchKeyAndRef             SearchNetKeyAndRef
     KeyExists                   NetKeyExists
     NextKey                     NextNetKey
     PrevKey                     PrevNetKey
     ClearKey                    ClearNetKey
     NextDiffKey                 NextDiffNetKey
     PrevDiffKey                 PrevDiffNetKey

     B-Tree Net также добавляет одну новую типированную константу.

     {$IFDEF DynamicNet}
     const
       DynamicNetType : NetSupportType = MsNet;
     {$ENDIF}

     Эта типированная константа объявлена только  при определении
DynamicNet. В  этом  случае она задает,  какой код поддержки сети
нижнего уровня  будут  использован.  Прикладная  программа   сама
должна определить нужный код сети и назначить  до
вызова .   может принимать  одно  из
значений в   :  NoNet,  Novell,  CBISNet,  MsNet,
MsNetMachName или PCMOS386.


AddNetKey
-----------------------------------------------------------------
Объявление
----------

     procedure AddNetKey(IFBPtr : IsamFileBlockPtr;
                      Key : Integer;
                      UserDatRef : LongInt;
                      UserKey : IsamKeyStr);

Параметры
---------

     IFBPtr        Указатель файлового блока

     Key           Номер ключа, как в параметре , передаваемом
                   в 

     UserDatRef    Номер записи данных, полученный из предыдущего
                   вызова 

     UserKey       Добавляемый ключ

Описание
--------

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

Ошибки
------

     9900..9906   Ошибки операционной системы

     10003        (Только в режиме сохранности). Операция была
                  абортирована вследствие суровой ошибки ввода/
                  вывода. Реконструкция файловых блоков не нужна,
                  поскольку "ремонт" был выполнен успешно.

     10178        Параметр "Key" содержит неверный параметр.

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

     10378        Операция разрешена только при запертом сетевом
                  файловым блоке.

Примечания
----------

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

     Эта процедура может быть успешно использована,  если сетевой
файловый блок заперт со степенью 1 или 2.


AddNetRec
-----------------------------------------------------------------
Объявление
----------

     procedure AddNetRec(IFBPtr : IsamFileBlockPtr;
                      var RefNr : LongInt;
                      var Source);

Параметры
---------

     IFBPtr        Указатель файлового блока.
     RefNr         Позиция в файле данных, куда была записана запись
                   данных (относительный номер записи в файле);
                   используется для добавления индекса при помощи
                   .
     Source        Добавляемая запись данных.

Описание
--------

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

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

Ошибки
------

     9900..9906   Ошибки операционной системы

     10001        (Только в режиме сохранности). Операция была
                  абортирована вследствие суровой ошибки ввода/
                  вывода. Реконструкция файловых блоков не нужна,
                  поскольку "ремонт" был выполнен успешно.

     10369        Операция предотвращена запиранием.

     10376        Операция разрешена только при запертом сетевом
                  файловым блоке.

Примечания
----------

     Эта процедура может быть успешно использована,  если сетевой
файловый блок заперт со степенью 1 или 2.


ClearNetKey
-----------------------------------------------------------------
Объявление
----------

     procedure ClearNetKey(IFBPtr : IsamFileBlockPtr; Key : Integer);

Параметры
---------

     IFBPtr        Указатель файлового блока

     Key           Номер ключа, как в параметре , передаваемом
                   в 

Описание
--------

      сбрасывает последовательный указатель  ключа с
номером  .  Это  позволяет    возвратить  первый
(наименьший) ключ,  - последний (наибольший) ключ.

Ошибки
------

     10171       Параметр  содержит неверный номер.

     10359        Операция предотвращена запиранием.


CloseEachFileBlock
-----------------------------------------------------------------
Объявление
----------

     procedure CloseEachFileBlock;

Описание
--------

     Закрывает все открытые файловые  блоки,  как  одно-,  так  и
многопользовательские. B-Tree Filer вызывает эту подпрограмму как
часть собственной     процедуры     выхода.     Лишний      вызов
 не   может   повредить,   поскольку  она  не
пытается снова закрыть уже закрытые файловые блоки.

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

Ошибки
------

     9900..9906   Ошибка операционной системы

     10080        Файловый блок не был открыт.

     10160        Файловый блок не мог быть правильно закрыт.

     10321        Файловый блок в текущий момент заперт.


CloseNetFileBlock
-----------------------------------------------------------------
Объявление
----------

     procedure CloseNetFileBlock(var IFBPtr : IsamFileBlockPtr);


Параметры
---------

     IFBPtr   Указатель закрываемого файлового блока.

Описание
--------

     Закрывает файловый  блок    и  освобождает  память,
выделенную     ,          или
.

Ошибки
------

     9900..9906   Ошибка операционной системы.

     10080        Файловый блок не был открыт.

     10160        Файловый блок не мог быть правильно закрыт.

     10321        Файловый блок в текущий момент заперт.


Примечания
----------

     Этот вызов  важет  с  точки  зрения  сохранения  целостности
файлового  блока.  Если    не   вызывать,   то
следующий   раз   при   запуске   программы   может  понадобиться
пересоздание индексного файла.  Это очень важно при  тестировании
программы:  если программа сбивается,  когда файлы открыты и были
выполнены индексные  операции,  то  индексный  файл  должен  быть
регенерирован.  B  -Tree  Filer  реализует процедуру выхода Turbo
Pascal,  которая автоматически закрывает  все  открытые  файловые
блоки при завершении программы,  как нормальном, так и аварийном,
с ошибкой времени выполнения.  При "зависании" программы этого не
происходит.

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


DeleteNetFileBlock
-----------------------------------------------------------------
Объявление
----------

     procedure DeleteNetFileBlock(FName : IsamFileBlockName);

Параметры
---------

     FName     Имя DOS, включающее необязательные имена дисковода и
               маршрута, но без расширения.

Описание
--------

     Удаляет все файлы DOS, принадлежащие файловому блоку с именем
, т.е.  все файлы с именем   и  расширением  '.DAT',
'.IX' и '.DIA'.

Ошибки
------

     9900..9906   Ошибки операционной системы.


DeleteNetKey
-----------------------------------------------------------------
Объявление
----------

     procedure DeleteNetKey(IFBPtr : IsamFileBlockPtr;
                      Key : Integer;
                      UserDatRef : LongInt;
                      UserKey : IsamKeyStr);

Параметры
---------

     IFBPtr        Указатель файлового блока

     Key           Номер ключа, как в параметре , передаваемом
                   в 

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

     UserKey       Удаляемый ключ

Описание
--------

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

Ошибки
------

     9900..9906   Ошибки операционной системы

     10004        (Только в режиме сохранности). Операция была
                  абортирована вследствие суровой ошибки ввода/
                  вывода. Реконструкция файловых блоков не нужна,
                  поскольку "ремонт" был выполнен успешно.

     10179        Параметр "Key" содержит неверный параметр.

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

     10379        Операция разрешена только при запертом сетевом
                  файловым блоке.

Примечания
----------

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


DeleteNetRec
-----------------------------------------------------------------
Объявление
----------

     procedure DeleteNetRec(IFBPtr : IsamFileBlockPtr; RefNr : LongInt);

Параметры
---------

     IFBPtr        Указатель файлового блока.

     RefNr         Номер удаляемой записи.

Описание
--------

      удаляет из файла запись данных. Запись данных
фактически  помечается  как свободная,  что позволяет последующим
вызовам  заполнять "пустоту".

Ошибки
------

     9900..9906   Ошибки операционной системы

     10002        (Только в режиме сохранности). Операция была
                  абортирована вследствие суровой ошибки ввода/
                  вывода. Реконструкция файловых блоков не нужна,
                  поскольку "ремонт" был выполнен успешно.

     10370        Операция предотвращена запиранием.

     10377        Операция разрешена только при запертом сетевом
                  файловым блоке.


Примечания
----------

     Удалены могут   быть   только   существующие  записи  данных.
Удаление уже удаленной записи запортит внутренний  связный  список
удаленных записей   данных,   что   приведет   к   непредсказуемым
результатам. Когда  запись  удалена,  B-Tree  Filer  устанавливает
первые четыре  байта  записи  в  ненулевое  значение.  Если первые
четыре байта  каждой  записи   данных   резервируются   и   обычно
установлены в ноль, это позволит легко различить удаленные записи.

     Эта процедура может быть успешно использована только  в  том
случае, если сетевой файловый блок заперт со степенью 1 или 2.


DisableSearchForSequential
-----------------------------------------------------------------
Объявление
----------

     procedure DisableSearchForSequential(IFBPtr : IsamFileBlockPtr;
                                          Key : Integer);

Параметры
---------

     IFBPtr        Указатель файлового блока

     Key           Номер ключа, как в параметре , передаваемом
                   в 

Описание
--------

     Данная процедура     делает     невозможным      специальный
последовательный метод       поиска,       активированный       в
.

Ошибки
------

     10393      Параметр  содержит неверный номер.

Примечания
----------

     По умолчанию  специальный  метод  поиска  невозможен,   если
только не     установить     в     значение     True    константу
.


EnableSearchForSequential
-----------------------------------------------------------------
Объявление
----------

     procedure EnableSearchForSequential(IFBPtr : IsamFileBlockPtr;
                                         Key : Integer);

Параметры
---------

     IFBPtr        Указатель файлового блока

     Key           Номер ключа, как в параметре , передаваемом
                   в 


Описание
--------

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

     В сетевой программе часто  случается,  что  последовательный
указатель, от   которого   зависит  работа  ,  бывает
запорчен другой рабочей станцией.  Это случается  в  том  случае,
если другая станция вызывает  или  через
некоторое время  после  того,   как   текущая   рабочая   станция
инициализировала последовательный указатель.  В этом случае вызов
 завершится неудачно, возвратив коды ошибки 10255 или
10265 ("последовательный доступ не разрешен").

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

     Будет ли  специальный  метод поиска разрешен или запрещен по
умолчанию, зависит от состояния глобальной типированной константы
,  с  которой  взаимодействует FILER.
Это  булево  значение  по  умолчанию  устанавливается  в   False,
запрещая поиск  для  всех  ключей,  пока  не  будет активирована.
Установка его в True (до создания или открытия  файлового  блока)
разрешает поиск для всех ключей.

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

Ошибки
------

     10390      Параметр  содержит неверный номер.

Примечания
----------

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


ExitNetIsam
-----------------------------------------------------------------
Объявление
----------

     procedure  ExitNetIsam;


Описание
--------

     Данная процедура должна вызываться последней  перед  выходом
из B-Tree   Net.   Она   удаляет   все   обработчики  прерываний,
установленные для  обнаружения   сетевых   ошибок   и   в   целом
восстанавливает сеть  в  то  состояние,  которое  было  у  нее до
запуска прикладной программы.

Ошибки
------

     10320   Неудачный выход сетевой программы.

Примечания
----------

     Выход из  B-Tree  Net  без  вызова  данной  процедуры  может
привести к   непредвиденным  проблемам  в  сети  -  даже  к  сбою
операционной системы.  B-Tree  Net  не   вызывает   
автоматически - как часть процедуры выхода Turbo Pascal.   (Он не
делает этого  по  ряду  причин:  чтобы  позволить   вам   вызвать
 до  выхода из программы и избежать проблем, которые
могут возникнуть,  если код выхода сети вызывается  более  одного
раза.)


FindNetKey
-----------------------------------------------------------------
Объявление
----------

     procedure FindNetKey(IFBPtr : IsamFileBlockPtr;
                      Key : Integer;
                      var UserDatRef : LongInt;
                      UserKey : IsamKeyStr);

Параметры
---------

     IFBPtr        Указатель файлового блока

     Key           Номер ключа, как в параметре , передаваемом
                   в 

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

     UserKey       Ключ поиска.

Описание
--------

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

Ошибки
------

     9900..9906   Ошибки операционной системы

     10174        Параметр "Key" содержит неверный параметр.

     10200        Ключ  не найден.

     10364        Операция предотвращена запиранием.

Примечания
----------

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


FindNetKeyAndRef
-----------------------------------------------------------------
Объявление
----------

     procedure FindNetKeyAndRef(IFBPtr : IsamFileBlockPtr;
                      Key : Integer;
                      var UserDatRef : LongInt;
                      var UserKey : IsamKeyStr
                      NotFoundSearchDirection : Integer);

Параметры
---------

     IFBPtr        Указатель файлового блока

     Key           Номер ключа, как в параметре , передаваемом
                   в 

     UserDatRef    Номер записи данных для ;
                   найденный номер возвращается через эту переменную.

     UserKey       Ключ поиска;
                   найденный ключ возвращается через эту переменную.

     NotFoundSearchDirection      Определяет, нужно ли и как
                   продолжать работу, если пара ключ/адрес записи
                   не найдена.

Описание
--------

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

Ошибки
------

     9900..9906   Ошибка операционной системы.

     10170        Параметр "Key" содержит неверный номер.

     10200        Ключ  не найден.

     10210        Ключ  не найден, и ключа с большим
                  значением не существует.

     10250        Большего ключа не существует.

     10255        Последовательный доступ не разрешен.

     10270        Ключ с таким адресом недоступен.

     10382        Операция предотвращена запиранием.

Примечания
----------

     Данная процедура не предназначена для возврата  адрес  записи
данных по конкретному ключу;  это вы уже должны были понять.  Она,
что более  важно,   позволяет   позиционировать   последовательный
указатель в   середине  блока  идентичных  вторичных  ключей.  Это
особенно полезно при экранном просмотре или создании списков.


FreeNetRecs
-----------------------------------------------------------------
Объявление
----------

     function FreeNetRecs(IFBPtr : IsamFileBlockPtr) : LongInt;

Параметры
---------

     IFBPtr      Указатель файлового блока.

     Результат   Число свободных записей данных.

Описание
--------

      возвращает  число  удаленных  записей   данных
("дыр") в файловом блоке . Физическая длина файла данных
вычисляется как:

     DatRecordSize(IFBPtr)*(UsedNetRecs(IFBPtr)+FreeNetRecs(IFBPtr)+1)

Ошибки
------

     9900..9906   Ошибка операционной системы

     10381        Операция предотвращена запиранием.


GetNetRec
-----------------------------------------------------------------
Объявление
----------

     procedure GetNetRec(IFBPtr : IsamFileBlockPtr;
                      RefNr : LongInt;
                      var Destination);

Параметры
---------

     IFBPtr        Указатель файлового блока

     RefNr         Номер читаемой записи

     Destination   Запись данных

Описание
--------

     Читает запись  данных  с  заданным номером .  
обычно получают при помощи предыдущей индексной операции.

Ошибки
------

     9900..9906   Ошибка операционной системы

     10363        Операция предотвращена запиранием.


Примечания
----------

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


GetNetRecInSpiteOfLock
-----------------------------------------------------------------
Объявление
----------

     procedure GetNetRecInSpiteOfLock(IFBPtr : IsamFileBlockPtr;
                      RefNr : LongInt;
                      var Destination);

Параметры
---------

     IFBPtr        Указатель файлового блока

     RefNr         Номер читаемой записи

     Destination   Запись данных

Описание
--------

     Читает запись  данных  с  заданным номером .  
обычно получают при помощи  предыдущей  индексной  операции.  Эта
процедура отличается  от   тем,  что она читает запись
даже если другая  рабочая  станция  выполнила  запирание  данного
сетевого файлового  блока  степеней 1 или 2.  Запирание степени 3
все же   предотвращают    доступ    к    записям    при    помощи
.

Ошибки
------

     9900..9906   Ошибка операционной системы

     10361        Операция предотвращена запиранием.


Примечания
----------

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


GetNetRecReadOnly
-----------------------------------------------------------------
Объявление
----------

     procedure GetNetRecReadOnly(IFBPtr : IsamFileBlockPtr;
                      RefNr : LongInt;
                      var Destination);

Параметры
---------

     IFBPtr        Указатель файлового блока

     RefNr         Номер читаемой записи

     Destination   Запись данных

Описание
--------

     Читает запись данных с  заданным  номером  .  
обычно  получают  при  помощи предыдущей индексной операции.  Эта
процедура отличается от  тем,  что она  читает  запись
даже  если  другая  рабочая  станция  выполнила  запирание данной
записи степени 3.  Поскольку  когда  запись  данных  заперта,  ее
первые  четыре  байта  не могут быть прочитаны,  то эти байты при
возврате записи  не  инициализированы. Однако,
если  они  были  зарезервированы для использовании в B-Tree Net в
качестве маркера  удаления,  то  никакая  критическая  информация
потеряна   не   будет.   Остальные   байты   записи   заполняются
обыкновенным образом.

Ошибки
------

     9900..9906   Ошибка операционной системы

     10205        Запись занных в настоящий момент заперта.
                  (При этом влюбом случае будут возвращены все
                  байты, кроме первых четырех).

GetRecordInfo
-----------------------------------------------------------------
Объявление
----------

     procedure GetRecordInfo(IFBPtr : IsamFileBlockPtr;
                             Ref : LongInt;
                             var Start, Len : LongInt;
                             var Handle : Word);
Параметры
---------

     IFBPtr        Указатель файлового блока

     Ref           Номер записи.

     Start         Возвращаемая физическая начальная позиция
                   записи данных.

     Len           Возвращаемая длина записи данных.

     Handle        Возвращаемый логический номер файла данных.

Описание
--------

     Данная процедура обеспечивает поддержку запирания степени 4.
Три переменных-параметра  ,    и    полностью
описывают положение найденной записи данных).

Примечания
----------

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


InitNetIsam
-----------------------------------------------------------------
Объявление
----------

     procedure  InitNetIsam(NetExpected : Boolean);

Параметр
--------

     NetExpected   True инициализирует сеть; False включает
                   режим эмуляции.

Описание
--------

     Данная процедура  должна быть вызвана один раз перед вызовом
любых других подпрограмм B-Tree Net.  В сетевой среде должен быть
задан параметр      со  значением  True.  Если  сеть
недоступна, то он должен быть установлен в  False,  например  для
тестирования программы    вне   сети.   Это   значение   заставит
 не  выполнять  инициализацию  сети   и   немедленно
выполнить выход,   не   генерируя   ошибку.  В  этом  случае  все
подпрограммы запирания  и  отпирания  B-Tree   Net   эмулируются.
Реальная сетевая  среда  активируется  только  при  
установленном в True.

Ошибки
------

     10310   Неверный номер рабочей станции или
             ошибка инициализации сети.

Примечания
----------

     Использование подпрограмм  B-Tree  Net  без  предшествующего
вызова этой  процедуры  ведет  к  непредсказуемым   последствиям,
возможно даже к сбою операционной системы.

     При выборе   сетевой   опции  B-Tree  Net  MsNet  вы  должны
определить текущий номер рабочей станци,  ,  прежде чем
вызывать .  Информацию о номерах рабочих станций см.
в Разделе 5.С.


LockAllOpenFileBlocks
-----------------------------------------------------------------
Объявление
----------

     procedure LockAllOpenFileBlocks;


Описание
--------

     Запираются все  сетевые  файловые  блоки.  Выполнение   этой
процедуры является  предварительным условием модификации сетевого
файлового блока (см. .)

Ошибки
------

     10330   Неудачная попытка запирания.

Примечания
----------

     Вызов данной  процедуры  более  одного  раза   не   является
ошибкой.   Сетевые   файловые   блоки  останутся  запертыми.  При
неудачном  завершении  данной  процедуры  все  открытые   сетевые
файловые блоки устанавливаются в незапертое состояние.


LockFileBlock
-----------------------------------------------------------------
Объявление
----------

     procedure LockFileBlock(IFBPtr :IsamFileBlockPtr);

Параметры
---------

     IFBPtr        Указатель файлового блока

Описание
--------

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

     
     
     
     
     

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

Ошибки
------

     10330   Неудачная попытка запирания.

Примечания
----------

     Вызов данной   процедуры   более  одного  раза  не  является
ошибкой. Сетевой файловый блок останется запертым.


LockRec
-----------------------------------------------------------------
Объявление
----------

     procedure LockRec(IFBPtr :IsamFileBlockPtr; Ref : LongInt);

Параметры
---------

     IFBPtr        Указатель файлового блока

     Ref           номер запираемой записи.

Описание
--------

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

Ошибки
------

     10335   Неудачная попытка запирания.


MakeNetFileBlock
-----------------------------------------------------------------
Объявление
----------

     procedure  MakeNetFileBlock(var IFBPtr : IsamFileBlockPtr;
                              FName : IsamFileBlockName;
                              DatSLen : LongInt;
                              NumberOfKeys : Integer;
                              IID : IsamIndDescr);

Параметры
---------

     IFBPtr        Указатель файлового блока, используемый для
                   ссылки к файлам базы данных после их открытия.

     FName         Имя DOS, включая необязательные имена дисковода
                   или маршрута, но без расширения.

     DatSLen       Длина записи данных в байтах, т.е.
                   SizeOf(запись данных).

     NumberOfKeys  Число ключей данного файлового блока.

     IID           Описывает  различных ключей.
                   Более подробную информацию см. описание типа
                   .

Описание
--------

      создает  файлы данных и индексов с именем
 и назначает их  сетевому  файловому  блоку,  указываемому
.    должно  быть  допустимым  именем файла DOS,
которое  может  включать  необязательные  имена  дисковода  и/или
маршрута.   B-Tree   Filer   автоматически   добавляет  к  именам
соответствующие расширения:  '.DAT' для файла данных и '.IX'  для
файла индексов,  заменяя ими любые расширения, если они были явно
заданы в .  (Расширение,  добавляемые файлам по умолчанию,
можно изменить,  модифицировав соответствующие константы в модуле
FILER. См. раздел 4.А).

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

     if IsamExists('MYDATA.DAT') then
       WriteLn('Файл данных уже существует!');
     else
       MakeNetFileBlock(IFBPtr, 'MYDATA', DatSLen, NumKeys, IID);

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

     Параметр    содержит    размер    записи    данных.
Рекомендуется,  чтобы каждое определение записи данных начиналось
полем типа LongInt, резервируемым для внутреннего использования B
-Tree  Filer.  Прикладная  программа  должна инициализировать это
поле  нулем.  B-Tree  Filer  будет  записывать   туда   ненулевые
значения,  помечая  записи  нак свободные при выполнении операции
. Эти значения служат для идентификации достоверных
(неудаленных)  записей  во  время перепостроения файлового блока,
если будет поврежден  индекс.  Они  позволяют  использовать  файл
данных  без ссылок к индексному файлу.  В противном случае запись
данных   рассматривается   как   нетипированный    параметр,    а
пользователь сам отвечает за его содержимое.

     Структура индексного  файла  определяется  параметром .
Обычно  параметр    должен  быть  объявлен   как   локальная
переменная  и  инициализироваться  непосредственно  перед вызовом
.  Более подробную  информацию  см.  в  Примере
программирования в разделе 3.С

      выделяет ((+1)*(32+5
*))+256 байтов  "кучи".  При вызове  не
забудьте зарезервировать как минимум это количество памяти "кучи".

Ошибки
------

     9900..9906   Ошибка операционной системы

     10020        Длина записи данных меньше 21 или больше
                  2,147,483,647 байтов.

     10040        Недостаточно памяти для создания поля дескриптора
                  файлового блока.

     10055        Ключ был объявлен длиннее .

     10100        Недостаточно памяти для создания файлового блока.

     10320        Не удалось создание сетевого файлового блока.

Примечания
----------

     Отметим, что  в  отличие  от  того,  что принято в некоторых
других СУБД,   оставляет файловый блок открытым
и   готовым  к  использованию.  В  некоторых  случаях  вам  может
понадобиться  закрыть  его  при  помощи      и
повторно     открыть     процедурой         или
. Это единственный способ доступа к только что
созданному  файловому блоку в режиме сохранности.  Некоторые сети
на базе файловой системы MS-DOS не разрешают  нескольким станциям
разделять  файл,  открытый  вызовом  Rewrite();  для  этого также
потребуется закрыть и повторно открыть файловый блок.


NetFileLen
-----------------------------------------------------------------
Объявление
----------

     function NetFileLen(IFBPtr : IsamFileBlockPtr) : LongInt;

Параметры
---------

     IFBPtr     Указатель файлового блока.

     Результат  Общее число записей в файловом блоке.


Описание
--------

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

     Физическая длина файла данных может быть вычислена как

     DatRecordSize(IFBPtr) * NetFileLen(IFBPtr)

Ошибки
------

     9900..9906   Ошибка операционной системы.

     10384        Операция предотвращена запиранием.


Примечания
----------

     Эта подпрограмма   поставляется    главным    образом    для
совместимости с DataBase Toolbox.  Для определения индивидуальных
компонентов  общего   количества,   возвращенного   ,
используйте  и .

NetKeyExists
-----------------------------------------------------------------
Объявление
----------

     function NetKeyExists (IFBPtr : IsamFileBlockPtr;
                         Key : Integer;
                         UserDatRef : LongInt;
                         UserKey : IsamKeyStr) : Boolean;

Параметры
---------

     IFBPtr        Указатель файлового блока
     Key           Номер ключа, как в параметре , передаваемом
                   в 
     UserDatRef    Номер записи данных, позволяющий различать
                   вторичные ключи. Этот параметр для вторичного
                   ключа обязательно должен быть задан правильно,
                   тогда как для первичного ключа он игнорируется.
     UserKey       Искомый ключ
     Результат     True, если искомый ключ существует, и False
                   в противном случае.

Описание
--------

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

Ошибки
------

     9900..9906   Ошибка операционной системы

     10176        Параметр  содержит неверный номер.

     10367        Операция предотвращена запиранием.


Примечания
----------

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


NetSupported
-----------------------------------------------------------------
Объявление
----------

     function NetSupported : NetSupportType;


Описание
--------

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

     NoNet            Однопользовательская среда

     Novell           Novell

     MsNet            Microsoft Network

     MsNetMachName    Microsoft Network с поддержкой имени машины

     CBISNet          CBIS-Network (Network-OS)

     PCMOS386         PC-MOS/386

     Возвращаемое функцией  значение не зависит от того, включена
ли эмуляция сети,  или нет.  (Эмуляция сети задается передачей  в
 параметра False.)



NextDiffNetKey
-----------------------------------------------------------------
Объявление
----------

     procedure NextDiffNetKey(IFBPtr : IsamFileBlockPtr;
                           Key : Integer;
                           var UserDatRef : LongInt;
                           var UserKey : IsamKeyStr);


Параметры
---------

     IFBPtr        Указатель файлового блока

     Key           Номер ключа, как в параметре , передаваемом
                   в 

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

     UserKey       Ключ для сравнения; через этот параметр возвращается
                   первый ключ, больший данного.

Описание
--------

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


Ошибки
------

     9900..9906   Ошибка операционной системы

     10177        Параметр  содержит неверный номер.

     10240        Ключа, большего, чем данный, не существует.

     10366        Операция предотвращена запиранием.

Примечания
----------

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


NextKey
-----------------------------------------------------------------
Объявление
----------

     procedure NextNetKey(IFBPtr : IsamFileBlockPtr;
                       Key : Integer;
                       var UserDatRef : LongInt;
                       var UserKey : IsamKeyStr);


Параметры
---------

     IFBPtr        Указатель файлового блока

     Key           Номер ключа, как в параметре , передаваемом
                   в 

     UserDatRef    Номер записи данных, который будет использован в
                   последующем вызове  при успешном поиске
                   при помощи .

     UserKey       Через этот параметр возвращается следующий ключ.

Описание
--------

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

Ошибки
------

     9900..9906   Ошибка операционной системы

     10172        Параметр  содержит неверный номер.

     10250        Большего ключа не существует.

     10255        Последовательный доступ не разрешен.

     10373        Операция предотвращена запиранием.


Примечания
----------

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

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


OpenNetFileBlock
-----------------------------------------------------------------
Объявление
----------

     procedure OpenNetFileBlock(var IFBPtr : IsamFileBlockPtr;
                             FName :IsamFileBlockName);

Параметры
---------

     IFBPtr   Указатель файлового блока, используемый для ссылки к
              файлам базы данных после их открытия.

     FName    Имя DOS, включая необязательные имена дисковода
              или маршрута, но без расширения.

Описание
--------

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

     10100        Недостаточно памяти для создания файлового блока.

     10180        Попытка "ремонта" файлового блока не удалась.
                  Требуется отдельная реконструкция.

     10355        Операция предотвращена запиранием.

     10356        Недостаточно памяти для дескриптора сетевого
                  файлового блока.



OpenSaveNetFileBlock
-----------------------------------------------------------------
Объявление
----------

     procedure OpenSaveNetFileBlock(var IFBPtr : IsamFileBlockPtr;
                                 FName :IsamFileBlockName);

Параметры
---------

     IFBPtr   Указатель файлового блока, используемый для ссылки к
              файлам базы данных после их открытия.

     FName    Имя DOS, включая необязательные имена дисковода
              или маршрута, но без расширения.

Описание
--------

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

Ошибки
------

     9900..9906   Ошибка операционной системы

     10010        Индексный файл не был правильно закрыт в последнем
                  сеансе (См. раздел 3.D, "Управление файловым
                  блоком").

     10030        Недостаточно памяти для создания поля дескриптора
                  файлового блока.

     10060        Вычисленное число ключей превышает ,
                  или произошла ошибка чтения, не распознанная
                  операционной системой.

     10100        Недостаточно памяти для создания файлового блока.

     10180        Попытка "ремонта" файлового блока не удалась.
                  Требуется отдельная реконструкция.

     10355        Операция предотвращена запиранием.

     10356        Недостаточно памяти для дескриптора сетевого
                  файлового блока.

Примечания
----------

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


PrevDiffNetKey
-----------------------------------------------------------------
Объявление
----------

     procedure PrevDiffNetKey(IFBPtr : IsamFileBlockPtr;
                           Key : Integer;
                           var UserDatRef : LongInt;
                           var UserKey : IsamKeyStr);


Параметры
---------

     IFBPtr        Указатель файлового блока

     Key           Номер ключа, как в параметре , передаваемом
                   в 

     UserDatRef    Номер записи данных, который будет использован в
                   последующем вызове  при успешном поиске
                   при помощи .

     UserKey       Предшествующий ключ.

Описание
--------

      ищет в индексном файле  следующий  ключ  до
,   отличный   от  него.  Соответствующий  номер  записи
возвращается  в  ,  а  отличный  ключ  в   .
  завершается  неудачно только если такой ключ не
существует ( меньше или равен наименьшему ключу).


Ошибки
------

     9900..9906   Ошибка операционной системы

     10177        Параметр  содержит неверный номер.

     10245        Ключа, меньшего, чем данный, не существует.

     10366        Операция предотвращена запиранием.

Примечания
----------

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


PrevNetKey
-----------------------------------------------------------------
Объявление
----------

     procedure PrevNetKey(IFBPtr : IsamFileBlockPtr;
                       Key : Integer;
                       var UserDatRef : LongInt;
                       var UserKey : IsamKeyStr);


Параметры
---------

     IFBPtr        Указатель файлового блока

     Key           Номер ключа, как в параметре , передаваемом
                   в 

     UserDatRef    Номер записи данных, который будет использован в
                   последующем вызове  при успешном поиске
                   при помощи .

     UserKey       Через этот параметр возвращается предшествующий
                   ключ.

Описание
--------

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

Ошибки
------

     9900..9906   Ошибка операционной системы

     10173        Параметр  содержит неверный номер.

     10260        Предшествующего ключа не существует.

     10265        Последовательный доступ не разрешен.

     10374        Операция предотвращена запиранием.


Примечания
----------

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

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


PutNetRec
-----------------------------------------------------------------
Объявление
----------

     procedure PutNetRec(IFBPtr : IsamFileBlockPtr;
                      RefNr : LongInt;
                      var Souece);

Параметры
---------

     IFBPtr        Указатель файлового блока

     RefNr         Номер записываемой записи данных.

     Source        Запись данных.


Описание
--------

     Записывает запись   данных   назад,    по    ее    исходному
относительному номеру   в   файле   данных,   например  после  ее
модификации.  был получен предыдущей индексной операцией.

Ошибки
------

     9900..9906   Ошибка операционной системы

     10368        Операция предотвращена запиранием.

     10375        Операция разрешена только при запертом сетевом
                  файловым блоке.


Примечания
----------

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

     Эта процедура может быть успешно использована только  в  том
случае, если сетевой файловый блок заперт со степенью 1 или 2.


PutNetRecInSpiteOfLock
-----------------------------------------------------------------
Объявление
----------

     procedure PutNetRecInSpiteOfLock(IFBPtr : IsamFileBlockPtr;
                      RefNr : LongInt;
                      var Source);

Параметры
---------

     IFBPtr        Указатель файлового блока

     RefNr         Номер записываемой записи

     Source        Запись данных

Описание
--------

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

Ошибки
------

     9900..9906   Ошибка операционной системы

     10362        Операция предотвращена запиранием.


Примечания
----------

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

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


SearchNetKey
-----------------------------------------------------------------
Объявление
----------

     procedure SearchNetKey(IFBPtr : IsamFileBlockPtr;
                         Key : Integer;
                         var UserDatRef : LongInt;
                         UserKey : IsamKeyStr);

Параметры
---------

     IFBPtr        Указатель файлового блока

     Key           Номер ключа, как в параметре , передаваемом
                   в 

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

     UserKey       Ключ поиска; через этот параметр будет возвращен
                   найденный соответствующий ключ.

Описание
--------

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

Ошибки
------

     9900..9906   Ошибки операционной системы

     10175        Параметр "Key" содержит неверный параметр.

     10210        Ключ  не найден, и большег ключа не
                  существует.

     10255        Последовательный доступ не разрешен.

     10365        Операция предотвращена запиранием.

Примечания
----------

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


SearchNetKeyAndRef
-----------------------------------------------------------------
Объявление
----------

     procedure SearchNetKeyAndRef(IFBPtr : IsamFileBlockPtr;
                               Key : Integer;
                               var UserDatRef : LongInt;
                               var UserKey : IsamKeyStr);

Параметры
---------

     IFBPtr        Указатель файлового блока

     Key           Номер ключа, как в параметре , передаваемом
                   в 

     UserDatRef    Номер записи данных для ;
                   найденный номер возвращается через эту переменную.

     UserKey       Ключ поиска;
                   найденный ключ возвращается через эту переменную.

Описание
--------

     В индексном    файле    ищется   ключ   ,   которому
соответствует номер записи  .  Если  ключ  найден,  то
последовательный  указатель устанавливается на этот элемент.  Если
же он не найден,  ищется "ближайший" ключ, сканированием сперва в
прямом, а   затем   в   обратном   направлении.   В    и
 будут   возвращены    "соответствующие    заданному"
значения.

Ошибки
------

     9900..9906   Ошибка операционной системы.

     10169        Параметр "Key" содержит неверный номер.

     10255        Последовательный доступ не разрешен.

     10359        Операция предотвращена запиранием.

Примечания
----------

     Данная процедура не предназначена для возврата  адрес  записи
данных по конкретному ключу;  это вы уже должны были понять.  Она,
что более  важно,   позволяет   позиционировать   последовательный
указатель в   середине  блока  идентичных  вторичных  ключей.  Это
особенно полезно при экранном просмотре или создании списков.


SetDosRetry
-----------------------------------------------------------------
Объявление
----------

     function SetDosRetry(NrOfRetries, WaitTime : Integer) : Boolean;

Параметры
---------

     NrOfRetries   Число повторных попыток, которое выполняется в
                   случае недоступности разделяемых ресурсов DOS.

     WaitTime      Время интервала между попытками повторения доступа
                   (в "цикловых задержках").

     Результат     True при удачном завершении, иначе FAlse.

Описание
--------

     Подпрограмма использует функцию DOS $44 для  установки числа
попыток DOS  при  обнаружении  недоступности  разделяемого файла.
Задержка между попытками  устанавливается  в  значение,  заданное
параметром .  Одна "цикловая задержка" равна времени, в
течение которого команда перехода в начало цикла выполнится 65536
раз. Такая задержка для каждой машины имеет свое значение.

      возвращает  True,  если только при возврате из
функции DOS не было обнаружено, что установлен флаг переноса.

Примечания
----------

     При окончании  программы  DOS  не  восстанавливает  исходные
значения данных  параметров.  В  целом,  перед  выходом   в   DOS
прикладная программа  должна  установить  их  сама.  Значения  по
умолчанию для  равны 1, а для  - 3.

     Для работы функции требуется версия DOS 3.1 или старше.


TestSearchForSequential
-----------------------------------------------------------------
Объявление
----------

     procedure TestSearchForSequential(IFBPtr : IsamFileBlockPtr;
                                          Key : Integer;
                                          var TSFS : Boolean);

Параметры
---------

     IFBPtr        Указатель файлового блока

     Key           Номер ключа, как в параметре , передаваемом
                   в 

     TSFS          True, если SearchForSequential разрешает специальный
                   режим поиска, и False в противном случае.

Описание
--------

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

Ошибки
------

     10396      Параметр  содержит неверный номер.


UnlockAllOpenFileBlocks
-----------------------------------------------------------------
Объявление
----------

     procedure UnlockAllOpenFileBlocks;


Описание
--------

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

Ошибки
------

     10340   Неудачная попытка отпирания.

Примечания
----------

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


UnlockFileBlock
-----------------------------------------------------------------
Объявление
----------

     procedure UnlockFileBlock(IFBPtr :IsamFileBlockPtr);

Параметры
---------

     IFBPtr        Указатель файлового блока

Описание
--------

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

Ошибки
------

     10340   Неудачная попытка отпирания.

Примечания
----------

     Вызов данной   процедуры   более  одного  раза  не  является
ошибкой. Сетевой файловый блок останется незапертым.


UnlockRec
-----------------------------------------------------------------
Объявление
----------

     procedure UnlockRec(IFBPtr :IsamFileBlockPtr; Ref : LongInt);

Параметры
---------

     IFBPtr        Указатель файлового блока

     Ref           Номер отпираемой записи.

Описание
--------

     Удаляет существующий   признак   запирания  (степени  3)  из
заданной записи.

Ошибки
------

     10345   Неудачная попытка отпирания.

Примечания
----------

     Очень важно  удалить  все  запирания,  прежде  чам   сетевой
файловый блок   будет   закрыт,   а  программа  завершится.  Если
запирания не удалены,  то многие сети свяжут старые запирания  со
вновь открываемыми файлами.


UsedNetRecs
-----------------------------------------------------------------
Объявление
----------

     function UsedRecs(IFBPtr : IsamFileBlockPtr) : LongInt;

Параметры
---------

     IFBPtr        Указатель файлового блока

     Результат     Число используемых записей данных.

Описание
--------

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

     DatRecordSize(IFBPtr)*(UsedNetRecs(IFBPtr)+FreeNetRecs(IFBPtr)+1)


Ошибки
------

     9900..9906   Ошибка операционной системы.

     10380        Операция предотвращена запиранием.


WSNrLogIn
-----------------------------------------------------------------
Объявление
----------

     procedure WSNrLogIn(WSLogFileName : IsamFileBlockName);

Параметры
---------

     WSLogFileName    Имя DOS  разделяемого файла, в котором
                      находится журнал регистрациии
                      рабочих станций.

Описание
--------

     Данная функция может вызываться,  когда сетевая операционная
система не  обеспечивает   автоматического   метода   определения
уникального номера   рабочей   станции.     должен
задавать полное имя  пути  для  файла,  доступного  всем  рабочим
станциям.   пробует  открыть  этот  файл;  если это не
получается, то файл создается заново.  Номер станции, в диапазоне
от 1    до    ,   присваивается   глобальной
переменной B-Tree   Net   .   Файл   журнала   занимает
 байтов.  Он  закрывается перед возвратом из
.

Ошибки
------

     10401    Не получается запереть .

     10402    Не получается отпереть .

     10403    Выход за пределы номеров рабочих станций.

Примечания
----------

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

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

     Более подробную информацию о номерах рабочих станций  см.  в
разделе 5.С.


WSNrLogOut
-----------------------------------------------------------------
Объявление
----------

     procedure WSNrLogOut(WSLogFileName : IsamFileBlockName);

Параметры
---------

     WSLogFileName    Имя DOS  разделяемого файла, в котором
                      находится журнал регистрациии
                      рабочих станций.

Описание
--------

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

Ошибки
------

     10401    Не получается запереть .

     10402    Не получается отпереть .

Примечания
----------

     Если не  использовать  данную  процедуру,   то   скоро   все
свободные номера  рабочих  станций  будут израсходованы,  что при
очередном вызове    приведет  к  ошибке.   Это   может
случиться при  сбое  операционной системы до выхода из прикладной
программы. Чтобы исправить ситуацию,  просто удалите файл журнала
регистрации при неактивной программе.  Хорошая идея также стирать
файл регистрации  автоматически  в  последовательности   загрузки
сетевой системы.



8. Утилиты B-Tree Filer
-----------------------

     Будучи надстройкой  над мощными подпрограммами B-Tree Filer,
описанными в  предыдущих  главах,   описываемые   здесь   утилиты
работают на   верхнем   уровне,   еще   более  упрощая  написание
прикладных программ,  работающих с базами данных.  Каждая утилита
реализована как  модуль Turbo Pascal,  который может быть в любом
месте программы,  где он понадобится. Модули утилит предназначены
для работы  как  в однопользовательской,  так и в сетевой среде -
независимо от того, какую версию B-Tree Filer вы приобрели.

     Обычно базам данных необходима поддержка  записей переменной
длины. Кроме  всего прочего,  это средство позволяет использовать
"поля памяти" ("memo") (поля  примечаний  переменной  длины),  не
затрачивая на хранение каждого из них памяти по максимуму.

     Другая критическая  способность,  особенно  для  сетевых баз
данных, состоит в  автоматической  очистке  удаленных  записей  и
перепостроении индексов.    Здесь    B-Tree    Filer   использует
преимущества указателей   ппроцедуры   для   построения   ключей,
необходимых для    переиндексации    каждой   записи   во   время
перепостроения.

     Утилита реорганизации  базы  данных  выполняет  также  равно
важные требования  к  возможности  импортирования информации базы
данных из других  форматов  и  модифицирования  структуры  записи
существующих данных.  И  снова  указатели процедуры позволяют вам
настроить в   соответствии    свашими    требованиями    действие
основных подпрограмм реорганизации B-Tree Filer.

     Модуль другой  утилиты  обеспечивает  множество  функций для
манипуляции строками ключей.  Он включает в себя подпрограммы для
преобразования всех   числовых   форматов  в  строки  и  обратно.
Дополнительные подпрограммы упаковывают  и  распаковывают  строки
ключей ASCII, до 38% уменьшая размер индексов.

     И наконец,   какое  средство  разработки  баз  данных  может
обойтись без модуля сортировки?  B-Tree Filer обеспечивает модуль
очень быстрой  виртуальной  сортировки,  эффективно  использующей
обычную оперативную память,  дисковую  память  и  EMS-память  для
сортировки наборов  данных любого размера.  Ввод данных,  вывод и
сравнение выполняются под управлением  подпрограмм  пользователя,
что обеспечивает полную универсальность возможностей сортировки.

А. Записи переменной длины
--------------------------

     Модуль VREC использует остроумный  метод  расширения  B-Tree
Filer для  работы  с  записями  переменной  длины.  Такие  записи
становятся исключительно важными,  когда  базе  данных  требуются
поля примечаний,  так  как  выделение  каждой  записи  памяти  по
максимальному размеру каждого примечания вызывает огромный расход
лишней памяти.

     Для того,  чтобы  обеспечить  поддержку  записей  переменной
длины, в программе выдолжны сначала использовать  (оператор  USE)
модуль Vrec,  а  затем модуль FILER,  от которого зависит первый.
Затем, вместо использования подпрограмм доступа к  записям  FILER
(например, ,    ,    ),    вы   вызываете
аналогичные подпрограммы  из   VREC.   Подпрограммы   FILER   для
управления файловыми   блоками   и   ключами   используются   без
изменений. Подпрограммы доступа к записям VREC  вызываются  почти
так же,  как  и  их аналоги в FILER,  но с добавленным параметром
, который задает или возвращает длину переменной записи.

     Существует и еще одно важное различие. В то время, как ранее
мы  рекомендовали  вам,  чтобы каждая запись данных резервировала
первые четыре байта для использования их B-Tree Filer,  в  случае
использования записей переменной длины мы абсолютно настаиваем на
этом.  Модуль автоматической  реконструкции  базы  данных  B-Tree
Filer  не  станет  работать,  если  эти  четыре  первые  байта не
зарезервированы,  а самостоятельно  выполнить  реконструкцию  вам
будет весьма затруднительно.

     Вот в  чем  состоит  остроумная  идея  VREC:  каждая  запись
переменной длины  состоит  из  серии  более   коротких   "секций"
фиксированной длины.  Модуль  VREC  подразделяет и пересоставляет
затем  записи  переменной   длины  из  таких  секций.  FILER   же
управляет записями фиксированной длины, как обычно.

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

     Как мы должны выбирать длину секции? Одно граничное значение
очевидно: она  не  должна  быть  намного больше,  чем длина самой
короткой записи. Действительно, она должна быть как можно короче,
чтобы дисковое   пространство   использовалось  как  можно  более
эффективно. Соображения   быстродействия,   в    свою    очередь,
накладывают следующее  ограничение:  секция  должна  быть длиннее
одной восьмой от  длины  самой  длинной  записи  (чтобы  избежать
чтения слишком   большого  числа  секций  для  образования  одной
записи). И наконец,  учтем,  что VREC резервирует в каждой секции
область для  своего  собственного использования.  В каждой записи
эти затраты памяти составляют 6 байтов на первую секцию  и  по  7
байтов на все остальные.

     Следующий пример  позволяет сделать вопрос яснее. Представим
себе, что у нас  имеется  прикладная  программа  с  фиксированным
минимальным размером записи, равным 114 байтам (признак удаления,
имя, компания,  адрес,  телефон,  номер клиента и т.д.).  К конце
каждой записи  мы  должны  добавить  примечания,  имеющие длину в
диапазоне от 1 до 250 байтов (точно совпадая с  возможной  длиной
строки Turbo  Pascal).  Следовательно,  размер  наибольшей записи
составит 364 байта.

     Ниже приводятся  два  обоснованных  варианта  выбора   длины
разделов:

секции по 64 байта
  минимальное число секций: 2 (полное заполнение: 114+1+6+7+128)
  максимальное число секций: 7 (и 36 байтов еще доступны)
секции по 128 байтов
  минимальное число секций: 1 (и 7 байтов еще доступны)
  максимальное число секций: 3 (полное заполнение)

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

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

     При использовании  записей  переменной  длины   подпрограммы
B-Tree Filer   ,      и     не
возвращают значений,  которые можно использовать непосредственно.
Как вы могли предположить, они возвращают значения, основанные на
фиксированной длине секции.  Тем не менее,  возвращаемые значения
тем не  менее  полезны  для  вычисления  фактических требований к
дисковой памяти. Модуль VREC содержит замену для :
 возвращает   фактическую   длину  заданной
записи.

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

     1. Инициализация   сети   вызовом       (только
многопользовательская версия).

     2. Создание страничного буфера вызовом .

     3. Открытие  или  создание  одного или более файловых блоков
вызовом  и т.д.

     *. Создание  буфера   записей   переменной   длины   вызовом
 или .

     4. Использование подпрограмм  B-Tree  Filer,  B-Tree  Net  и
VREC.

     5. Закрытие    всех   открытых   файловых   блоков   вызовом
 или .

     *. Освобождение  буфера  записей  переменной  длины  вызовом
.

     6. Освобождение страничного буфера вызовом .

     7. Выход из B-Tree Filer путем вызова . (Только
многопользовательская версия).

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

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

     1. Открытие файлового блока

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

     2. Операции с файлом данных

     При добавлении,  удалении или обновлении записей используйте
подпрограммы, экспортируемые    модулем   VREC,   а   не   FILER.
Соответствия между ними указаны в следующей таблице:


            Фиксированная длина                Переменная длина
Однопользовательская   Многопользовательская   Одно- или много-
                                               пользовательская
--------------------   ---------------------   ----------------
     AddRec                 AddNetRec          AddVariableRec
     DeleteRec              DeleteNetRec       DeleteVariableRec
     GetRec                 GetNetRec          GetVariableRec
     PutRec                 PutNetRec          PutVariableRec

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

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

     3. Операции с индексным файлом

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

     4. Экранный просмотр файлового блока

     Модуль BROWSER   (описаннный   в   разделе  8.В),  позволяет
экранный просмотр записей как  фиксированной,  так  и  переменной
длины. Не забывайте установить параметр  функции 
в значение  True  для  записей  переменной  длины  и  в  False  в
противном случае.

     5. Перепостроение или реорганизация файлового блока

     Для записей   переменной   длины  предназначены  специальные
версии REBUILD и REORG. Не забудьте, что их имена в этом случае -
VREBUILD и VREORG.

Идентификаторы VREC
-------------------

     В данном разделе описаны все  идентификаторы, экспортируемые
модулем VREC.

Типы
----

     IsamAccessMode = (Normal, InSpiteOfLock, ReadOnly);

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


AddVariableRec
-----------------------------------------------------------------
Объявление
----------

     procedure AddVariableRec(IFBPtr : IsamFileBlockPtr;
                      var RefNr : LongInt;
                      var Source;
                      Len : Word);

Параметры
---------

     IFBPtr        Указатель файлового блока.

     RefNr         Позиция в файле данных, куда была записана запись
                   данных (относительный номер записи в файле);
                   используется для добавления индекса при помощи
                   .

     Source        Добавляемая запись данных.

     Len           Фактическая длина записи.

Описание
--------

      используется для добавления записи данных в
файл данных.  Запись дописывается в конец файла данных, если файл
не  имеет  удаленных  элементов;  в  противном  случае  одна   из
удаленных при помощи  записей замещается новой
и используется повторно.  Будущие ссылки  на  эту  запись  данных
выполняются   посредством    типа  LongInt,  возвращаемого
.

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

Ошибки
------

     9900..9906   Ошибки операционной системы

     10001        (Только в режиме сохранности). Операция была
                  абортирована вследствие суровой ошибки ввода/
                  вывода. Реконструкция файловых блоков не нужна,
                  поскольку "ремонт" был выполнен успешно.

     10369        Операция предотвращена запиранием.

     10376        Операция разрешена только при запертом
                  сетевом файловом блоке.

Примечания
----------

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


CreateVariableRecBuffer
-----------------------------------------------------------------
Объявление
----------

     function CreateVariableRecBuffer(IFBPtr : IsamFileBlockPtr) :
                                      Boolean;

Параметры
---------

     IFBPtr        Указатель файлового блока


Описание
--------

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

Примечания
----------

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


DeleteVariableRec
-----------------------------------------------------------------
Объявление
----------

     procedure DeleteVariableRec(IFBPtr : IsamFileBlockPtr;
                                 RefNr : LongInt);

Параметры
---------

     IFBPtr        Указатель файлового блока.

     RefNr         Номер удаляемой записи.

Описание
--------

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

Ошибки
------

     9900..9906   Ошибки операционной системы

     10002        (Только в режиме сохранности). Операция была
                  абортирована вследствие суровой ошибки ввода/
                  вывода. Реконструкция файловых блоков не нужна,
                  поскольку "ремонт" был выполнен успешно.

     10370        Операция предотвращена запиранием.

     10377        Операция разрешена только при запертом
                  сетевом файловом блоке.

Примечания
----------

     Удалены могут   быть   только   существующие  записи  данных.
Удаление уже удаленной записи запортит внутренний  связный  список
удаленных записей   данных,   что   приведет   к   непредсказуемым
результатам. Когда  запись  удалена,  B-Tree  Filer  устанавливает
первые четыре  байта  записи  в  ненулевое  значение.

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


GetVariableRec
-----------------------------------------------------------------
Объявление
----------

     procedure GetVariableRec(IFBPtr : IsamFileBlockPtr;
                      RefNr : LongInt;
                      var Destination;
                      var Len : Word;
                      Mode : IsamAccessMode);

Параметры
---------

     IFBPtr        Указатель файлового блока

     RefNr         Номер читаемой записи

     Destination   Возвращаемая запись данных

     Len           Фактическая длина возвращаемой записи данных

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

Описание
--------

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

Ошибки
------

     9900..9906   Ошибка операционной системы

     10363        Операция предотвращена запиранием.


Примечания
----------

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


GetVariableRecLength
-----------------------------------------------------------------
Объявление
----------

     procedure GetVariableRecLength(IFBPtr : IsamFileBlockPtr;
                      RefNr : LongInt;
                      var Len : Word);

Параметры
---------

     IFBPtr        Указатель файлового блока

     RefNr         Номер записи, длина которой будет возвращена

     Len           Возвращаемая фактическая длина записи данных


Описание
--------

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

Ошибки
------

     9900..9906   Ошибка операционной системы


GetVariableRecPart
-----------------------------------------------------------------
Объявление
----------

     procedure GetVariableRecPart(IFBPtr : IsamFileBlockPtr;
                      RefNr : LongInt;
                      var Destination;
                      Len : Word;
                      Mode : IsamAccessMode);

Параметры
---------

     IFBPtr        Указатель файлового блока

     RefNr         Номер читаемой записи

     Destination   Возвращаемая запись данных

     Len           Число читаемых байтов

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

Описание
--------

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

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

Ошибки
------

     9900..9906   Ошибка операционной системы

     10363        Операция предотвращена запиранием.


Примечания
----------

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


PutVariableRec
-----------------------------------------------------------------
Объявление
----------

     procedure PutVariableRec(IFBPtr : IsamFileBlockPtr;
                      RefNr : LongInt;
                      var Source;
                      Len : Word;
                      Mode : IsamAccessMode);

Параметры
---------

     IFBPtr        Указатель файлового блока

     RefNr         Номер записываемой записи данных.

     Source        Запись данных.

     Len           Фактическая длина записи данных

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


Описание
--------

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

Ошибки
------

     9900..9906   Ошибка операционной системы

     10368        Операция предотвращена запиранием.

     10375        Операция разрешена только при запертом
                  сетевом файловом блоке.


Примечания
----------

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

     В сетевой  программе  данная  процедура  может  быть вызвана
успешно только если сетевой файловый блок был заперт  со степенью
1 или  2.


ReleaseVariableRecBuffer
-----------------------------------------------------------------
Объявление
----------

     procedure ReleaseVariableRecBuffer;

Описание
--------

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


SetVariableRecBuffer
-----------------------------------------------------------------
Объявление
----------

     function SetVariableRecBuffer(Size : Word) : Boolean;

Параметры
---------

     Size    Размер создаваемого буфера.


Описание
--------

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

Примечания
----------

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


Управление файловым блоком с переменной длиной записей
------------------------------------------------------

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

     Процедура  из модуля  VREBUILD вызывается
для перепостроения   файлового   блока   переменной   длины.  Она
конструирует новые файлы данных и  индексов  из  исходного  файла
данных. Такая  возможность существует только если в каждой записи
первые четыре байта зарезервированы  для  маркера  удаления.  При
этом   работает несколько больше,  чем обычно,
поскольку ей  приходится  воссоединять   секции   каждой   записи
переменной длины.   Чтобы   решить   эту  проблему,  модуль  VREC
экспортирует добавочную  процедуру.  Хотя  она  предназначена   в
основном для  внутреннего  применения,  вы  может  найти  для нее
дополнительные применения.



GetVariableRecRebuilt
-----------------------------------------------------------------
Объявление
----------

     procedure GetVariableRecRebuilt(var F : IsamFile;
                                     DatSLen : Word;
                                     var RefNr : LongInt;
                                     OnlyLen : Boolean;
                                     var Destination;
                                     var Len : Word);

Параметры
---------

     F             Реконструируемый файл "сырых" данных

     DatSLen       Длина записи, задаваемая в 
                   (длина секции)

     RefNr         Последняя искомая секция, обновляемая после
                   возврата

     OnlyLen       При значении True подпрограмма возвращает только
                   длину записи. Иначе она копирует запись в
                   Destination.

     Destination   Реконструируемая запись данных

     Len           Фактическая длина записи данных.


Описание
--------

      ищет  в открытом файле  следующую
достоверную запись данных.  Каждый вызов  
начинает поиск с позиции +1. Следовательно,  должен
содержать при первом вызове значение 1, так чтобы поиск начался с
начала файла.   Если   найдена  достоверная  запись  данных,  она
копируется в  ,  в  случае,  когда    имеет
значение False.   Затем      устанавливается   в  значение
финальной секции,  которое может далее служить  начальной  точкой
при следующем  вызове  .  Длина  найденной
записи данных возвращается в .  Если больше  записей  данных
для поиска  не имеется,   содержит значение 0,  обозначающее
завершение процесса.

     Если параметр   равен  True,  то  запись  данных  в
 не  копируется,  а возвращается только длина записи
данных. В этом случае также не изменяется значение  . Этот
метод позволяет определить ожидаемый размер записи данных.

Ошибки
------

     9900..9906   Ошибка операционной системы



B. Экранный просмотр
--------------------

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

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

     Для использования  BROWSER в вашей программе просто добавьте
соответствующее имя в оператор USES.  BROWSER  также  зависим  от
следующих модулей:  CRT,  DOS,  FILER и VREC. Если вы используете
модуль Turbo  Professional  TPCRT,  не  забудьте  отредактировать
BTDEFINE.INC и  активизировать условную директиву определения Use
TPCRT.

     Способ, которым  BROWSER  обрабатывает  команды,  реализован
аналогично модулям  Turbo  Pascal  5.0  типа  TPPICK,  TPENTRY  и
другим. Конфгурируемая таблица команд определена  таким  образом,
чтобы отображать   нажатия  клавиш  для  логических  команд  вида
"перейти к следующей записи". Хотя эта таблица инициализируется в
приемлемые значения  по  умолчанию,  прикладная  программа  может
модифицировать ее   во   время   выполнения    для    специальных
возможностей. Более   подроюное  описание  см.  ниже,  в  разделе
"Обработка сигналов клавиатуры в BROWSER".

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

Идентификаторы BROWSER
----------------------

     Данный раздел описывает все  идентификаторы,  экспортируемые
модулем BROWSER.

Константы
---------

     BKnone        = 00; {Не является командой}
     BKchar        = 01; {Обычный символ - не является командой}
     BKenter       = 02; {Выбор}
     BKquit        = 03; {Escape}
     BKfirstRec    = 04; {Курсор на первую запись}
     BKlastRec     = 05; {Курсор на последнюю запись}
     BKleft        = 06; {Курсор влево на один столбец}
     BKright       = 07; {Курсор вправо на один столбец}
     BKup          = 08; {Курсор вверх на одну строку}
     BKdown        = 09; {Курсор вниз на одну строку}
     BKpageUp      = 10; {Курсор вверх на одну страницу}
     BKpageDown    = 11; {Курсор вниз на одну страницу}
     BKplus        = 12; {Повторение чтения текущей записи}
     BKhelp        = 13; {Вызов подпрограммы-справки}
     BKtask0       = 14; {Определяемые пользователем команды задач}
     ...
     BKtask9       = 23;
     BKuser0       = 24; {Определяемые пользователем команды выхода}
     ...
     BKuser9       = 33;

     Это коды  для  каждой  команды BROWSER перемещения курсора и
выбора. Большинство из них говорят сами за себя. Команда 
активируется при   каждом   нажатии   .   Если   была  задана
подпрограмма-справка, определяемая  пользователем,  то   в   этот
момент вызывается она. ... могут быть назначены
последовательностям нажатий клавиш,  заставляющих BROWSER при  их
нажатии вызывать     определяемые    пользователем    подпрограмм
специальных задач.       Нажатия       клавиш,        назначенные
..., вызывают выход из утилиты просмотра. Затем
прикладная программа  может  рассмотреть  возвращаемый   параметр
 для определения предпринимаемого действия.

     MaxCols = 128;

     Задает максимальную   ширину   однострочной  форматированной
записи, выводимой утилитой на дисплей. Она может превышать ширину
физического экрана  при  условии,  что определяемые пользователем
подпрограммы поддерживают горизонтальный  скроллинг. Максимальное
значение равно 255.  Данная константа,  в комбинации с ,
определяет использование доминантное использование  области стека
функцией . Для значений по умолчанию   использует
иногда менее 4000 байтов области стека.

     MaxRows = 20;

     Задает самое большое по высоте окно,  разрешенное  утилитой.
Если фактическое  окно  (заданное  при вызове ) выше,  то
BROWSER ограничит  его   высоту   значением   .   Данная
константа определяет  размер  переменной,  локальной относительно
функции .  Она  должна  быть   достаточно   мала,   чтобы
помещаться на физическом экране (обычно меньше или равна 25).

     MinRows = 4;

     Задает наименьшую  высоту окна,  разрешенную утилитой.  Если
фактическое окно (заданное в вызове ) короче,  то BROWSER
увеличит высоту  до  .  BROWSER  не  предназначается  для
работы с меньшими значениями ,  и  поэтому  единственная
опция состоит здесь в том, чтобы сделать их больше.

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

     RetriesOnLock : Integer = 50;

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

Типы
----

     BKType = BKnone..BKuser9;

      определяет класс  действия,  выполняемого  утилитой
просмотра. Сюда  входят  такие действия,  как перемещение курсора
вверх и вниз,  выбор элемента и выход из  утилиты.  Подробно  они
описаны для вышеперечмсленных констант.

     RowRec =
       record
         IKS : IsamKeyStr;      {Ключ записи}
         Ref : LongInt;         {Относительный номер записи}
         Row : String[MaxCols]; {Строка, выводимая на дисплей,
                                 в зависимости от содержимого
                                 записи}
       end;

     BROWSER использует этот тип для управления выводом записи на
дисплей. Функция    объявляет  массив из ,  части
которого она инициализирует сама, а другие части инициализируются
подпрограммами прикладной   программы.   В   частности,  
инициализирует поля      и   .   Затем   она   вызывает
определяемую пользователем  подпрограмму,  на  которую  указывает
, вычисляющая строку .  И  наконец,  
вызывает другие   определяемые   пользователем  подпрограммы,  на
которые указывает ,  выводящая строку    на
экран. Подробности см. ниже.

Переменные
----------

     BrowseHelpIndex : Word;

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

     BrowseHelpPtr : Pointer;

     Указывает на подпрограмму, которая будет вызвана при нажатии
ключа запроса справки. По умолчанию этот указатель пустой (nil) и
никаких действий не происходит. Подробности см. ниже.

     BrowseKeyPtr : Pointer;

     Указывает на  подпрограмму,  которая во время работы утилиты
читает каждое нажатие клавиши.  По умолчанию  указывает  либо  на
BrowseReadKey, либо    на    Turbo    Professional   ReadKeyWord,
подпрограммы, возвращающие как  скэн-код,  так  и  символ  ASCII.
Прикладная программа   может   установить   указатель  на  другую
подпрограмму, возвращающую клавишу и возможно, выполняет во время
ожидания ввода некоторые фоновые задачи.  Подробности см. ниже, в
разделе "Обработка сигналов с клавиатуры в BROWSER".


AddBrowseCommand
-----------------------------------------------------------------
Объявление
----------

     function AddBrowseCommand(Cmd : BKtype;
                               NumKeys : Byte;
                               Key1, Key2 : Word) : Boolean;

Параметры
---------

     Cmd       Код команды, назначаемый заданным клавишам.

     NumKeys   Число нажатий клавиш команды (1..2).

     Key1      Первое нажатие клавиши для данной команды.

     Key2      Второе нажатие клавиши для данной команды.

     Результат True, если команда модифицирована успешно, иначе False

Описание
--------

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

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

     Status := AddBrowseCommand(BKuser0, 1, $5300, 0);

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

     Второй параметр задает, сколько нажатий клавиш соответствует
данной команде.  Допустимые значения данного параметра ограничены
значениями 1 и 2.  Число 2 задается в том случае, если вы хотите,
чтобы пользователь нажимал некоторые комбинации в стиле WordStar,
например  . В данном примере  это одно нажатие
клавиши,  поэтому  мы  задаем  значение  1.  Скэн-код и ASCII-код
клавиши  находятся в следующем  параметре;  эти  коды  можно
найти в Руководстве по Turbo Pascal.  Последний параметр в данном
случае игнорируется,  поскольку  равен 1. Иначе бы здесь
находился второй код.

      может  возвратить False по трем причинам:
если таблица отображения команд уже  полна  (она  может  суммарно
хранить до  200  нажатий  клавиш для всех команд);  если значение
 не равно 1 или  2;  или  если  новая  последовательность
нажатий клавиш   приведет  к  неоднозначности  интерпретации  уже
существующей команды.  После отладки программы 
должна всегда возвращать True.

     Та же  методика  применяется  для  использования  в 
подпрограммы для специальной задачи.  В  этом  случае  вы  можете
выбрать код команды в диапазоне ...

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

     Status := AddBrowseCommand(BKnone,1,$4800,0); {Отмена }
     Status := AddBrowseCommand(BKnone,1,$5000,0); {Отмена }

     Код команды  это  специальное  значение,  означающее,
что "в случае нажатия данной клавиши никаких действий выполняться
не должно",  т.е. что нажатие этой клавиши игнорируется. И снова,
каждой команде соответствовало по одному нажатию,  а их скэн-коды
мы взяли в Руководстве по Turbo Pascal.

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

     Status := AddBrowseCommand(BKpageDown,1,$7600,0);
     Status := AddBrowseCommand(BKpageUp,1,$8400,0);

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

     Более подробное  описание  настройки  клавиатуры  для модуля
BROWSER см.  ниже,  в разделе "Обработка сигналов с клавиатуры  в
BROWSER".


Browse
-----------------------------------------------------------------
Объявление
----------

     function Browse(IFBPtr : IsamFileBlockPtr;
                     VarRec : Boolean;
                     KeyNr : Integer;
                     LowKey : IsamKeyStr;
                     HighKey : IsamKeyStr;
                     StartScreenRow : Integer;
                     NrOfRows : Integer;
                     var DatS;
                     var DatLen : Word;
                     var Ref : LongInt;
                     var KeyStr : IsamKeyStr;
                     var ExitKey : BKtype;
                     ProcSpecialTask : Pointer;
                     ProcBuildaRow : Pointer;
                     ProcDisplayaRow : Pointer) : Integer;

Параметры
---------

     IFBPtr          Указатель файлового блока.

     VarRec          True, если файловый блок имеет записи переменной
                     длины; иначе False.

     KeyNr           Номер ключа, по которому выбирается
                     последовательность вывода на дисплей.

     LowKey          Наименьший выводимый на дисплей ключ.

     HighKey         Начало наибольшего выводимого ключа.

     StartScreenRow  Номер первой строки экрана, с которой будут
                     выводиться записи

     NrOfRows        Число строк для вывода записей.

     DatS            Буфер для возврата выбранной записи данных.

     DatLen          Возвращаемая длина записи переменной длины.

     Ref             Номер записи, высвечиваемой первоначально.
                     Возвращает номер выбранной записи.

     KeyStr          Первоначально высвечиваемый ключ.
                     Возвращает выбранный ключ.

     ExitKey         Первоначально выполняемая функцией команда.
                     Возвращает команду выхода.

     ProcSpecialTask Указатель процедуры специальной задачи
                     SpecialTask, либо пустой указатель (Nil).

     ProcBuildaRow   Указатель процедуры BuildaRow.

     ProcDisplayaRow Указатель процедуры DisplayaRow.

     Результат       0 Удачное завершение.
                     1 Ключи заданного диапазона  не доступны.
                     2 Суровая ошибка из FILER (IsamErrorClass >= 2).


Описание
--------

      указывает на открытый файловый блок.  Файловый блок
может быть  открыт  как   однопользовательский,   сетевой   и/или
переменной длины.   должен быть равен True, если файловый
блок содержит  записи  переменной  длины,  и  False  в  противном
случае.     задает,   какие   индексы   использовать   для
упорядочения записей при их выводе на экран.

     Утилита выведет на дисплей все ключи в диапазоне от 
до ,   включительно.   Отметим,   как   интерпретируется
. Если,  например,   равен 'SMITH",  то в  окне
просмотра появятся следующие записи: 'SMIT', 'SMITH', 'SMITHERS',
'SMITHSON'. Если задать для  'SMITH'#0, то последние две
записи не появятся.

     Комбинация    и    задает  первую  выводимую  и
высвечиваемую запись.  Если  меньше  ,  то  будет
выведена первая запись, большая или равная LowKey>. Если 
больше ,  то первым будет высвечен наибольший  доступный
ключ.

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

      задает  номер  строки  экрана,  в   которой
появится  первая  запись,  а   - это число одновременно
видимых записей.  Если величина  меньше чем  ,
она будет увеличена до этого значения.  Аналогичным образом, если
величина  превысит , то она будет уменьшена до
этого значения.

      и     являются  указателями
процедур, используемых для создания и вывода на  дисплей  строки,
соответственно. Эти   процедуры   обеспечиваются   в   прикладной
программе, и они  обязаны  иметь  заголовок  того  же  типа,  что
показан в  следующих примерах.  Более того,  эти процедуры должны
быть объявлены с моделью памяти при компиляции FAR (дальняя) и не
должны быть   вложенными   в   другие   процедуры.   Модель   FAR
активизируется при помощи директивы компилятора {$F+}.

     Процедура, адрес  которой  передается  в  ,
будет вызываться при нажатии клавиш,  назначенных командным кодам
от  до .  Если никакие  специальные  задачи  не
нужны, то  в  этом  параметре  нужно  передать значение nil.  При
использовании  этот указатель  должен  указывать
на процедуру,   заголовок   которой   в   точности  соответствует
показанному ниже в примерах и которая  компилируется  для  модели
памяти FAR.

     Код кманды,  вызывающей  выход  из ,  возвращается в
. В  этом  параметре  также  задается  первое  действие,
выполняемое   при входе.  Если это действие не требуется,
то параметр  должен быть инициализирован в (=0).

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

     Когда  возвращает нулевой код  успешного завершения,
значение   может  быть  проверено  для определения того,
какое действие должно быть дальше выполнено.  Если    <>
 (была  нажата  любая клавиша выхода,  кроме Escape>,  то
 содержит выбранную  запись  данных,    -  номер  этой
записи, а  содержит ее строку ключа.  Если же  =
, все эти параметры остаются неопределенными.

Примечания
----------

      не очищает экран при входе и не восстанавливает его
при выходе. За эти действия отвечает вызывающая программа.

     Практический пример  использования  модуля  BROWSER  см.   в
NETDEMO.PAS.


BrowseReadKey
-----------------------------------------------------------------
Объявление
----------

     function BrowseReadKey : Word;

Параметры
---------

     Результат     Слово скэн-кода для нажатия клавиши.


Описание
--------

     Ожидает нажатия клавиши  и  затем  возвращает  ее  код.  Для
обычных нажатий  клавиш  (например,  буква 'a'),  
возвращает обычный ASCII-код символа ($61 для 'a').  В случае  же
расширенных нажатий  клавиш  она  возвращает  слово со скэн-кодом
клавиши в старшем байте и нулем в младшем байте  (например, $4800
для стрелки  "Вверх").  Эти  значения  возврата  не  противоречат
способу, которым  сама считывает клавиши.

     Данная функция   взаимодействует   с   BROWSER,   так    что
определяемые программистом  фоновые  задачи могут вызывать ее для
базового ввода с клавиатуры. Более подробную информацию см. ниже,
в "Обработка сигналов с клавиатуры в BROWSER".

BuildaRow
-----------------------------------------------------------------
Объявление  (при желании имя можно изменить)
----------

     procedure BuildaRow(var RR : RowRec;
                         KeyNr : Integer;
                         var DatS;
                         DatLen : Word);

Параметры
---------

     RR       RowRec, тип, описанный выше.

     KeyNr    Номер активного ключа.

     DatS     Запись данных для вывода на дисплей.

     DatLen   Длина записи переменной длины.

Описание
--------

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

     При входе в  поле   уже  инициализировано
ключевой  строкой  текущей записи,  а поле RR.Ref> содержит номер
текущей записи. Параметр  содержит полную запись данных.

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

Примечания
----------

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


DisplayaRow
-----------------------------------------------------------------
Объявление  (при желании имя можно изменить)
----------

     procedure DisplayaRow(var RR : RowRec;
                         KeyNr : Integer;
                         RowNr : Integer;
                         StartRow : Integer;
                         HighLight : Boolean;
                         var HorizOfs : Integer);

Параметры
---------

     RR         RowRec, тип, описанный выше.

     KeyNr      Номер активного ключа.

     RowNr      Относительный номер строки экрана.

     StartRow   Номер первой строки вывода.

     HighLight  True для текущей выбранной строки; иначе False.

     HorizOfs   Задаетзапрошенный горизонтальный скроллинг.
                После возврата может быть модифцирован.

Описание
--------

     Процедура этого  типа  вызывается  из    для  вывода
записи на дисплей после ее форматирования в  .  Модуль
BROWSER  определяет  подпрограмму  просто как пример
такого рода процедур.  Вовсе не имеется в  виду,  что  вы  будете
реально  вызывать  ее  из  своей  программы,  и фактически она не
использует кодового пространства вашей программы. Написанная вами
вместо  нее подпрограмма должна быть глобальной и компилироваться
для модели памяти FAR.

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

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

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


SpecialTask
-----------------------------------------------------------------
Объявление  (при желании имя можно изменить)
----------

     procedure SpecialTask(IFBPtr : IsamFileBlockPtr; var DatS;
                           Ref : LongInt; IKS :AsamKeyStr;
                           KeyNr : Integer; var Command : BKType;
                           var ExitCode : Integer; DatLen : Word);

Параметры
---------

     IFBPtr        Указатель файлового блока

     DatS          Активная запись данных

     Ref           Номер активной записи

     IKS           Активная ключевая строка

     KeyNr         Номер ключа по которому упорядочивается вывод

     ExitCode      Код, передаваемый обратно в 

     DatLen        Длина записи переменной длины.


Описание
--------

     Процедура этого типа вызывается    при  нажатии  там
одной  из  клавиш  специальной задачи.  Модуль BROWSER определяет
подпрограмму    просто  как   пример   такого   рода
процедур. Вовсе не имеется в виду, что вы будете реально вызывать
ее из своей программы,  и фактически она не  использует  кодового
пространства   вашей   программы.   Написанная  вами  вместо  нее
подпрограмма должна быть глобальной и компилироваться  для модели
памяти FAR.

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

      содержит код команды,  которая  привела  к  вызову
данной прецедуры.  Он  может  принимать  значения от  до
. Этот параметр также имеет  важный  специальный  смысл.
Его значение  после  возврата  из   определяет,  что
 должен  сделать  следующим  действием.  Например,   если
специальная задача определяет, что  должен после возврата
из нее выполнить переход на страницу вниз (),  то 
должен содержать  при выходе .  Если никаких действий
не требуется, то не забудьте перед выходом установить  в
(=0). Соответствующее   использование  команды  
позволяет также  циклические  вызовы  специальной  задачи.   Этим
параметром нужно пользоваться аккуратно.

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

Примечания
----------

     Из специальной   задачи   даже  возможен  рекурсивный  вызов
 (например,  для просмотра второго,  связанного с  данным
файлового блока).   Если   это   требуется,  убедитесь,  что  для
рекурсивного вызова  достаточно  места  в  стеке.  По   умолчанию
 использует  около  4000  байтов  стека на один экземпляр
вызова.


Обработка сигналов с клавиатуры в BROWSER
-----------------------------------------

     Утилита экранного  просмотра  предлагает  несколько   мощных
механизмов   подключения   процедуры   пользователя   посредством
передачи ее указателя ("hook") для настройки  своих  операций  по
умолчанию.  Эти средства моделируются по типу впервые введенных в
Turbo Professional 5.0,  поэтому если  вы  знакомы  с  обработкой
сигналов  с  клавиатуры  TPENTRY  или  TPEDIT,  то  мощь сресттв,
предлагаемых  утилитой  просмотра,  легко  оценить.  В  противном
случае прочтите следующий материал.

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

     Механизмы подключения  инсталлируемой   клавиатуры   BROWSER
доступен посредством  функции  ,  уже описанной
выше. Эта функция читает и модифицирует типированную  константу -
байтовый массив,    в   котором   хранятся   соответствия   между
логическими командами  и  последовательностями  нажатий   клавиш.
Массив BROWSER называется  и может содержать до 201
байта такой  информации  о   соответствиях.   По   умолчанию   он
конфигурирован в  соответствии  с  привычными  представлениями  о
функциях клавиатуры для просмотра списка  записей,  а  также  для
поддержки команд типа WordStar.  См. описание ,
где указывается,  как нужно модифицировать этот список команд  во
время работы программы. Для значительных модификаций этого списка
команд существуют две другие опции.  Первая состоит в том,  чтобы
просто модифицировать желаемым образом сам исходный код BROWSER и
задать там все  нужные  клавиши.  Вторая  состоит  в  том,  чтобы
написать программу  инсталляции,  которая  будет  находить список
по идентифицирующей строке,  гарантированно  расположенной  перед
таблицей. Здесь такая программа не рассматривается; см. примеры в
Borland EditorToolbox и Turbo Professional (TPKEYS  в  директории
BONUS).

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

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

     {$F+}
     function MyReadKey : Word;
     begin
       while not KeyPressed do begin
         inline($CD/$28); {Разрешить работу резидентной программе}
         {** Здесь идет выполнение фоновой задачи **}
       end;
       MyReadKey := BrowseReadKey;
     end;
     {$F-}

     Данная функция  должна  компилироваться с моделью FAR и быть
глобальной (не  вложенной  в  любые  другие  подпрограммы).  Цикл
KeyPressed опрашивает  нажатие клавиш и предоставляет возможность
непрерывно выполнять    фоновую    задачу.    Оператор     inline
необязателен, но  иногда он необходим,  чтобы дать возможность во
время ожидания ввода с клавиатуры работать резидентной программе.
Разумеется, сама  фоновая задача должна выполняться быстро, иначе
сам ввод с клавиатуры станет очень замедленным.

     Для активации фоновой задачи присвойте адрес  вашей  функции
переменной BROWSER , например

     BrowseKeyPtr := @MyReadKey;

     Активация механизма  подключения контексто-зависимой справки
представляет собой аналогичный процесс.  При нажатии  BROWSER
проверяет, имеет  ли указатель  значение nil. Если
имеет, то клавиша   игнорируется.  Если  нет,  то  вызывается
подпрограмма с   указанным   адресом.   (Разумееется,  назначение
клавиши  само  может  быть  изменено  механизмом  подключения
инсталлируемой клавиатуры).

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

     {$F+}
     procedure HelpRoutine(UnitCode : Byte; IdPtr : Pointer;
                           HelpIndex : Word);
     begin
     end;
     {$F-}

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

     При вызове  такой  подпрограммы  из  BROWSER параметры имеют
специальный смысл.  Первый параметр всегда будет  иметь  значение
, равный  7.  Это  указывает  на  то,  что  запрос
справки пришел из утилиты просмотра базы данных. Второй параметр,
, устанавливается    равным   указателю   просматриваемого
файлового блока. Третьему параметру, , будет присвоено
значение из    ,   переменной,   устанавливаемой
прикладной программой       перед        вызовом        .
Подпрограмма-справка может  принять  решение  относительно  того,
какая именно справка нужна,  в зависимости  от  этих  параметров.
За вывод  справки на экран отвечает прикладная программа;  если у
вас есть Turbo Professional,  то модуль TPHELP идеален  для  этой
задачи.

     Для активации  механизма подключения справки присвойте адрес
вашей процедуры переменнов  BROWSER,например:

     BrowseHelpPtr := @HelpRoutine;



C. Перепостроение поврежденного файлового блока
-----------------------------------------------

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

     B-Tree Filer,  в отличие от некоторых других СУБД, может как
минимум обнарудивать   такого   рода   повреждения.   Во    время
буферизации данных B-Tree Filer записывает флаг, который остается
установленным до тех пор,  пока буферы  не  будут  гарантированно
сброшены на  диск  (при закрытии файлового блока).  Если в момент
открытия файлового блока оказывается,  что такой флаг установлен,
B-Tree Filer   возвращает   код  ошибки  10010,  означающую,  что
файловый блок должен быть "перестроен".

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

     Имеются и  другие  ситуации,  когда  такая  операция   может
оказаться полезной:

     - Многие  записи  были  удалены,  а добавление значительного
числа новых записей не ожидается. в этом случае мы называем такое
перепостроение "чисткой",  поскольку оно удаляет из файлов данных
и индексов неиспользуемое пространство.

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

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

     Для того,  чтобы использовать подпрограммы перепостроения  в
программе, добавьте  в  оператор  USES  имена  блоков REBUILD или
VREBUILD после имени модуля FILER,  от  которого  завися  от  оба
первых модуля. (VREBUILD зависит также от модуля VREC).

     Отметим, что   реконструкция  возможна  только  если  первые
четыре байта каждой записи данных резервированы для использования
B-Tree Filer  и были инициализированы нулем при первом добавлении
файла в базу данных.  Мы все время говорили об этом в руководстве
- надеемся,  это не застанет вас врасплох,  когда вы в первый раз
захотите выполнить перепостроение.

     Побочно мы должны отметить, что существуют и другие способы,
используемые иногда  для  обозначения  удаляемых  записей данных.
Один из таких методов состоит  в  принудительном  обнулении  всех
полей записи в целом (за
исключением ее  первых  четырех  байтов),  когда  она должна быть
удалена. Это   выполняется   последовательностью:    ,
, обнуление  полей,  .  Во  время  перепостроения
удаленные записи распознаются по нулевым полям. Такой метод имеет
преимущество дополнительной безопасности данных: удаленные записи
в этом случае полностью уничтожаются. Модуль B-Tree Filer REBUILD
не поддерживает такого метода;  однако,  вы  можете  использовать
модуль REORG, описанный в разделе 8.D, чтобы перестроить файловый
блок, где каждая запись  не  помечается  первоначально  нулем,  а
вместо этого вся запись, до конца, стирается, как было описано.


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


Идентификаторы REBUILD и VREBUILD
---------------------------------

     В данном разделе описаны все  идентификаторы, экспортируемые
модулями REBUILD и VREBUILD.  Подпрограммы этих модулей настолько
близки друг к другу, что описываются попарно.


RebuildFileBlock/RebuildVFileBlock
-----------------------------------------------------------------
Объявление
----------

     procedure RebuildFileBlock(FBlName : IsamFileBlockName;
                                DatSLen : LongInt;
                                NumberOfKeys : Integer;
                                IID : IsamIndDescr;
                                FuncBuildKey : Pointer);

     procedure RebuildVFileBlock(FBlName : IsamFileBlockName;
                                DatSLen : LongInt;
                                NumberOfKeys : Integer;
                                IID : IsamIndDescr;
                                FuncBuildKey : Pointer);

Параметры
---------

     IBlName        Имя DOS реконструируемого файлового блока
                    (без расширения)

     DatSLen        Длина каждой записи. (См. раздел 8.А, как
                    задавать этот параметр для файловых блоков
                    переменной длины).

     NumberOfKeys   Число ключей данного файлового блока. Это
                    число может отличаться от значения,
                    первоначально заданного .

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

     FuncBuildKey   Указатель функции, которая вернет ключевую строку
                    для заданного номера записи и индекса.

Описание
--------

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

     1. Переименовывает файл '.DAT' в '.SAV', если файл '.SAV' не
существует.

     2. Вызывает     для  имени  ,  длины
записи   и  числа    ключей,  описанных  в
.

     3. Читает  из  файла  '.SAV'  каждую  не-удаленную  запись и
добавляет ее в новый файловый блок при помощи .

     4. Для каждого индекса считывает  каждую  запись  из  нового
файла  '.DAT'  и  добавляет  ключ  в  новый файловый блок вызовом
.

     5. Закрывает файловый блок.

     6. При успешном завершении стирает файл '.SAV'.

     Для выполнения   шага    4        вызывает
подпрограмму, которая  становится ей известна через параметр типа
указатель - . (Помните, что B-Tree Filer никогда не
знает фактического содержания каких-либо записей.)

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

     Если во   время   перепостроения  встречается  дублирующийся
первичный ключ,  то соответствующая запись данных и все введенные
для нее к этому моменту ключи удаляются. Содержимое записи данных
вместе с ее ключами записываются в текстовый файл  с  расширением
'MSG'. Этот  файл затем можно изучить с точки зрения того,  чтобы
впоследствии выполнить  реконструкцию  вручную.  Если  дубликатов
первичных ключей не встречено, то файл '.MSG' не создается.

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

Ошибки
------

     1..255       Содержимое встроенной переменной IOResult (возможно
                  только при записи '.MSG'-файла.)

     9900..9906   Ошибка операционной системы

     10400        Файл для реконструкции не найден

     10401        Недостаточно памяти для внутренних буферов

     10402        Длина записи данных превысила 65535.

Примечания
----------

     Реконструируемый файловый блок запирается процедурой. Прежде
чем он  снова  может  быть  использован,  должна   быть   вызвана
процедура    (или   соответственная   подпрограмма
открытия).

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

     Перед вызовом     не   забудьте   вызвать
 или .


BuildKey
-----------------------------------------------------------------
Объявление  (при желании может быть выбрано другое имя)
----------

     function BuildKey(var DatS; KeyNr : Integer) : IsamKeyStr;

Параметры
---------

     DatS          Запись, ключи которой должны быть перестроены.

     KeyNr         Номер перестраиваемого ключа.

     Результат     Сконструированная строка ключа.


Описание
--------

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

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

     MyDat : MyRecordType absolute DaTS;

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


D. Реорганизация файлового блока
--------------------------------

     Реорганизация - это процесс,  аналогичный перепостроению, но
используемый в других обстоятельствах. Реорганизация используется
в тех  случаях,  когда  размер каждой записи данных или ее формат
должны быть   изменены.   Модуль   B-Tree   Filer   REORG   также
обеспечивает способ  импортирования  данных  из другого формата в
формат файлового блока.

     Процедуры  и  , находящиеся
в модулях REORG и VREORG,  реализуют эти идеи для файловых блоков
с записями  фиксированной  и  переменной  длины,  соответственно.
 читает любой файл с записями фиксированной длины,
независимо от того,  был ли он создан B-Tree Filer.  (Однако,  она
при этом     всегда     пропускает    первую    запись    файла).
 специфична и предназначена только  для формата,
используемого записями переменной длины B-Tree Filer.

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

     REORG зависит  от  модуля  FILER.  VREORG зависит от модулей
FILER и REORG.

     Перед вызовом  REORG  или   VREORG   рекомендуется   сделать
запасные копии исходного файла данных,  на случай,  если во время
преобразования что-нибудь пойдет не так.


Идентификаторы REORG и VREORG
-----------------------------

     В данном разделе описаны все  идентификаторы, экспортируемые
модулями REORG  и  VREORG.  Они настолько близки,  что могут быть
описаны попарно.


ReorgFileBlock/ReorgVFileBlock
-----------------------------------------------------------------
Объявление
----------

     procedure ReorgFileBlock(FBlName : IsamFileBlockName;
                                DatSLen : LongInt;
                                NumberOfKeys : Integer;
                                IID : IsamIndDescr;
                                DatSLenOld : LongInt;
                                FuncBuildKey : Pointer;
                                ProcChangesDatS : Pointer);

     procedure ReorgVFileBlock(FBlName : IsamFileBlockName;
                                DatSLen : LongInt;
                                NumberOfKeys : Integer;
                                IID : IsamIndDescr;
                                DatSLenOld : LongInt;
                                MaxDiffBytes : Word;
                                FuncBuildKey : Pointer;
                                ProcChangesDatS : Pointer);

Параметры
---------

     IBlName        Имя DOS преобразуемого файлового блока
                    (без расширения)

     DatSLen        Длина новой записи данных.

     NumberOfKeys   Число ключей нового файлового блока.

     IID            Индексный дескриптор нового файлового блока

     DatSLenOld     длина записи  данных старого файлового блока

     FuncBuildKey   Указатель функции, которая вернет ключевую строку
                    для заданного номера записи и индекса.

     FuncChangeDatS Указатель функции, которая будет выполнять
                    контроль достоверности и преобразование каждой
                    записи данных

     MaxDiffBytes   (Только VREORG). Максимальное число байтов, на
                    которое вырастет длина записи переменной длины
                    при преобразовании. Отметим, что DatSLen и
                    DatSLenOld представляют длину "секции" файлового
                    блока, а  не  фактическую  длину   переменной
                    записи.

Описание
--------

     Данная процедура высокого уровня преобразовывает файл данных
файлового блока с именем  в новый формат и перестраивает
индекс. Это выполняется за следующие шаги:

     1. Переименовывает файл '.DAT' в '.SAV', если файл '.SAV' не
существует.

     2. Вызывает     для  имени  ,  длины
записи   и  числа    ключей,  описанных  в
.

     3. Читает  из  файла  '.SAV'  каждую запись.


     4. Вызывает подпрограмму преобразования и,  если  требуется,
добавляет преобразованную запись в новый файловый блок при помощи
.

     5. Для каждого индекса считывает  каждую  запись  из  нового
файла  '.DAT'  и  добавляет  ключ  в  новый файловый блок вызовом
.

     6. Закрывает файловый блок.

     7. При успешном завершении стирает файл '.SAV'.

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

     По контрасту   с     и  ,
процедура  передает в подпрограмму преобразования
все записи   данных   (включая   не  инициализированные  четырьмя
начальными байтами).  Это  делается  для  того,  чтобы  позволять
реорганизацию файлов с записями  фиксированной  длины  из  других
форматов. Написанная  пользователем  подпрограмма  преобразования
должна определять  достоверность  каждой  записи данных,  как она
считает нужным в  конкретном  случае,  и  возвращать  True,  если
запись принимается, и False, если она отвергается.

      и      должны   указывать  на
функции с заголовками, идентичными имеющимся в примерах программ,
описываемых  ниже.  Функции  должны компилироваться с моделью FAR
(при помощи директивы  компилятора  {$F+}  или  объявления  их  в
разделе  интерфейса  модуля),  и  не  должны быть вложены в любую
другую процедуру или функцию.

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

     Если во   время   реорганизации   встречается  дублирующийся
первичный ключ,  то соответствующая запись данных и все введенные
для нее к этому моменту ключи удаляются. Содержимое записи данных
вместе с ее ключами записываются в текстовый файл  с  расширением
'MSG'.  Этот файл затем можно изучить с точки зрения того,  чтобы
впоследствии выполнить  реконструкцию  вручную.  Если  дубликатов
первичных ключей не встречено, то файл '.MSG' не создается.

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


Ошибки
------

     1..255       Содержимое встроенной переменной IOResult (возможно
                  только при записи '.MSG'-файла.)

     9900..9906   Ошибка операционной системы

     10410        Файл для реорганизации не найден

     10411        Недостаточно памяти для внутренних буферов

     10412        Длина записи данных превысила 65535.

Примечания
----------

     Вы могли  отметить,  что  и  передаются
не с типом Word, а с типом LongInt. Они определены таким образом,
чтобы последующие  версии  могли позволить работу
с записями,  превышающими по длине  64К.  В  текущий  момент  это
средство не реализовано.

     Подпрограмма     требует   задание   одного
дополнительного параметра,   .   Эта   подпрограмма
использует данный параметр для выделения буфера,  в который будет
записываться преобразованная запись,  которая может быть  длиннее
исходной. Если  преобразованная  запись  во  всех  случаях  будет
короче, то в качестве   можно  ввести  ноль.  Также
отметим, что параметры  и  относятся к длине
секции записи (определение секции было дано в разделе  8.А), если
речь идет о записях переменной длины.

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

     Перед вызовом       не   забудьте   вызвать
 или .


ConvertRecord/ConvertVRecord
-----------------------------------------------------------------
Объявление  (при желании может быть выбрано другое имя)
----------

     function ConvertRecord(var DatSOld; var DatSNew) : Boolean;

     function ConvertVRecord(var DatSOld; var DatSNew;
                             var Len : Word) : Boolean;

Параметры
---------

     DatSOld       Преобразуемая запись

     DatSNew       Новая запись после преобразования

     Len           (Только VREORG). Длина записи переменной длины

     Результат     True для добавления записи и False, чтобы ее
                   пропустить.

Описание
--------

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


     Когда вызывает подпрограмму ,
то в нее передаются все записи, даже те, которые по стандартам B-
Tree Filer  считаются  удаленными.  Это делается для того,  чтобы
разрешить импортировать в B-Tree Filer  записи  других  форматов.
Подпрограмма преобразования  должна  проверять достоверность всех
данных и возвращать значение False для тех  записей,  которые  не
должны импортироваться.

Примечания
----------

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




E. Сортировка
-------------

     Хотя сортировка  представляет  собой  обычную  программу баз
данных, поставляемый модуль сортировки не  является  интегральной
частью модуля  FILER  в  том смысле,  котором ими являются VREC и
другие модули утилит.  Модуль сортировки может  быть  использован
для сортировки  любого  вида данных,  включая файлы данных B-Tree
Filer. Однако,  при  сортировке  файлов  данных  нужна  некоторая
осторожность. Более    подробную   информацию   см.   в   разделе
"Сортировка файловых блоков B-Tree Filer", ниже.

     Модуль виртуальной  сортировки,  MSORT,  представляет  собой
реализацию алгоритма  "сортировки слиянием".  Сортировка слиянием
позволяет сортировать больше записей, чем одновременно поместится
в оперативной  памяти,  за  счет  того,  что  сначала сортируются
небольшие порции  данных,  а  затем  пред-отсортированные  списки
сливаются в  итоговый  выходной файл.  Теоретически,  MSORT может
одновременно отсортировать два миллиарда записей.  Практически же
число записей   ограничивается  доступным  объемом  дисковой  или
расширенной (EMS) памяти,  а также временем ожидания  сортировки,
которое вас устраивает.

     MSORT используется в манере, аналогичной модулю SORT Borland
Database Toolbox   и   модулю   TPSORT   нашего   пакета    Turbo
Professional. Если  вы  ранее использовали любой из этих модулей,
вы быстро освоитесь с MSORT.

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

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

     Следующий небольшой  пример  показывает,  как   организовать
прикладную программу, использующую MSORT.


     program Example;
     uses
       Msort;
     var
       Status : MSortStatus;
       NumToDo : Word;

     { Подпрограммы, вызываемые MSORT, должны быть объявлены
       FAR и GLOBAL }

     {$F+}
     procedure GetElem;
       { Передача каждого сортируемого элемента в модуль Msort }
     var
       W, I : Word;
     begin
       for I := 1 to NumToDo do begin
         W := Random(MaxInt);
         if not PutElement(W) then begin
           WriteLn('Ошибка в PutElement');
           Halt;
         end;
       end;
     end;

     procedure PutElem;
     { Возврат каждого отсортированного элемента из модуля Msort }
     var
       W : Word;
     begin
       while GetElement(W) do
         WriteLn(W);
     end;

     function Less(Var X,Y) : Boolean;
       { сравнение сортируемых элементов }
     begin
       Less := Integer(X) < Integer(Y);
     end;
     {$F-}

     begin
       Write('Введите число сортируемых целых: ');
       ReadLn(NumToDo);
       Status := AutoSort(NumToDo, SizeOf(Integer), '', @GetElem,
                          @Less, @PutElem);
       case Status of
         MSortSuccess     : WriteLn('Успешное выполнение');
         MSortOutOfMemory : WriteLn('Недостаточно оперативной памяти');
         MSortDiskError   : WriteLn('Дисковая ошибка: ',MSortIOResult);
         MSortOutOfDisk   : WriteLn('Недостаточно дисковой памяти
                                     для слияния');
         MSortEMSError    : WriteLn('Ошибка EMS-памяти');
       else                 WriteLn('Неизвестная ошибка: ',Ord(Status));
       end;
     end.

     Отметим, что  подпрограммы  GetElem,  PutElem  и Less должны
быть объявлены как FAR и GLOBAL одновременно.  Невыполнение этого
требования приведет  к неверной последовательности сортировки или
даже к сбою программы.


Сортировка файловых блоков B-Tree Filer
---------------------------------------

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

     Если вы   решили  отсортировать  файловый  блок,  вы  должны
рассмотреть некоторые  дополнительные  вопросы.  Первый  из  них:
каждая удаленная  запись  в  файле  данных  содержит  специальный
признак, используемый для организации связного  списка свободного
пространства в файле данных; сортировка файла данных нарушит этот
список. Разумеется  сортировка  файла  данных  делает   полностью
недостоверным файл  индексов,  в котором ссылки делаются прямо на
номер записи.  И наконец,  первая запись в файле данных  содержит
внутреннюю системную  информацию;  после сортировки она все равно
должна остаться первой.  Следовательно,  при сортировке файлового
блока B-Tree    Filer    вы    должны    принимать    специальные
меры предосторожности, как показано в следующем примере.

     type
       MyRecType =
         record
           Dele : LongInt;   {Признак удаления}
           { Прочие поля }
         end;
     const
       DataName = 'MYDATA';  {Имя сортируемого файлового блока}
       NumberOfKeys = 2;     {Число ключей файлового блока}

     {$F+}
     procedure GetElem;
       { Передача каждого сортируемого элемента в модуль Msort }
     var
       RecNum : LongInt;
       IFBPtr : IsamFileBlock;
       Rec : MyRecType;
     begin
       OpenFileBlock(IFBPtr, DataName);  {Открыть только если он
                                          закрыт}
       for RecNum := 1 to UsedRecs(IFBPtr)+FreeRecs(IFBPtr)
       do begin
         GetRec(IFBPtr, RecNum, Rec);    {Прочитать каждую запись}
         if Rec.Dele = 0 then      {Убедиться, что она не удалена}
           if not PutElement(Rec) then begin  {Передать запись в
                                               модуль MSORT}
             CloseFileBlock(IFBPtr);  {Закрытие файлового блока
                                       в случае ошибки сортировки}
             Exit;
           end;
       end;
       CloseFileBlock(IFBPtr);        {Закрытие файлового блока}
     end;

     procedure PutElem;
     { Возврат каждого отсортированного элемента из модуля Msort }
     var
       RecNum : LongInt;
       KeyNum : Integer;
       KeyStr : IsamKeyStr;
       IFBPtr : IsamFileBlock;
       IID : IsamIndDescr;
       Rec : MyRecType;
     begin
       {Инициализация индексного дескриптора, IID}
        ...
       {Пересоздание файлового блока}
       MakeFileBlock(IFBPtr,DataName,SizeOf(MyRecType),NumberOfKeys,IID);
       while GetElement(Rec) do begin   {Прием каждого отсортированного
                                         элемента}
         AddRec(IFBPtr, RecNum, Rec);   {Добавление записи}
         for KeyNum := 1 to NumberOfKeys do begin
           KeyStr := ...                { Построение ключевой строки}
           AddKey(IFBPtr, KeyNum, RecNum, KeyStr); {Добавление ключа}
         end;
       end;
       CloseFileBlock(IFBPtr);   {Закрытие файлового блока}
     end;

     function Less(Var X,Y) : Boolean;
       { сравнение сортируемых элементов }
     begin
       { Возвращает значение TRue, если MyRec(X) < MyRec(Y) }
     end;
     {$F-}


     Отметим, что  GetElem пропускает запись 0,  которая содержит
внутренние данные,  описывающие файловый блок. GetElem читает все
остальные записи,  но  не передает в MSORT удаленные записи,  так
как сортировка удаленных записей просто зря тратит время. PutElem
создает новый  файловый  блок,  в данном случае заменяющий старый
(что в реальной прикладной программе не очень хорошо).  Затем она
принимает каждую   запись   назад   из  MSORT  в  отсортированной
последовательности и добавляет его и его ключи в  новый  файловый
блок. Функция  Less работает как любая другая функция MSORT Less,
поскольку удаленные записи уже отфильтрованы.

     Хотя данный  пример  показывает  вам   макет   требуемых   в
программе шагов,  она  не  включает  в  себя контроль ошибок.  за
каждым вызовом  подпрограммы  B-Tree   Filer   должна   следовать
проверка .


Управление памятью в MSORT
--------------------------

     MSORT использует специальный модуль, TPALLOC, поставляемый с
B-Tree Filer.   TPALLOC   содержит    специальные    подпрограммы
управления "кучей",  позволяющие  выделение структур данных свыше
64К байт.  Такие большие  структуры  могут  понадобиться  системе
сортировки для организации ее внутренних данных. Конкретно, MSORT
использует  одну  структуру,  называемую  "буфером прогона",  для
сортировки в  оперативной  памяти  наибольшей  группы  элементов,
какая там только поместится.

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

     Если фрагментация  станет  проблемой,  вы  можете   изменить
стратегию выделения  памяти  MSORT.  Для  этого удалите директиву
компиляции "BigHeap"    из    верхней    части    MSORT.PAS     и
перекомпилируйте модуль.  Фрагментация перестанет быть проблемой,
но появится новое ограничение.  Чтобы избежать затрат времени  на
освобождение возможно    тысяч   указателей,   MSORT   использует
специальный вид Mark и Release.  Этот метод  работает  достаточно
хорошо, если  программа,  вызвавшая подпрограммы MSORT,  не имеет
сама необходимости в выделении и освобождении  памяти  "кучи"  во
время процесса   выполнения   сортировки  -  т.е.,  речь  идет  о
процедурах пользователя, использующих сортировку.

     Если прикладной  программе   требуется   выделение   области
"кучи" в  процессе  сортировки,  она должна принять еще одну меру
предосторожности, помимо  того,  что  она   не   должна   удалять
директиву BigHeap.   Описываемая   ниже   типированная  константа
 сообщает MSORT о том,  какую  область  "кучи"  она
может использовать   для   сортировки.   Значение   по  умолчанию
позволяет MSORT использовать  всю  "кучу".  Прикладная  программа
должна устанавливать    в меньшее значение,  прежде
чем вызывать    или   ,   чтобы   гарантировать
доступность во время сортировки области "кучи".

     MSORT также использует память EMS, если она имеется и нужна.
(Более подробную информацию о  том,  как    определяет,
будет ли   использована   EMS-память,   см.  ее  описание).  Если
прикладная программа  сама  использует  EMS-память,  она   должна
выделить там  нужное  ей  число  страниц  до  вызова  подпрограмм
сортировки. Определяемые пользователем подпрограммы  Get,  Put  и
Less могут  использовать EMS сами,  даже даже пересылая данные из
EMS непосредственно  в  MSORT.  MSORT  также  устанавливает  свой
собственный контекст отображения всякий раз при чтении или записи
в EMS,  поэтому подпрограммам  пользователя  не  требуется  самим
сохранять и восстанавливать этот контекст.

     MSORT автоматически  освобождает  по  завершении сортировки,
либо в ее процедуре выхода в случае ошибки времени  выполнения  в
процессе сортировки, все используемые ей страницы EMS.

     Использование EMS   можно   отменить   установкой  константы
 в значение False.


Использование дисков MSORT
--------------------------

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

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

Идентификаторы MSORT
--------------------

     Данный раздел описывает все  идентификаторы,  экспортируемые
модулем MSORT.

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


Константы
---------

     BiggestDataItem = 65521;

     Размер наибольшего  отдельного  элемента  данных,  с которым
может работать Turbo Pascal.

     MaxHeapToUse = 5;

     Задает максимальный  объем  "кучи",   который   может   быть
использован MSORT.

     MergeOrder = 5;

     Задает порядок  слияния  для  сортировки.  Управляет  числом
файлов, открываемых на  фазе  слияния,  что  влияет  на  скорость
выполнения сортировки.  В  худшем  случае для ввода будет открыто
 для ввода и один - для  вывода.  Для  баланса  между
быстродействием, использованием     памяти    и    использованием
логических номеров принято значение по  умолчанию  5.  Вы  можете
уменьшить это значениее, минимум до числа 2.

     STemp : String[5] = 'STEMP';

     Используется как  первые  пять  символов  каждого временного
файла, создаваемого на фазе слияния.

     UseEms : Boolean = True;

     Управляет тем, будет ли система сортировки слиянием пытаться
использовать память типа EMS, если она доступна и нужна.


Типы
----

     MSortStatus = (MSortSuccess,     {Успешная сортировка}
                    MSortOutOfMemory, {Недостаточно памяти}
                    MSortDiskError,   {Ошибка дискового ввода/вывода}
                    MSortOutOfDisk,   {Недостаточно дисковой памяти
                                       для слияния}
                    MSortEMSError);   {Ошибка EMS}

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

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

     PathName = String[79];

     Строковый тип, используемый для имени маршрута.


Переменные
----------

     GRunLength : Word;

     Содержит длину  одного  прогона,  представляющую собой число
элементов (записей),  одновременно  помещающихся  в   оперативной
памяти. Если  все  сортируемые  элементы помещаются в памяти,  то
данная переменная  будет  равна  общему  числу   элементов.   При
использовании   это число вычисляется автоматически,  в
зависимости от объема доступной памяти.

     LastFileName : PathName;

     Содержит имя маршрута последнего файла, записанного системой
сортировки слиянием.

     MSortIOResult : Integer;

     Если сортировка   возвращает   статус  ,  то
 будет  содержать  значение  IOResult   в   момент
ошибки.

     UsingEMS : Boolean;

     Эта переменная  будет  равна  True,  если система сортировки
слиянием использует  EMS-память.  EMS-память  будет  использована
только если типированная константа  равна True,  если для
использования доступно достаточное число  страниц  EMS  (хотя  бы
размерым в один прогон), и если требуется фаза слияния.






AutoSort
-----------------------------------------------------------------
Объявление
----------

     function  AutoSort(FSizeInRecs : LongInt;
                        RecLength : Word;
                        TempPath : PathName:
                        GetElements : Pointer;
                        LessFunc : Pointer;
                        PutElements : Pointer) : MSortStatus;

Параметры
---------

     FSizeInRecs    Оценочное максимальное число сортируемых
                    записей

     RecLength      Длина каждой записи

     TempPath       Дисковод и маршрут, где будут храниться
                    временные файлы для слияния.

     GetElements    Указатель подпрограммы, передающей записи на
                    сортировку

     LessFunc       Указатель функции сравнения двух записей

     PutElements    Указатель подпрограммы, возвращающей
                    отсортированнык записи в программу

     Результат      Статус завершения сортировки (см. выше описание
                    типа .

Описание
--------

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

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

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

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

     Остальные параметры   представляют собой указатели
на подпрограммы,  вызываемые во время выполнения сортировки.  Эти
подпрограммы должны   иметь  определенные  свойства:  они  должны
компилироваться для  модели  памяти  FAR  (при  помощи  директивы
{$F+}); они  должны  быть  глобальными  (не  вложенными  в другие
процедуры); а  их  заголовки  должны  соответствовать  заголовкам
приводимых ниже примеров.

      указывает на процедуру с заголовкам вида:

     {$F+}
     procedure GetSortElements;
     begin;
       { Для каждого сортируемого элемента выполнить ... }
         if not PutElement(X) then
           Exit;
     end;
     {$F-}

     Данная подпрограмма  должна  получать   каждый   сортируемый
элемент и  вызывать   указывает на функцию,  возвращающую True, если ее
первый элемент  меньше  второго,  и  False  в  противном  случае.
Отметим, что    параметры,    передаваемые    в   функцию   Less,
нетипированные; они   могут   рассматриваться   как    переменные
заданного типа   путем   использования  преобразования  типа  или
переменных, объявленных  как  absolute  и   наложенных   на   эти
параметры. Поскольку  X  и Y это параметры-переменные,  они могут
быть объявлены как параметры фактического типа данных.

     {$F+}
     function Less(var X,Y) : Boolean;
     begin
       { Возвращает True, если X < Y, иначе False }
     end;
     {$F-}

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

     {$F+}
     procedure PutSortElements;
     begin
       while GetElement(X) do
         { Что-то выполнить с X }
     end;
     {$F-}

     С использованием показанных примеров, вызов  может
иметь вид:

     Status := AutoSort(NumItems, RecSize, '',
                        @GetSortElements, @Less, @PutSortElements);

      будет вызывать подпрограмму GetSortElements после
выполнения   предварительного    контроля    ошибок    и    задач
инициализации.  GetSortElements,  в свою очередь, должна вызывать
  для  помещения  каждого  элемента   во   внутренние
структуры данных MSORT. Когда  требуется сравнить два
элемента, чтобы поместить их в последовательности сортировки, она
должна   вызвать  вашу  функцию  Less.  Функция  Less  сравнивает
элементы  любым  желательным  способом,  в  зависимости  от  типа
данных,  и  возвращает  True,  если первый элемент X "меньше чем"
второй  элемент  Y.  После  того,   как   сортировка   завершена,
  вызовет вашу подпрограмму PutSortElements,  которая в
свою  очередь  должна  вызывать    для  приема  назад
каждого    отсортированного    элемента.    При    возврате    из
PutSortElements  освобождает использовавшуюся ей память
и  возвращает  статус сортировки в исходную вызывающую программу.
Используемые в  коды см. в описании типа MSortStatus.


AutoSortInfo
-----------------------------------------------------------------
Объявление
----------

     function  AutoSortInfo(FSizeInRecs : LongInt;
                        RecLength : Word;
                        var HeapSpace : LongInt;
                        var DiskSpace : LongInt;
                        var FileHandles : Word;
                        var EMSPages : Word;
                        var RunLen : Word;
                        var FileBufs : Word;
                        var OutFileBufs : Word;
                        var AllInMem : Boolean) : MSortStatus;

Параметры
---------

     FSizeInRecs    Число сортируемых записей

     RecLength      Длина каждой записи

     HeapSpace      Пиковое число байтов требуемой области "кучи"

     DiskSpace      Пиковое число байтов требуемой области диска

     FileHandles    Пиковое число требуемых логических номеров файлов

     EMSPages       Пиковое число требуемых страниц EMS-памяти
                    (каждая по 16384 байта)

     RunLen         Число записей, одновременно находящихся в памяти

     FileBufs       Число байтов, используемых для буферов входных
                    файлов во время слияния

     OutFileBufs    Число байтов, используемых для буфера выходного
                    файла во время слияния

     AllInMem       True, если слияние не требуется, т.е. сортировка
                    полностью выполняется в оперативной памяти

     Результат      Статус смоделированной сортировки,
                    MSortSuccess или MSortOutOfMemory.


Описание
--------

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


Примечания
----------

      вычислит расход памяти "кучи" для ,
а затем  проверит,  позволяет  ли  имеющееся количество свободной
памяти "кучи" выполнить сортировку целиком в  оперативной памяти.
Если не  позволяет,  то она выбирает максимальный размер прогона,
который поместится в доступной памяти,  и смоделирует  сортировку
слиянием для  вычисления  объема  дисковой памяти,  страниц EMS и
числа логических номеров файлов, требуемых для слияния.


DoSort
-----------------------------------------------------------------
Объявление
----------

     function  DoSort(RunLength : Word;
                        RecLength : Word;
                        InFileBufMax : Word;
                        OutFileBufMax : Word;
                        TempPath : PathName:
                        GetElements : Pointer;
                        LessFunc : Pointer;
                        PutElements : Pointer) : MSortStatus;

Параметры
---------

     RunLength      Число записей, одновременно сортируемых в
                    оперативной памяти

     RecLength      Длина каждой записи

     InFileBufMax   Число байтов, используемое для буферов ввода
                    при слиянии

     OutFileBufMax  Число байтов, используемое для буфера вывода
                    при слиянии

     TempPath       Дисковод и маршрут, где будут храниться
                    временные файлы для слияния.

     GetElements    Указатель подпрограммы, передающей записи на
                    сортировку

     LessFunc       Указатель функции сравнения двух записей

     PutElements    Указатель подпрограммы, возвращающей
                    отсортированнык записи в программу

     Результат      Статус завершения сортировки (см. выше описание
                    типа .


Примечания
----------

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

     Многие параметры      совпадают  с  передаваемыми  в
; мы не будем повторять здесь  их  описание.  Некоторые
новые параметры описаны ниже.

      это  число элементов,  сортируемых в оперативной
памяти за один раз.  Пользователь сам отвечает за то,  чтобы  как
минимум *  байтов  "кучи"  были свободными.
(Должно ли это пространство  быть  непрерывным,  или  не  должно,
определяется условным определением BigHeap, описанным выше).

      и    задают  размеры  буферов,
которые будут  использованы  при  выполнении  слияния.  И  снова,
вызывающая программа   должна   обеспечить  наличие  достаточного
объема свободной памяти "кучи", чтобы  могла выделить эти
буферы. Если в этом параметре передан ноль, то буферизация вообще
отменяется.

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


GetElement
-----------------------------------------------------------------
Объявление
----------

     function GetElement(var X) : Boolean;

Параметры
---------

     X     Будет возвращен следующий отсортированный элемент.


Описание
--------

      вызывается  для  приема  каждого   элемента   в
отсортированной последовательности  после  завершения сортировки.
Ваша прикладная  программа   может   вызывать      из
подпрограммы доступа к отсортированным записям,  адрес которой вы
передаете в .

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

      возвращает  True,  если  есть  еще элементы для
приема. Если она возвратила False, значит параметр X неопределен.


PutElement
-----------------------------------------------------------------
Объявление
----------

     function PutElement(var X) : Boolean;

Параметры
---------

     X     Следующий сортируемый элемент.


Описание
--------

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

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

      возвращает  True,  если  элементы  был  успешно
добавлен во внутреннюю структуру MSORT.  Если возвращено значение
False, то произошла ошибка  (возможно,  связанная  с  недостатком
оперативной или  дисковой памяти),  и прикладная программа должна
прекратить добавлять элементы и выйти из программы-загрузчика.






F. Числовые ключи
-----------------

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

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

     Модуль NUMKEYS также содержит несколько подпрограмм, которые
создают "упакованные" строки ключей.  для  заданной  обыкновенной
строки символов  эти подпрограммы возвращают сжатую ее версию,  в
которой каждый символ представлен 5 или  6  битами,  а  не  8.  В
случаях, где могут быть использованы упакованные ключевые строки,
можно тем самым получить экономию в 25-37%  (например,  строка из
50 символов  в сжатом виде может быть представлена либо 32,  либо
38 символами).  Как и в случае строк  для  числовых  ключей,  эти
упакованные строки  нельзя просматривать непосредственно,  но при
использовании в_деревом   они   будут   давать   верный   порядок
сортировки. Для  распаковки  упакованных  ключевых  строк имеются
также дополнительные подпрограммы.

     За идеи,  лежащие  в  основе  подпрограмм  данного   модуля,
отдельное спасибо Скотту Бассингеру.

Идентификаторы NUMKEYS
----------------------

     В данном разделе описаны все  идентификаторы, экспортируемые
модулем NUMKEYS.  Вследствие  высокой степени идентичности многих
из этих подпрограмм мы опишем их по группам, а не отдельно.

Типы
----

     String2  = String[2];
     String4  = String[4];
     String5  = String[5];
     String6  = String[6];
     String7  = String[7];
     String8  = String[8];
     String9  = String[9];
     String10 = String[10];

     Строковые типы,  связанные с различными числовыми форматами.
Переменные типа  Integer  и  Word  преобразуются  в  тип String2;
LongInt в  String4;  Real  в  String6;   Extended   в   String10.
промежуточные типы строк вводятся для того, чтобы позволить более
короткие ключи,  когда точность числовой  переменной  может  быть
уменьшена.


Преобразование чисел в ключи
-----------------------------------------------------------------
Объявление
----------

     function IntToKey(I : Integer) : String2;
       { Преобразование Integer в String }

     function WordToKey(W : Word) : String2;
       { Преобразование Word в String }

     function LongToKey(L : LongInt) : String4;
       { Преобразование LongInt в String }

     function RealToKey(R : Real) : String6;
       { Преобразование Real в String }

     function ExtToKey(E : Extended) : String10;
       { Преобразование Extended в String }

Параметры
---------

     Заданное значение        Числовое значение, преобразовываемое
                              в строку символов.

     Результат                Эквивалентная строка символов.

Описание
--------

     Каждая из  этих  подпрограмм  преобразует  числовое значение
заданного типа в  строку  символов.  Строка  предназначается  для
использования в  качестве  ключа  файлового  блока  B-Tree Filer;
вывод ее на дисплей не ожидается, поскольку отдельные ее значения
могут лежать   в  полном  диапазоне  кодов,  от  0  ло  255.  При
сравнениии двух   преобразованных   строк   операции   строкового
сравнения ("<", ">", и т.д.) возвращают ожидаемый результат.

     После возврата каждая строка имеет длину, равную максимально
допустимой для  данного  типа.   Например,      всегда
возвращает строки  длиной  6  символов.  Для  чисел типа Integer,
Word, LongInt  и  Real  для  сохранения  значения  числа   должна
храниться вся строка полностью.

      появляется  только  в  том  случае,  когда модуль
NUMKEYS компилируется    с    опцией    {$N+}     (математический
сопроцессор). Эта  единственная  подпрограмма  может  служить для
преобразования в строки числе с  плавающей  точкой  формата  IEEE
типа Syngle,  Double, Extended и Comp. Для менее точных из них не
все символы возвращаемой строки  являются  значимыми.  Вы  можете
использовать без  потери  точности  любые  из следующих строковых
типов для хранения результатов :

     Single    : String5 (min) - String10 (max)
     Double    : String9 (min) - String10 (max)
     Extended  : String10 (min/max)
     Comp      : String10 (min/max)

     Впрочем, если вы можете несколько пожертвовать точностью, то
для типов Single,  Double и Extended могут  быть  использованы  и
несколько более  короткие  строки (на один байт короче указанного
минимума). Для    Comp    настоятельно    рекомендуется    всегда
использовать String10.

Примечания
----------

     Стандарт IEEE  числел  с   плавающей   точкой,   реализуемый
математическим сопроцессором     8087,    определяет    несколько
специальных классов чисел,  которые  обычно  не  являются  частью
формальной математики, но полезны в контексте численного анализа.
Примерами таких   чисел   являются    NAN    ("Не-число"),    INF
("Плюс-бесконечность") и -0 ("Минус-ноль").

     Когда математический  сопроцессор  (или  его эмулятор) имеет
дело с такими  специальными  числами,  он  применяет  специальные
правила. Например,  он возвращает True при сравнении (0 = -0),  а
результатом сложения NAN с любым нормальным числом равен NAN.

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

     Эти ситуации   не   должны  вызывать  проблем  в  нормальных
условиях. Специальные   значения   восстанавливаются    обратными
подпрограммами преобразования.



Преобразование ключей в числа
-----------------------------------------------------------------
Объявление
----------

     function KeyToInt(S : String2) : Integer;
       { Преобразование String в Integer }

     function KeyToWord(S : String2) : Word;
       { Преобразование String в Word }

     function KeyToLong(S : String) : LongInt;
       { Преобразование String в LongInt }

     function KeyToReal(S : String) : Real;
       { Преобразование String в Real }

     function KeyToExt(S : String) : Extended;
       { Преобразование String в Extended }

Параметры
---------

     S           Строка символов, полученная предыдущим
                 преобразованием ключа.

     Результат   Исходное числовое значение.


Описание
--------

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

Примечания
----------

      появляется  только  в  том  случае,  когда модуль
NUMKEYS компилируется    с    опцией    {$N+}     (математический
сопроцессор).

Упаковка ключевых строк
-----------------------------------------------------------------
Объявление
----------

     function Pack5BitKeyUC(Src : String; Len : Byte) : string;
       { Упаковка Src в последовательность из 5 битов.
         Алфавитные символы преобразуются в верхний регистр }

     function Pack6BitKeyUC(Src : String; Len : Byte) : string;
       { Упаковка Src в последовательность из 6 битов.
         Алфавитные символы преобразуются в верхний регистр }

     function Pack6BitKey(Src : String; Len : Byte) : string;
       { Упаковка Src в последовательность из 6 битов }

Параметры
---------

     Src         Упаковываемая строка символов.

     Len         Длина возвращаемой упакованной строки.

     Результат   Упакованная строка.


Описание
--------

     Все эти  подпрограммы   выозвращают   упакованную   ключевую
строку, в   которой   каждый   символ   исходной  строки  ()
представлен вместо 8 либо 5,  либо 6 битами.  Упакованная  строка
становится, таким образом, примерно на 25-37% короче исходной.

      -   это   длина   возвращаемой   упакованной   строки.
Правильное значение данного параметра зависит (1) от максимальной
длины неупакованной строки,  переданной в параметре ,  и (2)
от того,  хранит ли вызываемая подпрограмма  упаковки  символы  в
виде 5, или 6 битов. Формулы, используемые для вычисления :

5 бит: (MaxLength*5) div 8 + Ord((MaxLength*5) mod 8 <> 0)

6 бит: (MaxLength*6) div 8 + Ord((MaxLength*6) mod 8 <> 0)

     Например, если   вы   используете    (которая
представляет символ 5 битами), а максимальная длина неупакованной
ключевой строки равна 50, то  может быть вычислена как:

     Len = (50*5) div 8 + Ord(50*5) mod 8 <> 0)
         = 250 div 8    + Ord(250 mod 8 <> 0)
         = 31           + Ord(2 <> 0)
         = 31           + 1
         = 32

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

 const
   UnpackedLen = 50;
   PackedLen = (UnpackedLen*5) div 8 + Ord((UnpackedLen*5) mod 8 <> 0);

     Каждая из  этих  подпрограмм  делает  важное   предположение
относительно того,   какого   рода  символы  находятся  в  .
Следовательно, вы должны выбрать ту подпрограмму,  которая  лучше
подходит в  конкретной  ситуайии.  В таблице ниже показаны наборы
символов, которые каждая подпрограмма может представлять 5  или 6
битами. В   каждом  случае  число  справа  указывает  фактические
значения, используемые для представления каждого символа.


Pack5BitKeyUC       Pack6BitKeyUc        Pack6BitKey
-------------       -------------        ------------
'A'..'Z'  1-26      '!'..'_'   1-63      '0'..'9' 1-10
'a'..'z'  1-26      'A'..'Z'   33-58     'A'..'Z' 11-36
все прочие 0        'a'..'z'   33-58     'a'..'z' 37-62
                    все прочие 0         все прочие 0


     Как можно    видеть,    каждая    схема    обладает   своими
преимуществами и недостатками:

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

      аналогична  ,  но  она  также
позволяет,  помимо заглавных букв,  представлять  цифры  и  знаки
пунктуации (за исключением '`').
(Строчные буквы    преобразовываются    в     заглавные     буквы
автоматически). Хотя    может  представлять больше
символов, чем ,  она обеспечивает меньшую  степень
сжатия (примерно 25%).

      дает    ту    же   степень   сжатия,   что   и
, но может представлять только цифры  ('0'..'9') и
буквы, но  не  знаки  пунктуации.  Ее  главное  преимущество  над
первыми двумя  программами  состоит  в  том,  что  она  различает
строчные и  заглавные  буквы.  В  ситуациях,  где важно учитывать
регистр буквы,  эта программа -  единственная  из  трех,  которую
можно использовать.


Распаковка ключевых строк
-----------------------------------------------------------------
Объявление
----------

     function Unpack5BitKeyUC(Src : String) : string;
       { Распаковка ключа, созданного  }

     function Unpack6BitKeyUC(Src : String) : string;
       { Распаковка ключа, созданного  }

     function Unpack6BitKey(Src : String) : string;
       { Распаковка ключа, созданного  }


Параметры
---------

     Src         Распаковываемая упаковыванная строка символов ключа.

     Результат   Распакованная строка.


Описание
--------

     Эти подпрограммы  распаковывают  ключевые  строки,  созданные
функциями  ,   {Pack6BitKeyUC>   и   ,
соответственно.

     Отметим, что   возвращаемые   строки   не  обязательно  будут
идентичны исходно  переданным  в  подпрограммы   упаковки.   Любые
символы, которые  подпрограммы упаковки не смогли запаковать в 5/6
битах, будут соответственно возвращены здесь как пробелы,  и кроме
того, строчные  буквы  'a'..'z'  будут  распакованы как заглавные,
кроме случая использования .

     Длина распакованной  строки  также  может   превышать   длину
исходной строки (если эта исходная строка была короче максимальной
длины, использованной для вычисления параметра Len,  переданного в
подпрограмму упаковки);  в  этом  случае  в  распакованной  строке
появятся дополняющие пробелы.





9. Сетевые утилиты
------------------

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

     С учетом  всего  этого  мы создали три дополнитьльных мощных
модуля для  многопользовательской   версии   B-Tree   Filer.   (В
однопользовательскую версию  они не входят.) Признавая лидирующее
положение Novell на рынке сетей  для  PC,  мы  предлагаем  модуль
NETWARE, обеспечивающий  большое  число  специфичных  для  Novell
средств.Модуль NETBIOS предлагает доступ к подпрограммам передачи
сообщений между  рабочими станциями,  поддерживаемым большинством
современных сетей,  включая Novell, 3Com, PC LAN и PC-NET. Модуль
SHARE включает  в себя подпрограммы запирания файлов,  снабженные
утилитой MS-DOS   3.x   SHARE   и   некоторыми    подпрограммами,
специфическими для MS-NET и PC-LAN.

     Три демонстрационные    программы   показывают   возможности
сетевых утилит.  NETINFO идентифицирует вид активной  сети,  если
сеть имеется,  и сообщает все сведения о сети,  которые она может
определить. NSEND и NRECEIVE являются  партнерами:  они  копируют
файл с   одной   рабочей   станции   на  другую  (без  посредства
файл-сервера), используя для этого сервисные средства NetBIOS или
NetWare, о   которых   вы   узнаете  ниже  в  данной  главе.  Эти
демонстрационные программы описаны  в  последнем  разделе  данной
главы.

     Общее введение в концепции организации сетей см.  в любой из
следующих книг:

     Understanding Local Area Networks
       Stan Schatt, Howard W.Sams & Co, 1988.

     Local Area Networks, The Second Generation
       T.W.Madrone, John Wiley and Sons, 1988.

     Communications and Networking for the IBM PC and Compatibles
       Larry Jordan, Brady Books, Simon & Schuster, 1986.

A. Novell NetWare
-----------------

     Для доступа к мощным средствам  своей  операционной  системы
Advanced NetWare  фирма  Novell поставляет только подпрограммы на
языке Си.  Это  оставляет  программистов,  работающих  на   Turbo
Pascal, в беспомощном положении.  Модуль NETWARE,  поставляемый в
составе данного продукта,  реализует многие средства интерфейса с
прикладными программами  (API)  NetWare  - сервисные средства для
доступа к функциям локальной  сети  NetWare  (LAN).  Инструменты,
собранные в модуле NETWARE, делают доступными такие средства, как
сетевая система  буферизации  печати,  сервисные  функции  обмена
сообщениями, прямая  связь станция-станция,  средства трассировки
транзакций NetWare SFT, и т.д.

     В действительности в  NetWare  API  подпрограмм  значительно
больше, чем  реализовано  нами.  Мы  выбрали для реализации те из
них, которые,  с нашей точки зрения,  наилучшим образом дополняют
подпрограммы B-Tree   Filer.   Если   вам  нужны  другие  сетевые
подпрограммы, то мы надеемся,  что наш исходный код, в комбинации
с документацией Novell, позволит реализовать любые ваши желания.

     Подпрограммы в  данном  модуле специфичны для среды NetWare.
Некоторые операционные  системы,  совместимые  с  NetWare  (вроде
CBIS Network-OS),  поддерживают  некоторые  из  этих функций,  но
маловероятно, чтобы оне поддерживали все.

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

     Руководство пользователя Novell
     Справочник по интерфейсу с прикладными программами (API)
        Novell, Том 1
     Справочник по интерфейсу с прикладными программами (API)
        Novell, Том 2

     Всю эту  литературу  можно заказать непосредственно на фирме
Novell.

     В данном разделе мы пишем NETWARE заглавными  буквами,  если
имеется в виду модуль B-Tree Filer, и NetWare смешанными буквами,
если имеется в виду операционная система Novell.

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

     - Управление файлами и директориями;

     - Трассировка транзакций;

     - Буферизация печати;

     - Базовые сервисные средства обмена сообщениями
       (каналы и широковещательные средства);

     - Продвинутые сервисные средства обмена сообщениями
       (IPX и SPX).

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

     Если вы углубленно изучите исходный код NETWARE, вы увидите,
что некоторые идентификаторы задействованы для интерфейса,  но не
документированы.  Несмотря  на  то,  что  все  эти идентификаторы
выполняют полезные функции,  мы решили, что если мы попытаемся их
здесь документировать,  то  данная  глава  Руководства  по B-Tree
Filer превратится в том,  объемом в полный комплект  документации
для разработчика  Novell.  Мы взяли курс на документирование лишь
тех типов и  подпрограмм,  с  которыми  действительно  необходимо
работать обычному     программисту,     не    специализирующемуся
исключительно по сетям.  Если у вас имеется документация Novell и
вы хотите   воспользоваться  недокументированными  подпрограммами
NETWARE, то полный вперед! Мы и сами их используем.

Аттрибуты файлов и директорий
-----------------------------

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

     - Определение того, загружена ли NetWare;

     - Прием или установка расширенных файловых атрибутов;

     - Определение того, является ли файл разделяемым,
       или установка его в качестве такового;

     - Прием логического номера NetWare для маршрута на сетевом
       дисководе;

     - Прием или установка прав доступа к директории
       (на чтение, на запись и т.д.);

     - Переключение между режимами NetWare: расширенного режима
       с запираниями и режима совместимости с DOS;

     - Определение того, имеет ли рабочая станция привилегии
       консоли;

     - Чтение даты и времени сервера сети.


Константы
---------

     NwRead = $01;
     NwWrite = $02;
     NwOpen = $04;
     NwCreate = $08;
     NwDelete = $10;
     NwParental = $20;
     NwSearch = $40;
     NwModify = $80;

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

     NwPermanent = $01;
     NwTemporary = $02;
     NwLocal = $80;

     Определения битового   набора   в  параметре  ,
возвращаемом из .


Типы
----

     DayOfTheWeek = (Sunday, Monday, Tuesday, Wennesday, Thursday,
                     Friday, Saturday);

     Используется в сочетании с подпрограммой .

     ServerInformation =
       record
         Len : Word;
         ServName : array [1..48] of Char;
         NetWareVer : Byte;
         NetWareSub : Byte;
         MaxConns : Word;
         UsedConns : Word;
         MaxVols : Word;
         Revision : Byte;
         SFTLevel : Byte;
         TTSLevel : Byte;
         PeakConn : Word;
         AccountVer : Byte;
         VAPVer : Byte;
         QueueVer : Byte;
         PrintServVer : Byte;
         VirtualVer : Byte;
         SecurityVer : Byte;
         BridgeVer : Byte;
         Reserved : Array[1..60] of Byte;
       end;

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


ConsolePriv
-----------------------------------------------------------------
Объявление
----------

     function ConsolePriv : Boolean;

Параметры
---------

     Результат       Возвращает True, если рабочая станция имеет
                     привилегии консоли.


Описание
--------

     Некоторые сервисные  подпрограммы  NetWare  требуют,   чтобы
вызывающая станция  имела  привилегии  консоли.  Из  включенных в
состав модуля NETWARE только  и    требуют
наличия такой привилегии.  Данная подпрограмма определяет,  имеет
ли вызывающая станция такую привилегию.


FileIsShareable
-----------------------------------------------------------------
Объявление
----------

     function FileIsShareable(Path : PathName;
                              var FAttr : Word;
                              var ErrCode : Word) : Boolean;

Параметры
---------

     Path       Имя файла DOS.

     FAttr      Возвращаемые аттрибуты файла DOS.

     ErrCode    0 в случае успешного выполнения;
                иначе код ошибки DOS.

     Результат  True, если файл разделяемый; иначе False.

Описание
--------

     Возвращает True,   если   файл,  заданный  параметром  Path,
помечен  в  NetWare  как   разделяемый.   Аттрибуты   DOS   файла
возвращаются в .

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

  7  6  5  4  3  2  1  0
  |     |  |  |  |  |  |
  |     |  |  |  |  |  |
  |     |  |  |  |  |  |
  |     |  |  |  |  |   ------ Только чтение
  |     |  |  |  |   --------- Скрытый
  |     |  |  |   ------------ Системный
  |     |  |   --------------- Метка тома или только для выполнения
  |     |   ------------------ Субдиректория
  |      --------------------- Модифицирован с момента копирования
   --------------------------- Разделяемый (специфично для NetWare)

     Фактически атрибут представляет собой по  размеру  байт,  но
ему отводится   слово,   что  обеспечивает  непротиворечивость  с
модулем Turbo Pascal DOS.

Ошибки (возвращаемые в ErrCode)
------

     0   Успешное завершение.

     2   Файл не найден.

     5   Доступ не разрешен.


Примечания
----------

     NetWare использует   старший  бит  обычного  байта  атрибута
файлов DOS для обозначения признака  разделяемости  файла.  Чтобы
доступ к  файлу имело несколько рабочих станций,  этот бит должен
быть явно  установлен  при  создании  файла,  или   же   позднее,
прикладной программой.

     Файлы, открытые  в сети Novell при помощи команд для сетевых
файловых блоков B-Tree  Filer,  автоматически  получают  атрибуты
разделяемых.

GetDirHandle
-----------------------------------------------------------------
Объявление
----------

function GetDirHandle(Drive : Char; var StatusFlags : Byte) : Byte;

Параметры
---------

     Drive         Буква для проверяемого дисковода.

     StatusFlags   Возвращаемый тип логического номера (handle)
                   директории.

     Результат     Логический номер директории,
                   0 для неверного дисковода.


Описание
--------

      задает букву дисковода,  например,  'A', 'B', и т.д.
(Регистр при этом  значения  не  имеет).  Сервисные  функции  для
сетевых файлов не обращаются непосредственно к дисководам; вместо
этого они используют однобайтовые логические  номера  директорий.
Данный вызов  позволяет  программам определить текущий логический
номер директории, связанный с конкретным дисководом.

     Если функция возвращает 0,  это означает, что задан неверный
дисковод .  В противном случае возвращаемое значение равно
логическому номеру для данного дисковода ().

     StatusFlags представляет собой байт,  битовый набор которого
интерпретируется следующим образом:

  7  6  5  4  3  2  1  0
  |                 |  |
  |                 |  |
  |                 |  |
  |                 |   ------ Логический номер постоянной директории
  |                  --------- Логический номер временной директории
   --------------------------- Отображается на локальном дисководе

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


GetDirPath
-----------------------------------------------------------------
Объявление
----------

     function GetDirPath(DirHandle : Byte; var Path : String) : Byte;

Параметры
---------

     DirHandle   Логический номер директории.

     DirPath     Возвращаемый маршрут к директории,
                 связанной с DirHandle.

     Результат   0 при успешном завершении; иначе код ошибки NetWare


Описание
--------

     Возвращает текущую   директорию,   связанную   с  логическим
номером директории.

Ошибки (возвращаемые в качестве результата функции)
------

     $9B   Неверный логический номер директории.

Примечания
----------

      имеет тип String,  поскольку NetWare позволяет  иметь
более длинныен  маршруты,  чем  DOS.  Возвращаемая  строка  может
фактически иметь длину до 255 байтов.


GetDirRights
-----------------------------------------------------------------
Объявление
----------

     function GetDirRights(DirHandle : Byte;
                           Path : String;
                           var Rights : Byte) : Byte;

Параметры
---------

     DirHandle   Логический номер директории (задающий дисковод).

     Path        Имя суб-директории DOS, относительно DirHandle.

     Rirhts      Возвращаются действующие права доступа.

     Результаты  0 при успешном завершении; иначе код ошибки NetWare.


Описание
--------

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

      это     байт,     битовое     множество    которого
интерпретируется следующим образом:

  7  6  5  4  3  2  1  0
  |  |  |  |  |  |  |  |
  |  |  |  |  |  |  |  |
  |  |  |  |  |  |  |  |
  |  |  |  |  |  |  |   ------ Чтение разрешено
  |  |  |  |  |  |   --------- Запись разрешена
  |  |  |  |  |   ------------ Файлы могут быть открыты
  |  |  |  |   --------------- Файлы могут быть созданы
  |  |  |   ------------------ Файлы могут быть удалены
  |  |   --------------------- Суб-директории могут быть созданы
  |  |                                        или удалены
  |   ------------------------ Поиск для данной директории разрешен
   --------------------------- Биты статуса файла могут быть
                                              модифицированы

Ошибки
------

     $98     Том не существует.

     $9B     Неверный логический номер директории.

Примечания
----------

      имеет   тип   String,   поскольку  NetWare  позволяет
задавать более длинные маршруты, чем DOS.


GetExtFAttr
-----------------------------------------------------------------
Объявление
----------

     function GetExtFAttr(Path : PathName; var Attr : Byte) : Byte;

Параметры
---------

     Path        Имя файда DOS.

     Attr        Возвращаемые расширенные аттрибуты файлы.

     Результаты  0 при успешном завершении; иначе код ошибки NetWare.


Описание
--------

     Возвращает расширенные  атрибуты заданного файла в параметре
.

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

  7  6  5  4  3  2  1  0
  |  |  |  |     |  |  |
  |  |  |  |      ------------ Режим поиска
  |  |  |   ------------------ Транзакции разрешены
  |  |   --------------------- Быстрая индексация
  |   ------------------------ Контроль доступа чтения
   --------------------------- Контроль доступа записи

     Биты режима  поиска  имеют  смысл только когда  задает
выполняемый файл,  например .EXE- или .COM-файл.  Значение  этого
бита определяет,  будет ли и каким образом выполняемый файл будет
искать свои файлы данных (или оверлейные файлы).  Обычно никакого
поиска не выполняется,  и файл данных должен находиться в текущей
директории или в другой директории,  явно названной в  прикладной
программе. Когда  поиск  разрешен,  NetWare автоматически сначала
просматривает директорию по умолчанию, затем все дисководы поиска
(эквивалент NetWare   для  DOS  PATH).  Поиск  происходит,  когда
прикладная программа делает для того,  чтобы открыть файл,  вызов
Turbo Pascal Reset().

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

     0      Команд поиска нет. Выполняемый файл будет использовать
            метод поиска, заданный в файле NetWare  SHELL.CFG.
            Этот режим является умолчанием для всех выполняемых
            файлов.

     1      Если выполняемым файлом задается полное имя маршрута,
            то поиск будет выполнен только по этому маршруту.
            Если задано только имя файла, то NetWare будет
            искать его сначала в текущей директории, а затем
            на всех дисководах поиска.

     2      Поиск только в директории по умолчанию.

     3      Если выполняемым файлом задается полное имя маршрута,
            то поиск будет выполнен только по этому маршруту.
            Если задано только имя файла и файл открыт только
            для чтения, то NetWare будет искать его сначала в
            текущей директории, а затем на всех дисководах поиска.

     4      Резервируется.

     5      NetWare будет выполнять поиск сначала в директории
            по умолчанию, а затем на всех дисководах поиска,
            независимо от того, задан ли маршрут.

     6      Резервируется.

     7      Если файл открыт только на чтение, то NetWare будет
            выполнять поиск сначала в директории по умолчанию,
            а затем на всех дисководах поиска, независимо от того,
            задан ли маршрут.

     В случае,  если установлен бит  транзакций,  файл  позволяет
поддержку трассировки   транзакций  (TTS).  Если  установлен  бит
быстрой индексации,  NetWare будет держать индекс всех  блоков  в
файле, чтобы  увеличить скорость произвольного доступа.  Этот бит
должен быть установлен для часто используемых файлов  с  размером
более 2  мегабайт.  Биты  контроля чтения и записи означает,  что
каждый доступ к  файлу  будет  регистрироваться  в  файле-журнале
контроля доступа (средство,  не реализованное в некоторых версиях
NetWare).

Ошибки (возвращаемые в качестве результата функции)
------

     2     Файл не найден.

     18    Запрашивающая станция не имеет прав поиска.


GetServerDateTime
-----------------------------------------------------------------
Объявление
----------

     procedure GetServerDateTime(var Year : Word;
                   var Month, Day, Hour, Minute, Second : Byte;
                   var WeekDay : DayOfTheWeek);

Параметры
---------

     Year     Возвращаемый год (1900-1999).

     Month    Возвращаемый месяц (1..12).

     Day      Возвращаемый день месяца (1..31).

     Hour     Возвращаемый час (0..23).

     Minute   Возвращаемая минута (0..59).

     Second   Возвращаемая секунда (0..59).

     WeekDay  Возвращаемый день недели (Sunday..Saturday).

Описание
--------

     Возвращает сетевое время и дату из файл-сервера.

Примечания
----------

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


GetServerInfo
-----------------------------------------------------------------
Объявление
----------

     procedure GetServerInfo(var ServerInfo : ServerInformation);

Параметры
---------

     ServerInfo   Возвращается подробная информация, описывающая
                  сервер.


Описание
--------

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


GetWSInfo
-----------------------------------------------------------------
Объявление
----------

     procedure GetWSInfo(var ShellMajor, ShellMinor
                             ShellRevision : Byte;
                         var OSType, OSVer, Hardware : Str10);

Параметры
---------

     ShellMajor     Десятичная часть версии оболочки NetWare.

     ShellMinor     Дробная часть.

     ShellRevision  Номер ревизии оболочки.

     OSType         Тип версии NetWare.

     OSVer          Строковое представление номера версии.

     Hardware       Тип аппаратного обеспечения сети.


Описание
--------

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

IsLockModeExtended
-----------------------------------------------------------------
Объявление
----------

     function IsLockModeExtended : Boolean;

Параметры
---------

     Результат   True при использовании расширенного режима
                 запирания; False в противном случае.

Описание
--------

     Возвращает True  при   использовании   расширенного   режима
запирания Advanced NetWare. В противном случае запирания возможны
в режиме  совместимости,  который   должен   использоваться   при
выполнении прикладной программы в NetWare версий до 4.61.

     Запирания в режиме совместимости выполняются по умолчанию.


MakeFileShareable
-----------------------------------------------------------------
Объявление
----------

     function MakeFileShareable(Path : PathName) : Boolean;

Параметры
---------

     Path       Имя файла DOS.

     Результат  0 при успешном завершении; иначе код ошибки DOS.


Ошибки (возвращаемые в качестве результата функции)
------

     0   Успешное завершение.

     2   Файл не найден.

     5   Доступ не разрешен.


Описание
--------

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


NetWareLoaded
-----------------------------------------------------------------
Объявление
----------

     function NetWareLoaded(var LoggedOn : Boolean) : Boolean;

Параметры
---------

     LoggedOn    Возвращает True, если станция зарегистрировалась
                 в сети; иначе False.

     Результат   Возвращает True, если NetWare API доступны.

Описание
--------

     Прикладные программы,  которым  нужен  доступ  к   служебным
средствам NetWare, должны первой вызывать эту подпрограмму, чтобы
гарантировать, что оболочка  NetWare  (обычно  это  NET3.COM  или
ANET3.COM) была  загружена  на текущей рабочей станции.  Параметр
 задает,  была ли текущая  станция  зарегистрирована  в
сети. Все   это  необходимо,  чтобы  прикладная  программа  могла
успешно использовать подпрограммы модуля NETWARE.


SetExtFAttr
-----------------------------------------------------------------
Объявление
----------

     function SetExtFAttr(Path : PathName; Attr : Byte) : Byte;

Параметры
---------

     Path       Имя файла DOS.

     Attr       Устанавливаемые расширенные атрибуты.

     Результат  0 при успешном завершении; иначе код ошибки NetWare.


Описание
--------

     Устванавливает расширенные  атрибуты файла  в значение
. Дополнительную информацию о  возможных  атрибутах  см.  в
описании .

Ошибки (возвращаемые в качестве результата функции)
------

     0   Успешное завершение.

     2   Файл не найден.

     5   Доступ не разрешен.



SetLockMode
-----------------------------------------------------------------
Объявление
----------

     procedure SetLockMode(Extended : Boolean);

Параметры
---------

     Extended   True, чтобы разрешить расширенный режим запирания;
                False, чтобы запретить.

Описание
--------

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




Трассировка транзакций
----------------------

     Novel Advanced NetWare SFT (NetWare,  устойчивая к системным
сбоям)  обеспечивает  сложную  систему  трассировки   транзакций,
позволяющую  улучшить  целостность  данных.  Благодаря  сервисным
средствам  трассировки  транзакций  (TTS)  сетевая   операционная
система  может  гарантировать,  что  либо  вся последовательность
операций запишется на диск,  либо на диск  не  запишется  ничего.
Модуль NETWARE также поддерживает эти фукции:

     - Определение, доступны ли сервисные средства TTS;

     - Начало, конец или абортирование транзакции;

     - Проверка статуса транзакции;

     - Отмена или разрешение трассировки транзакции.

     NetWare поддерживает   две  категории  транзакций:  явную  и
неявную. Явные   транзакции   инициируются,   когда    прикладная
программа выполняет   явное  обращение  к  операционной  системе.
Неявная транзакция начинается автоматически,  когда  операционная
система распознает,   что   прикладная   программа   активировала
конкретные уровни запирания записей.  Здесь документирован только
явный метод; более подробную информацию о неявных транзакциях см.
в документации Novell и описаниях  процедур    и
.


Примеры
-------

     Наиболее часто   TTS   используются   во  время  добавления,
удаления или модификации записи базы данных. TSS особенно ценны в
этом случае тем,  что они могут гарантировать, что вся транзакция
целиком - обновление файла данных и связанных  с  ним  индексов,-
произойдет полностью,  либо  не  произойдет  вообще.  Даже  режим
сохранности B-Tree Filer сам по себе этого обеспечить  не  может.
Следующий пример,  основанный на подпрограммах, рассматриваемых в
Главе 6, показывает макет такого рода использования TTS.

     var
       UseTTS : Boolean;
       TransactionActive : Boolean;

     procedure BeginTransaction;
     begin
       if UseTTS and not TransactionActive then
         case TTSBegin of
           0, $FE, $FF : TransactionActive := True;
         else
           {Выход за пределы рабочей области. Обработка ошибки}
         end;
     end;

     procedure EndTransaction;
     var
       ID : LongInt;
       Retries : Word;
     begin
       if UseTTS and TransactionActive then
         case TTSEnd(ID) of
           0, $FE :
             begin
               Retries := 0;
               while Retries < 100 do begin
                 if TTSStatus(ID) then
                   { Транзакция записана на диск }
                   Exit;
                 Delay(100);
                 inc(Retries);
               end;
               { Транзакция утеряна. Обработка ошибки }
             end;
         else
           { TTS отменены. Обработка ошибки }
         end;
     end;

     procedure AbortTransaction;
     begin
       if UseTTS and TransactionActive then
         case TTSAbort of
           0, $FE, $FF : TransactionActive := False;
         else
           { TTS отменены. Обработка ошибки }
         end;
     end;

  function AddRecord(P : PersonDef) : Boolean;
  var
    KeyNr : Integer;
    RefNr : LongInt;
    Key : IsamKeyStr;
  begin
    AddRecord := False;

    {Запереть базу данных}
    repeat
      LockFileBlock(PF);
    until not IsLockError(True);

    { Начать транзакцию }
    BeginTransaction;

    AddNetRec(PF, RefNr, P);
    if not IsamOK then begin
      {Обработка ошибки}
      UnlockFileBlock(PF);
      AbortTransaction;
      Exit;
    end;

    for KeyNr := 1 to NrKeys do begin
      Key := CreateKey(P, KeyNr);
      AddNetKey(PF, KeyNr, RefNr, Key);
      if not IsamOK then begin
        {Удаление добавленных до сих пор ключей}
        UndoAdd(P, RefNr, KeyNr-1);
        {Удаление новой записи}
        DeleteNetRec(PF, RefNr);
        {Обработка ошибки}
        UnlockFileBlock(PF);
        AbortTransaction;
        Exit;
      end;
    end;

    UnlockFileBlock(PF);
    if IsamOK then
      EndTransaction;
    AddRecord := IsamOK;
  end;

var
  LoggedOn : Boolean;

begin
  {Убедиться, что TTS доступны}
  UseTTS := False;
  if NetWareLoaded(LoggedOn) then
    if LoggedOn then
      UseTTS := TTSAvailable ;
  TransactionActive := False;
  ...
end.

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

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

     В случае,  если  произошла  ошибка,  подпрограмма  AddRecord
должна выполнить  те  же  действия  по  "откату  назад",  что и в
случае, когда  TTS  не  используются.  Эти  действия  состоят   в
обновлении собственных    внутренних    буферов   B-Tree   Filer;
AbortTransaction гарантирует,  что ни одно из этих обновлений  на
диске отражено не будет.

     И наконец   отметим,   что   прикладная   программа   должна
определить доступность TTS до того,  как  пытаться  обращаться  к
ним. Еще  один важный шаг показан не был.  Прежде чем трассировка
транзакций может быть использована для любого файла,  этому файлу
должен быть   присвоен   расширенный   файловый  атрибут  Novell,
позволяющий выполнять трассировку.  Дополнительную информацию  об
этом см.  выше,  в  описании  .  Для файлового блока
B-Tree Filer соответствующий атрибут должен быть  присвоен файлам
данных, индексов и диалога.


TTSAbort
-----------------------------------------------------------------
Объявление
----------

     function TTSAbort : Byte;

Параметры
---------

     Результат     0 при успешном завершении; иначе код ошибки NetWare.

Описание
--------

     Абортирует любую подвешенную транзакцию. Успешное завершение
 означает "возвращенную"  транзакцию,  т.е.  что  любые
обновления диска,    связанные   с   данной   транзакцией,   были
аннулированы или удалены из буферов  памяти.  Чтобы  эта  функция
могла работать, TTS должны быть доступны и разрешены.

Ошибки
------

     $FD   TTS запрещены ("возврат" транзакции не получился).

     $FE   Транзакция абортирована, но записи остались запертыми.

     $FF   Активных транзакций не было.

Примечания
----------

     Абортирование транзакции  обычно  освобождает  все  запертые
физические и логические записи, связанные с данной транзакцией.


TTSAvailable
-----------------------------------------------------------------
Объявление
----------

     function TTSAvailable : Boolean;

Параметры
---------

     Результат    True, если TTS доступны; иначе False.

Описание
--------

     Эта функция  должна   вызываться   раньше   всех   остальных
подпрограмм TTS,  чтобы  определить доступность сервисных средств
трассировки транзакций (TTS).


TTSBegin
-----------------------------------------------------------------
Объявление
----------

     function TTSBegin : Byte;

Параметры
---------

     Результат    0 при успешном завершении;
                  иначе код ошибки NetWare.

Описание
--------

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

Ошибки  (возвращаемые в качестве результата функции)
------

     $96   Выход за пределы динамической рабочей области.

     $FE   Неявная транзакция уже активна
           (неявная транзакция теперь превратилась в явную).

     $FF   Явная транзакция уже активна
           (существующая транзакция продолжается).

     Только $96  рассматривается  как  условие  ошибки.  Есл  это
возможно6 программа   позже   должна   попытаться  повторить  эту
функцию.

Примечания
----------

     Для того,  чтобы  файл  мог  быть использован с трассировкой
транзакций, он должен быть помечен  (флагом)  как  транзакционный
(см. ).  Кроме  того,  сервисные средства TTS должны
быть доступны и разрешены (см.  и ).

     Неявные транзакции,  упомянутые в описании ошибки $FE, здесь
не описываются.  Более подробную информацию см.  в Справочнике по
API Novell, том 2.


TTSDisable
-----------------------------------------------------------------
Объявление
----------

     function TTSDisable : Boolean;

Параметры
---------

     Результат    True, если сервисные средства TTS выключены;
                  иначе False.

Описание
--------

     Выключает сервисные   средства  TTS  (для  всей  сети).  Для
выключения TTS  вызывающая  программа  должна  иметь   привилегии
консоли (см. .

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


TTSEnable
-----------------------------------------------------------------
Объявление
----------

     function TTSEnable : Boolean;

Параметры
---------

     Результат    True, если сервисные средства TTS включены;
                  иначе False.

Описание
--------

     Включает сервисные   средства   TTS.   Для   включения   TTS
вызывающая   программа   должна  иметь  привилегии  консоли  (см.
. Если TTS доступны, то они активны по умолчанию.

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

Примечания
----------

     Всегда проверяйте доступность TTS  (вызовом  )
перед использованием .  NetWare может вернуть True для
, если TTS не доступны,


TTSEnd
-----------------------------------------------------------------
Объявление
----------

     function TTSEnd(var ID : LongInt) : Byte;

Параметры
---------

     ID        Возвращается относительный номер транзакции.

     Результат    0 при успешном завершении;
                  иначе код ошибки NetWare.

Описание
--------

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

Ошибки  (возвращаемые в качестве результата функции)
------

     $9D   TTS выключены.

     $FE   Транзакция закончена, но записи остались запертыми.

     $FF   Активной транзакции не было.

Примечания
----------

     Если до  полного  отображения  транзакции на диске произошел
сбой сервера, при его перезагрузке любые изменения будут отменены
("откат").

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

     Абортирование транзакции  обычно  освобождает  все  запертые
физические и логические записи, связанные с данной транзакцией.


TTSStatus
-----------------------------------------------------------------
Объявление
----------

     function TTSStatus(ID : LongInt) : Boolean;

Параметры
---------

     ID        Возвращаемый  относительный номер транзакции.

     Результат    True, если транзакция успешно записана на диск;
                  иначе False.

Описание
--------

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

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

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


Буферизация печати
------------------

     Следующий набор   подпрограмм   модуля   NETWARE   управляет
функциями буферизации   печати   в   сети.    Поскольку    термин
"буферизация" используется  программистами  в нескольких смыслах,
необходимо дать  несколько  определений.  Когда  рабочая  станция
NetWare активирует буферизацию,  весь выход,  обычно направляемый
на локальный принтер по умолчанию (например,  LPT1), направляется
вместо этого в файл перехвата файл-сервера.  Затем с точки зрения
прикладной программы печать происходит как обычно,  хотя на самом
деле выход  программы просто добавляется в файл перехвата.  Далее
возможны три  действия.  Прикладная  программа  может  нормальным
способом завершить буферизацию,  и вэтом случае NetWare закрывает
файл перехвата и ставит этот файл в  очередь  заданий  на  печать
принтером сервера.  Прикладная  программа может "сбросить" буфер,
что означает закрытие текущего файла перехвата,  передачу  его  в
очередь на  печать и открытие другого файла перехвата,  в котором
продолжается буферизация.   Либо   прикладная   программа   может
абортировать буферизацию, что означает закрытие и удаление файлов
перехвата и восстановление вывода печати на локальный принтер.

     Для поддержки  этих  операций   NETWARE   включае   в   себя
следующее:

     - Идентификация   или   изменение   локального  принтера  по
умолчанию;

     - Включение или выключение буферизации печати;

     - Сброс буфера на принтер;

     - Определение того, активна ли буферизация;

     - Получение статуса принтера;

     - Управление страничными заголовками при печати.


Примеры
-------

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

     var
       LPT : Text;
       PrintJob : PrintJobType;
       CaptureStatus : Byte;
     begin
       {Открыть доступ из Turbo Pascal к принтеру}
       Assign(LPT, 'LPT1');
       Rewrite(LPT);

       { Обеспечить перехват NetWare вывода LPT }
       SetDefaultLocalPrinter(LPT1);

       { Определить характеристики распечатки }
       GetPrintJobFlags(PrintJob);

       if PrintJob.Flags <> 0 then begin
         {Модификация любых желаемых полей в PrintJob}
         ...
         SetPrintJobFlags(PrintJob);
       end;

       {Начать буферизацию}
       CaptureStatus := StartLPTCapture;
       if CaptureStatus <> 0 then
         {Обработка ошибки};

       {Запись вывода в LPT1, перехватываемая NetWare}
       WriteLn(LPT, 'Привет');

       {Передача выведенного до сих пор на печать в очередь}
       Flush(LPT);
       CaptureStatus := FlushLPTCapture;

       {Буферизация вывода на принтер при этом продолжается}
       WriteLn(LPT, 'До свидания');

       {Передача выведенного до сих пор на печать в очередь
        и конец перехвата}
       Close(LPT);
       CaptureStatus := EndLPTCapture;
     end.

     Данный принтер  явно  открывает  локальный  принтер LPT1 как
текстовый файл.  В этой программе можно также использовать  (USE)
модуль PRINTER фирмы Borland.

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

     Отметим вызовы  подпрограмм  Turbo  Pascal  Flush  и  Close.
Прикладная программа должна  вызвать их перед вызовом подпрограмм
NetWare FlushLPTCapture и EndLPTCapture,  чтобы обеспечить запись
внутренних буферов Turbo.

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


Типы
----

     PrinterDevice = (LPT1, LPT2, LPT3);

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

     PrintJobType =
       record
         Status : Byte;
         Flags : Byte;
         TabSize : Byte;
         ServerPrinter : Byte;
         NumCopies : Byte;
         FormType : Byte;
         Reserved : Byte;
         Banner : Array[1..13] of Char;
         LocalLPT : Byte;
         FlushCaptureTimeout : Word;
         FlushCaptureOnClose : Byte;
       end;

     Описывает распечатку.  Более  подробную  информацию  см.   в
описании функции .


CancelLPTCapture
-----------------------------------------------------------------
Объявление
----------

     function CancelLPTCapture : Byte;

Параметры
---------

     Результат     0 при успешном завершении;
                   иначе код ошибки NetWare.

Описание
--------

     Прекращает перехват  выхода  на  локальный   принтер.   Файл
перехвата не ставится в очередь на печать, а напротив, удаляется.
Чтобы избежать  печати,  вызовите    до  вызова
 или .

     Для того,  чтобы  возобновить  перехват  выхода  на  печать,
вызовите .


Ошибки (возвращаемые в качестве результата функции)
------

     Novell не задает каких-либо кодов ошибки, но любое ненулевое
значение означает, что произошла ошибка.


EndLPTCapture
-----------------------------------------------------------------
Объявление
----------

     function EndLPTCapture : Byte;

Параметры
---------

     Результат     0 при успешном завершении;
                   иначе код ошибки NetWare.

Описание
--------

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

     Для того,  чтобы  возобновить  перехват  выхода  на  печать,
вызовите .

Ошибки (возвращаемые в качестве результата функции)
------

     Novell не задает каких-либо кодов ошибки, но любое ненулевое
значение означает, что произошла ошибка.


FlushLPTCapture
-----------------------------------------------------------------
Объявление
----------

     function FlushLPTCapture : Byte;

Параметры
---------

     Результат     0 при успешном завершении;
                   иначе код ошибки NetWare.

Описание
--------

     Ставит текущий  файл перехвата в очередь на печать сервера и
начинает новый  файл  перехвата.  Не  вызывайте,  пока  не  будет
вызвана .

Ошибки (возвращаемые в качестве результата функции)
------

     Novell не задает каких-либо кодов ошибки, но любое ненулевое
значение означает, что произошла ошибка.


GetBannerUser
-----------------------------------------------------------------
Объявление
----------

     function GetBannerUse(var BannerUser : Str20) : Boolean;

Параметры
---------

     BannerUser   Возвращается имя пользователя, печатаемое на
                  страничном заголовке.

     Результат    True, если функция поддерживается;
                  иначе False.

Описание
--------

     При использовании  средств  буферизации  NetWare  страничный
заголовок, идентифицирующий каждое задание  печати,  предшествует
самой распечатке.    возвращает  имя  пользователя,
которое будет   появляться   на   страничном    заголовке.    Имя
пользователя может  быть  изменено  вызовом .  Эти
функции поддерживаются только Advanced  NetWare  версии  2.1  или
старше.


GetDefaultLocalPrinter
-----------------------------------------------------------------
Объявление
----------

     function GetDefaultLocalPrinter : PrinterDevice;

Параметры
---------

     Результат    Устройство LPT, доступное для перехвата.

Описание
--------

     Все связанные с печатающими устройствами подпрограммы модуля
NETWARE работают  с  локальным  принтером  по  умолчанию.  Данная
подпрограмма определяет,   который   принтер   в  текущий  момент
является умолчанием  для  NetWare.  Принтер  по  умолчанию  можно
изменить при помощи .


GetPrinterStatus
-----------------------------------------------------------------
Объявление
----------

    procedure GetPrinterStatus(ServerPrinter  : Byte;
                               var PrinterNo, FormType : Byte;
                               var OffLine, Stopped : Boolean);

Параметры
---------

     ServerPrinter   Номер принтера в сети (0..4).

     PrinterNo       Возвращает то же, что и ServerPrinter,
                     пока не будет перенаправлен в сервере.

     FormType        Тип бланка, выбранный в текущий момент
                     для данного принтера (0..255).

     OffLine         True, если принтер в положении "офлайн".

     Stopped         True, если принтер был остановлен в сервере.


Описание
--------

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


GetPrintJobFlags
-----------------------------------------------------------------
Объявление
----------

     procedure GetPrintJobFlags(var PrintJob : PrintJobType);

Параметры
---------

     PrintJob     Возвращаемая запись, описывающая задание на печать.


Описание
--------

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

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

   В случае нулевого значения задание на печать является
           активным, и остальные флаги не могут быть изменены.

    Байт, битовое множество которого интерпретируется
           следующим образом:

  7  6  5  4  3  2  1  0
  |  |        |  |
  |  |        |   ------------ Печать прерванного перехвата
  |  |         --------------- Подавление автоматического прогона
  |  |                         бланка в конце задания
  |   ------------------------ Включение расширенной табуляции
   --------------------------- Печать страничного заголовка

     Значение по  умолчанию  для  флагов  равно  80h,  вызывающее
печать страничного заголовка.

   Число пробелов для каждой табуляции (1..18).

   Принтер сервера, используемый для вывода (0..4).

 Число печатаемых копий.

  Бланк, устанавливаемый на принтере в начале печати.
            Когда бланк должен быть не тот, что установлен в
            текущий момент, на консоль сервера выводится сообщение.
            Тип бланка по умолчанию 8.

    Имя печатаемое в заголовке. Если там заданы все нули,
            то печатается имя файла перехвата.

  Локальный принтер, вывод на который перехватывается
            (0..2).


LPTCaptureActive
-----------------------------------------------------------------
Объявление
----------

     function LPTCaptureActive(var QueServer : Byte) : Boolean;

Параметры
---------

     QueServer    Возвращается подсоединительный номер сервера
                  с очередью.

     Результат    True, если буферизация активна; иначе False.


Описание
--------

     Возвращает True, если выход на локальный принтер перехвачен.
Параметр ,  инициализируемый  только  если   результат
равен True,  возвращает  подсоединительный  номер (1..8) сервера,
обслуживающего очередь печати.


SetBannerUser
-----------------------------------------------------------------
Объявление
----------

     function SetBannerUser(UserName : Str20) : Boolean;

Параметры
---------

     UserName    Имя пользователя для печати на страничных
                 заголовках, 12 символов максимум.

     Результат    True, если функция поддерживается;
                  иначе False.

Описание
--------

     При использовании  средств  буферизации  NetWare  страничный
заголовок,  идентифицирующий каждое задание печати,  предшествует
самой распечатке.  задает имя пользователя, которое
будет  появляться  на  страничном  заголовке.  Имя  пользователя,
установленное в текущий момент,  может  быть  определено  вызовом
.   Эти  функции  поддерживаются  только  Advanced
NetWare версии 2.1 или старше.


SetDefaultLocalPrinter
-----------------------------------------------------------------
Объявление
----------

     procedure SetDefaultLocalPrinter(LPTNo : PrinterDevice);

Параметры
---------

     LPTNo      Новый локальный принтер по умолчанию (LPT1,
                LPT2 или LPT3).

Описание
--------

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


SetPrintJobFlags
-----------------------------------------------------------------
Объявление
----------

     procedure SetPrintJobFlags(var PrintJob : PrintJobType);

Параметры
---------

     PrintJob     Возвращаемая запись, описывающая задание на печать.


Описание
--------

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

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


StartLPTCapture
-----------------------------------------------------------------
Объявление
----------

     function StartLPTCapture : Byte;

Параметры
---------

     Результат     0 при успешном завершении;
                   иначе код ошибки NetWare.

Описание
--------

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

     Буферизованный локальный принтер по умолчанию назначается на
LPT1. Для  определения  текущего  локального  принтера   вызовите
. Для   изменения   установки  локального
принтера по умолчанию вызовите .




Базовые сервисные средства обмена сообщениями в сети
----------------------------------------------------

     NetWare имеет   средства   пересылки  сообщений  несколькими
различными способами.  Широковещательные сообщения  -  это  очень
короткие строки   (менее  56  символов),  выводимые  на  мониторе
принимающей рабочей   станции.    Каналы    передачи    сообщений
обеспечивают простой  метод  пересылки  коротких сообщений (менее
127 символов)  от  станции  к  станции,  используя   в   качестве
посредника сервер.    Модуль   NETWARE   обеспечивает   следующие
подпрограммы для доступа к этим сервисным функциям:

     - Прием подсоединительных  номеров  (номеров  узла)  рабочих
станций и серверов.

     - Ассоциирование    физических    адресов    с   именами   и
подсоединениями.

     - Прием  или  установка  режима  широковещания  (вывод   или
игнорирование широковещательных сообщений).

     - Передача широковещательных сообщений.

     - Чтение висящего широковещательного сообщения.

     - Открытие, проверка или закрытие канала сообщений.

     - Пересылка или прием сообщения по каналу.

     Ни один  из  этих  методов  не  гарантирует,  что получатель
сможет прочесть сообщение.  Для  эффективной  передачи  сообщений
между узлами  сети  с гарантированной доставкй Novell рекомендует
сервисные средства SPX (описываемые ниже).

Примеры
-------

     Поставляемая программа  MESEXAMP.PAS  демонстирует несколько
методов, используемых для передачи сообщений по  локальным  сетям
NetWare и  NetBios.  В  этом  разделе  вводятся  методы  передачи
широковещательных и канальных сообщений, используемые программой.

     Пересылка сообщения на консоль NetWare (на  файл-сервере  по
умолчанию) представляет  собой  самый простой из методов.  Строка
может иметь до 60 символов в длину.

     BroadcasrToConsole('Привет оператору консоли!');

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

     LogNetWorkMessage('примечание для файла журнала');

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

     procedure AllConnections(var Connect : ConnectionList);
     var
       I : Word;
       ServerInfo : ServerInformation;
     begin
       GetServerInfo(ServerInfo);
       with Connect do begin
         {Добавить в список все допустимые соединения}
         Count : ServerInfo.MaxConns;
         for I := 1 to Count do
           List[I] := I;
         {Удалить из списка себя}
         List{GetConnNo] := List[Count];
         Dec(Count);
       end;
     end;

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

     Если же сообщение должно быть послано только на  те станции,
пользователи которых зарегистрировались под конкретным именем, то
можно использовать следующую подпрограмму:

     procedure NamedConnections(Name : String;
                                var Connect : ConnectionList);
     var
       I : Word;
       Conn : Word;
       ServerInfo : ServerInformation;
     begin
       GetServerInfo(ServerInfo);
       with Connect do begin
         Count := 0;
         {Добавить в список все соответствующие соединения}
         for I := 1 to ServerInfo.MaxConns do begin
           Conn := GetConnFromName(I, I, Name);
           if Conn <> ) then begin
             Inc(Count);
             List[Count] := Conn;
           end;
         end;
       end;
     end;

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

     procedure Broadcast(Msg : BroadcastStr;
                         var Connect : ConnectionList);
     var
       I : Word;
       Result : ConnectionList;
     begin
       SendBroadcastMsg(Msg, Connect, Result);
       {Посмотрим, кто может его получить}
       for I := 1 to Result.Count do
         if Result.List[I] <> 0 then
           {Connect.List[I] не был подсоединен};
     end;

     Самое длинное широковещательное сообщение не может превышать
55 символов. Показанный выше цикл проверки в основном бесполезен,
поскольку он проверяет только,  была ли  данная  рабочая  станция
зарегистрирована в сети,  а не то,  получила ли она сообщение. По
умолчанию сообщение выводится в 25-й  строке  экрана  принимающей
станции. Однако,    любая    рабочая    станция   может   вызвать
, чтобы изменить данное умолчание; в результате
широковещательное сообщение  может  либо  вообще  игнорироваться,
либо помещаться  в  буфер   и   читаться   впоследствие   вызовом
.

     Канальные сообщения  начинаются с того же списка соединений,
но требуют дополнительных шагов перед их посылкой.  Канал  должен
быть открыт  как  посылающей,  так  и принимающей сторонами,  что
требует определенной степени взаимодействия  между  ними.  Каждая
сторона сначала  создает список соединений при помощи подпрограмм
типа AllConnections или NamedConnections.  Затем  каждая  сторона
пытается открыть свою половину канала следующим образом:

     function UserBreak : Boolean;
     begin
       IPXRelinquish;
       UserBreak := KeyPressed;
     end;

     procedure OpenPipe(Target : ConnectionList;
                        var Actual : ConnectionList);

     var
       I : Word;
       Result : ConnectionList;
     begin
       repeat
         OpenMessagePipe(Target, Result);
         Actual.Count := 0;
         for I := 1 to Result.Count do
           if Result.List[I] = 0 then brgin
             inc(Actual.Count);
             Actual.List[Actual.Count] := Target.List[I];
           end
       until (Actual.Count > 0) or UserBreak;
     end;

     Вариантов здесь  может  быть  множество.  Выход  из OpenPipe
происходит, когда  какая-либо  соединенная  станция  откликнется,
либо при нажатии клавиши.  Можно сделать и так, чтобы она ожидала
ответа от  всех  соединений  (задав   в   цикле   until   условие
Actual.Count = Target.Count).



     Внимание !!!!

     Отсутствует разворот со страницами 232-233 !!!!!


CheckMessagePipe
-----------------------------------------------------------------
Объявление
----------

     procedure CheckMessagePipe(var Connect, Result : ConnectionList);

Параметры
---------

     Connect     Проверяемый список соединений.

     Result      Коды, возвращаемые для каждого из соединений

Описание
--------

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

     0     Успешное завершение (канал сообщения является полным).

     $FE   Неполный канал (канал от сервера к назначению
           не существует).

     $FF   Неудача (неверный номер соединения или калал от передающей
           стороны к серверу не существует).

CloseMessagePipe
-----------------------------------------------------------------
Объявление
----------

     function CloseMessagePipe(var Connect, Result : ConnectionList)
                               : Byte;

Параметры
---------

     Connect     Список закрываемых соединений.

     Result      Коды, возвращаемые для каждого из соединений.

     Результат
     функции     0 при успешном завершении;
                 иначе код ошибки NetWare.


Описание
--------

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

     0    Успешное завершение (канал разорван).

     $FD  Неудача (Станция назначения неверно задана или больше
          не используется).

     $FF  Такого канала не существует.

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


Ошибки (возвращаемые в качестве результата функции)
------

     $FC   Очередь сообщений полна (каналы не закрыты).


GetBroadcastMode
-----------------------------------------------------------------
Объявление
----------

     function GetBroadCastMode : Byte;

Параметры
---------

     Результат     Возвращается режим широковещания рабочей станции
                   (0..3).

Описание
--------

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

     Режим     Сервер         Оболочка
     -----     -------        --------
       0       Сохраняет      Берет и выводит на дисплей
       1       Отвергает      Берет и выводит на дисплей
       2       Отвергает      Игнорирует
       3       Сохраняет      Игнорирует

     Когда "Сервер" имеет режим  "Отвергает",  сервер  игнорирует
любые сообщения,  предназначенные для текущей рабочей станции (за
исключением широковещательных сообщений самого  сервера,  которые
посылаются всегда). Когда "Оболочка" имеет режим "Берет и выводит
на дисплей"    ,    оболочка    NetWare    немедленно     выводит
широковещательное сообщение  в  строке 25 терминала.  В противном
случае рабочая станция может  опрашивать  наличие  сообщение  при
помощи вызова .

     По умолчанию  режим  устанавливается  режим широковещания 0.
Каждая рабочая станция имеет собственный режим широковещания.

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


GetBroadcastMsg
-----------------------------------------------------------------
Объявление
----------

     procedure GetBroadcastMsg(var Message : Str80);

Параметры
---------

     Message    Возвращается подвешенное сообщение.

Описание
--------

     Возвращает подвешенное   широковещательное  сообщение,  если
таковое имеется.  В  противном  случае    вернет  пустую
строку. Длина возвращаемой строки максимально равна 55 символов.

     NetWare поддерживает 4 различных "режима широковещания". Эти
режимы определяют поведение сервера и рабочей станции  при приеме
или посылке   широковещательного   сообщения.   Блоее   подробную
информацию см.  в описании .  
полезна только   для   режимов   2  и  3;  в  остьальных  режимах
широковешательные сообщения либо игнорируются,  либо выводятся на
экран оболочкой NetWare.



GetConnFromName
-----------------------------------------------------------------
Объявление
----------

     function GetConnFromName(LoConn, HiConn : Byte,
                              ObjName : String) : Byte;

Параметры
---------

     LoConn      Первый проверяемый номер соединения (1..100).

     HiConn      Последний проверяемый номер соединения (1..100).

     ObjName     Искомое зарегистрированное имя.

     Результат   Достоверный номер соединения, или 0,
                 если соответствие не найдено.


Описание
--------

     Данная подпрограмма просматривает все подсоединенные рабочие
станции в диапазоне от  до ,  чтобы найти один, с
зарегистрированным именем,    заданным    в    .   Поиск
выполняется без  учета  регистров.    возвращает
первый найденный  номер  соединения с данным именем.  Если оно не
найдено, то возвращаемое значение равно 0.

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

Примечания
----------

      игнорирует     номера    соединений    вне
допустимого диапазона для конкретной версии  NetWare.  (Например,
ELS II  поддерживает  диапазон  соединений только от 1 до 8).  За
исключением случая, когда имеются дубликаты регистрационных имен,
задание в диапазоне 1..100 всегда безопасно.


GetConnNo
-----------------------------------------------------------------
Объявление
----------

     function GetConnNo : Byte;

Параметры
---------

     Результат     Номер соединения для вызывающей программы.

Описание
--------

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

Примечания
----------

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


GetInternetAddress
-----------------------------------------------------------------
Объявление
----------

     procedure GetInternetAddress(ConnNo : Byte;
                                  var InterNetAdd : IPXAddress);

Параметры
---------

     ConnNo       Номер соединения, адрес которого принимает
                  эта процедура.

     Результат    Возвращаемый физический адрес соединения.

Описание
--------

     Эта подпрограмма  используется  для  трансляции   известного
номера соединения  в  физический  адрес,  подходящий  для посылки
сообщений IPX и SPX.   возвращает  достоверные  поля
 и  для .  Возвращаемый номер 
идентифицирует гнездо,   которое   локальная   оболочка   NetWare
использует для  коммуникаций  с  сервером.  Это  гнездо не должно
использоваться другими прикладными программами.

     Если заданный    неверен,  то   возвращаемый   адрес
Internet заполнен нулями.


GetMessagePipe
-----------------------------------------------------------------
Объявление
----------

     procedure GetMessagePipe(var SourceConn : Byte;
                              var Msg : MessageStr) ;

Параметры
---------

     SourceConn    Возвращается номер соединения посылающей стороны.

     Msg           Возвращаемое сообщения.

Описание
--------

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

     Более подробную информацию см. в описаниях 
и .


LogNetworkMessage
-----------------------------------------------------------------
Объявление
----------

     procedure logNetworkMessage(Message : Str80);

Параметры
---------


     Message    Регистрируемое сообщение.

Описание
--------

     Добавляет заданное сообщение в файл NET$LOG.MSG файл-сервера
по умолчанию.   NetWare   автоматически   предпосылает  сообщению
текущие дату и время,  а также номер  соединения  для  вызывающей
программы. Эта  подпрограмма  предназначена  для  использования в
программах, которым   требуется   регистрация    информация    об
их использовании в административных целях.



OpenMessagePipe
-----------------------------------------------------------------
Объявление
----------

     function OpenMessagePipe(var Connect, Result : ConnectionList);

Параметры
---------

     Connect     Список открываемых соединений.

     Result      Коды, возвращаемые для каждого из соединений.


Описание
--------

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

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


     0    Успешное завершение (канал теперь полон и открыт).

     $FE  Неполный канал (станция мишени существует, но не
          открыла свою половину).

     $FF  Неудача (номер соединения неверно задан или
          не используется).


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


SendBroadcastMsg
-----------------------------------------------------------------
Объявление
----------

     procedure SendBroadcastMsg(Msg : BroadcastStr;
                     var Connect, Result : ConnectionList);

Параметры
---------

     Msg          Посылаемое сообщение.

     Connect      Соединения, которым посылается сообщение.

     Result       Возвращает коды для каждой принимающей стороны.

Описание
--------

     Посылает широковещательное  сообщение  ко  всем соединениям,
заданным в .  (Детали см.  в описании ).
Длина сообщения   максимально   равна   55   символам.   
возвращает код для  каждого  заданного  соединения.  Для  каждого
элемента  в  возвращается следующий код:

     0     Успешная доставка сообщения.

     $FC   Станция - мишень уже имеет подвешенное сообщение
           (данное сообщение отвергается).

     $FD   Неверный номер соединения.

     $FF   Неверно задана станция-мишень
           (данное сообщение отвергается).

Примечания
----------

     Информацию о  том,  как  принимающая  станция  реагирует  на
широковещательное сообщение, см. в описании .



SendMessagePipe
-----------------------------------------------------------------
Объявление
----------

     procedure SendMessagePipe(Msg : MessageStr;
                    var Connect, Result : ConnectionList);

Параметры
---------

     Msg          Посылаемое сообщение.

     Connect      Список соединений, которым посылается сообщение.

     Result       Возвращает коды для каждого соединения.

Описание
--------

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

      задает   рабочую   станцию,   куда  будет  послано
сообщение.    возвращает   статус   каждой   доставки   с
использованием следующих кодов в поле :

     0    Успешное завершение (сообщение введено в канал).

     $FC  Канал полон (сообщение отвергается).

     $FE  Неполный канал (канал от сервера к станции мишени
          не существует).

     $FF  Неудача (номер соединения неверно задан или канал от
          посылающей стороны до сервера не существует).


Примечания
----------

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


ServerConnNo
-----------------------------------------------------------------
Объявление
----------

     function ServerConnNo : Byte;

Параметры
---------

     Результат   Номер соединения для сервера по умолчанию (1..8).

Описание
--------

     Соединения серверов  и  рабочих  станций  имеют  независимые
номера. Другими  словами,  первый  сервер  имеет номер соединения
сервера 1, а первая регистрируемая рабочая станция получает номер
соединения также 1.

     Номер соединения  для  файл-сервера в документации по Novell
часто называют номером гнезда.


SetBroadcastMode
-----------------------------------------------------------------
Объявление
----------

     procedure SetBroadCastMode(Mode : Byte);

Параметры
---------

     Mode   Новый режим широковещания (0..3).

Описание
--------

     Устанавливает режим широковещания в  значениие,  заданное  в
.  Этот  режим определяет,  каким образом рабочая станция и
сервер реагируют на широковещательные сообщения.  Он  может  быть
интерпретирован следующим образом:

     Режим     Сервер         Оболочка
     -----     -------        --------
       0       Сохраняет      Берет и выводит на дисплей
       1       Отвергает      Берет и выводит на дисплей
       2       Отвергает      Игнорирует
       3       Сохраняет      Игнорирует

     Когда "Сервер" имеет режим  "Отвергает",  сервер  игнорирует
любые сообщения,  предназначенные для текущей рабочей станции (за
исключением широковещательных сообщений самого  сервера,  которые
посылаются всегда). Когда "Оболочка" имеет режим "Берет и выводит
на дисплей"    ,    оболочка    NetWare    немедленно     выводит
широковещательное сообщение  в  строке 25 терминала.  В противном
случае рабочая станция может  опрашивать  наличие  сообщение  при
помощи вызова .

Примечания
----------

     Если вы модифицируете режим широковещания,  то рекомендуется
перед изменением сачала сохранить текущее состояние этого режима,
а затем, перед выходом из программы, восстановить его.


Расширенные сервисные средства обмена сообщениями в сети
--------------------------------------------------------

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

     IPX обозначает   Internetwork   Packet   eXchange   protocol
("протокол  пакетного  обмена в составной сети").  Это реализация
Novell протокола Datagram Packet Protocol,  разработанного фирмой
Xerox. Термин "составная сеть" обозначает как текущую сеть, так и
любые другие сети,  с которыми она может быть соединена "мостом".
IPX  требует  наличия  Advanced  NetWare  версии  270 или старше.
Прикладные программы,  работающие в Advanced NetWare,  используют
драйверы  IPX  для  прямой  связи  с  другими рабочими станциями,
серверами или устройствами.

     Каждое устройство в составной сети называется узлом и  имеет
уникальный адрес.  IPX позволяет узлу посылать пакет другому узлу
или принимать пакет от  него.  Пакетами  называются  произвольные
последовательности байтов  длиной  до  546 байтов.  IPX изолирует
прикладную программу от деталей физического маршрута пакета. Хотя
IPX не   гарантирует   доставку   пакета   (другой   узел   может
проигнорировать его),  его сервисные средства  позволяют  строить
протоколы гарантированной    доставки.   SPX   (описанный   ниже)
представляет собой протокол гарантированной доставки,  основанный
на IPX.

     Модуль NETWARE  реализует  подпрограммы  IPX,  от  низкой до
высокой степени  интеграции.  Подпрограммы  нижнего  уровня   это
просто процедуры  и  функции Паскаля,  непосредственно вызывающие
сервисные подпрограммы   IPX.   Подпрограммы   верхнего    уровня
изолируют программиста   от  деталей  формирования  пакетов  IPX.
Разработчики прикладных программ должны использовать подпрограммы
верхнего уровня.  Поскольку  подпрограммы  нижнего уровня требуют
детального понимания структур данных,  используемых  IPX,  мы  не
документируем их  здесь.  Программисты,  заинтересованные  в этом
вопросе, должны обратиться к Справочнику Novell API, Том 2.

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

     Чтобы послать   пакет  на  другой  узел,  необходимо  задать
несколько полей :

     - адрес сети, четырехбайтовое число;

     - адрес физического узла, честибайтовое число;

     - гнездо, двухбайтовое число.

     Адрес сети задает сеть узла назначения (требуется, поскольку
IPX может  соединять  несколько  сетей).  Если в это поле записан
ноль, то приемник относится к той же сети, что и передатчик.

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

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

     Вызывающая программа  должна   задать   номер   гнезда,   не
конфликтующий с  уже  активными  в текущий момент в сети.  Номера
гнезд в диапазоне от $4000 до  $7FFF  называются  "динамическими"
гнездами; они     предназначены    для    использования    любыми
пользователями сети.  Значения от $8000 и старше это "популярные"
гнезда, значения   которых   зарезервированы  Novell  для  широко
известных прикладных программ.  Гнезда со значениями менее  $4000
резервированы Novell для внутреннего использования.

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

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

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

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

     - определение доступности сервисных средств IPX;

     - получение адреса сети рабочей станции;

     - открытие, закрытие или выделение гнезда;

     - посылка или прием сообщения;

     - канцелирование запроса на посылку или прием;

     - освобождение и возврат управления драйверу IPX.


     Advanced NetWare  2.0  реализует   более   высокий   уровень
межузловых коммуникаций, который называется SPX (Sequenced Packet
Exchange Protocol - Протокол последовательного пакетного обмена).
SPX основан  на  протоколе  Sequenced Packet Protocol (SPP) фирмы
Xerox.

     Являясь надстройкой  над  сервисными  средствами  IPX,   SPX
обеспечивает систему  гарантированной  доставки  пакетов  данных.
Пакеты, получение которых не подтверждено получателем в  заданный
период времени,    автоматически   передаются   повторно.   После
неудачного завершения серии попыток передачи предполагается,  что
связь нарушена.   SPX   автоматически   выбирает  соответственную
уставку времени  и  число  попыток  передачи  в  зависимости   от
физических характеристик    сетевого   аппаратного   обеспечения.
Следовательно, прикладные программы, использующие SPX, не обязаны
входить в   подробности   относительно   гарантированной  системы
доставки. Поскольку SPX имеет больший  расход  памяти,  чем  IPX,
максимальный размер пакета несколько меньше: 534 байта.

     В отличие   от   канальных  и  широковещательных  сообщений,
соединение SPX  передает  сообщения  за  один  раз  между   двумя
конкретными узлами.  Во  время установки соединения SPX один узел
определяет себя в  качестве  передатчика,  а  второй  в  качестве
приемника. Исходное  соединение является односторонним;  приемник
не может отвечать  на  полученные  им  сообщения.  Хотя  и  можно
сделать соединение двусторонним,  реализовать данный метод в виде
универсальной подпрограммы     сложно.     Следовательно,     для
двусторонних соединений SPX вам предоставляются две альтернативы.
Вы можете открыть для обратного направления отдельное соединение;
этот способ    работает    достаточно   хорошо,   но   связан   с
использованием некоторой   дополнительной   памяти   и    времени
процессора. Второй   способ  состоит  в  том,  чтобы  рассмотреть
демонстрационные программы NSEND и NRECEIVE,  в которых показано,
как организовать реверсивную связь.

     Вызовы подпрограмм   нижнего   уровня   Novell   IPX  и  SPX
заключаются просто  в  сопоставлении  запроса   и   практического
события, связанного с сообщением.  Фактическое завершение события
не происходит  до  тех  пор,  пока  не   истечет   неопределенное
количество времени.  NetWare  требует  отдельный  блок управления
событием (типа  )  для  обработки  каждого   подвешенного
сообщения. Установление   SPX-соединения  между  двумя  станциями
требует фактически двух блоков  управления  событием  на  стороне
передатчика - один служит для посылки запроса,  и один для приема
подтверждения от приемника.

     Приемник сообщений SPX может потребовать, чтобы одновременно
было доступно  даже  большее  число  блоков  управления событием.
Предположим, что   приемник   ожидает   получение   10    пакетов
информации. Приемник  мог  объявить  всего  один  блок управления
событием. Он будет принимать каждый пакет,  обрабатывать его  при
получении и  быстро  делать единственный  снова доступным
для приема.  Однако, при таком подходе остается "окно", в течение
которого приходящий пакет может не найти доступного , что
приведет к потере пакета.  Более надежный подход состоит  в  том,
чтобы сделать  доступными  два  блока управления событием,  чтобы
гарантировать, что один из них всегда готов, если второй временно
занят. В  некоторых  случаях может оказаться желательным иметь 10
доступных блока управления событием;  тем  самым  вся  транзакция
может быть  завершена  без  переподчинения  управляющих  блоков в
отношении SPX.

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

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

     Модуль NETWARE обеспечивает  следующие  средства  доступа  к
SPX:

     - определение доступности сервисных средств SPX;

     - установление или отмена соединения SPX;

     - посылка или ожидание приема сообщения;

     - канцелирование запроса на посылку или прием.

Примеры
-------

     Поставляемая в  составе  продукта   программа   MESEXAMP.PAS
демонстрирует несколько  методов  передачи  сообщений в локальных
сетях NetWare и NetBIOS. В данном разделе вводятся методы NetWare
IPX и SPX,  используемые программой.  Перед использованием любого
из этих методов программа должна обеспечить доступность  NetWare,
IPX и SPX.

     
     procedure IPXSPXAvail(var IPXOK, SPXOK : Boolean);
     var
       Logged : Boolean;
       Version : Word;
       MaxConn : Word;
       AvailConn : Word;
     begin
       IPXOK := false;
       SPXOK := False;
       if NetWareLoaded(Logged) then
         if Logged then begin
           IPXOK := IPXServicesAvail;
           if IPXOK then
             SPXOK := ServicesAvail(Version, MaxConn, AvailConn);
         end;
     end;
     
     
     Следующая задача для любой прикладной программы,  работающей
с IPX или SPX,  состоит в том, чтобы определить адрес приемника в
составной сети.  При  использовании  IPX  сообщение  может   быть
послано всем  узлам  путем использования специального физического
адреса .  Процедура  может  работать
как для IPX, так и для SPX:
     
     var
       Receiver : IPXAddress;
     
       GetInternetAddress(ReceiverConn, Receiver);
     
     
     ReceiverConn это  номер  соединения  в NetWare (1..100).  Он
может быть  определен  из  регистрационного  имени   при   помощи
, как  показано в примерах для широковещательных
и канальных сообщений.
     
     Передатчик и  приемник  также  должны   согласвывать   номер
гнезда. Как обсуждалось выше,  обычный метод здесь состоит в том,
чтобы выбрать   произвольный   номер,    который    может    быть
модифицирован администратором сети:
     
     const
       IPXSocket : Word = $7001;
     
     Следующая функция показывает,  как послать сообщение  IPX  с
использованием глобального номера гнезда.
     
     function SendIPX(Receiver : IPXAddress;
                      MsgLen : Word;
                      var Msg) : Byte;
     var
       Status : Byte;
       IEvent : IPXRec;
     begin
       {Посылка сообщения}
       Status := IPXSend(IEvent,Receiver,IPXSocket,False,MsgLen,Msg);
       if Status <> 0 then bgin
         {MsgLen слишком велика, или таблица гнезд заполнена}
         SendIPX := Status;
         Exit;
       end;
       {Ожидание отправки сообщения}
       while not IPXEventComplete(IEvent, Status) do
       {При успешном завершении Status будет равен нулю}
       SendIPX := Status;
     end;
     
     Длина сообщения   может  достигать  546  байтов.  В  примере
используется нетипированный  параметр,   позволяющий   пересылать
любой тип данных.  Если заданное гнездо в этот момент не является
уже открытым,  то  открывает его. SendIPX возвращает код
статуса, указывающий возможность посылки сообщения.  При возврате
ненулевого кода  вызывающая   программа   может   соответственным
образом выполнить обработку ошибки.
     
     Приемник после  обращения к глобальному номеру гнезда должен
использовать следующую функцию.
     
     function ReceiveIPX(MaxLen : Word;
                         var Msg) : Byte;
     var
       Status : Byte;
       IEvent : IPXRec;
     begin
       {Ожидание сообщения}
       Status := IPXListen(IEvent,IPXSocket,False,MaxLen,Msg);
       if Status <> 0 then bgin
         {MaxLen слишком велика, или таблица гнезд заполнена}
         ReceiveIPX := Status;
         Exit;
       end;
       {Ожидание прибытия сообщения}
       while not IPXEventComplete(IEvent, Status) do
         if KeyPressed then begin
           {Пользователю надоело ждать}
           ReceiveIPX := 2;
           Exit;
         end;
       {При успешном завершении Status будет равен нулю}
       ReceiveIPX := Status;
     end;
              
     
     Отметим, что  ReceiveIPX  не  возвращает  фактическую  длину
сообщения. Вместо  нее  пользователь  должен  задать максимальную
длину, которую может иметь переменная  Msg.  IPX  возвращает  код
ошибки, если   фактическая   длина  сообщения  превышает  MaxLen.
Вызывающая программа может затем вызвать ReceiveIPX снова,  чтобы
принять остальную   часть   сообщения.   При  изменяющейся  длине
сообщения прикладая  программа  сама  должна  закодировать  длину
сообщения в составе самого сообщения.
     
     Для ReceiveIPX   важно  иметь  некоторый  механизм  выдержки
времени ожидания  на  тот  случай,  если  сообщение   вообще   не
поступит. Здесь   цикл  ожидания  приема  прервется  при  нажатии
пользователем любой клавиши; альтернативный способ состоит в том,
чтобы выждать  некоторый  определенный  период  времени,  а затем
выйти из цикла с соответствующим кодом ошибки.
     
     Перед завершением  прикладной  программы  и  передатчик,   и
приемник должны закрыть гнездо посредством следующего вызова:
     
     IPXCloseSocket(IPXSocket);
     
     Сообщения SPX   более   надежны,   но  и  более  сложны  для
использования. Как и в случае канальных сообщений,  передатчик  и
приемник до  обмена  сообщениями  должны  установить  между собой
соединение. Передающая  программа  устанавливает   свою   сторону
соединения следующим образом:
     
     const
       SPXSocket : Word = $7000;
     
     var
       SEvent : SPXRec;
     
     function SPXSendConn(Receiver : IPXAddress) : Byte;
     var
       Status : Byte;
     begin
       Status := SPXEstablishConn(SEvent,Receiver,SPXSocket,FALSE,0,2,nil);
       if Status <> 0 then bgin
         {Таблица соединений или гнезд заполнена}
         SPXSendConn := Status;
         Exit;
       end;
       {Ожидание подтверждение соединения}
       while not SPXEventComplete(SEvent, Status) do
         if KeyPressed then begin
           {Пользователю надоело ждать}
           SPXSendConn := 2;
           Exit;
         end;
       {При успешном завершении Status будет равен нулю}
       SPXSendConn := Status;
     end;
                  
     
     Отметим, что переменная SEvent хранится вне SPXSendConn. Это
существенно, поскольку подпрограмма, посылающая сообщения, должна
обращаться к этой же самой переменной.  Как и в  других  пимерах,
SPXSendConn использует   простой  способ  определения  того,  что
соединение установить не удалось:  попытки  продолжаются  до  тех
пор, пока   либо  соединение  не  установится,  либо  не  истечет
выдержка времени, либо пока пользователь не нажмет любую клавишу.
В конце  концов  SPX  по  истечении  выдержки  времени  возвратит
соответственный код ошибки,  но на это может уйти больше времени,
чем согласен   ждать   пользователь.   SPXSendConn  устанавливает
соединение SPX,  при котором передатчик  может  посылать,  но  не
может принимать сообщения.
     
     Приемник устанавливает   на  своей  стороне  соединение  при
помощи следующей подпрограммы:
     
     const
       SPXSocket : Word = $7000;
     
     var
       SEvent : SPXRec;
     
     function SPXReceiveConn(MaxLen : Word) : Byte;
     var
       Status : Byte;
     begin
       Status := SPXListenForConn(SEvent,SPXSocket,false,MaxLen,2,nil);
       if Status <> 0 then bgin
         {Таблица соединений или гнезд заполнена}
         SPXReceiveConn := Status;
         Exit;
       end;
       {Ожидание подтверждение соединения}
       while not SPXEventComplete(SEvent, Status) do
         if KeyPressed then begin
           {Пользователю надоело ждать}
           SPXReceiveConn := 2;
           Exit;
         end;
       {При успешном завершении Status будет равен нулю}
       SPXReceiveConn := Status;
     end;
                  
                 
     Вызов   выделяет  в  "куче"   два   буфера
размера MaxLen,  а также блоки управления событиями,  необходимые
для ожидания приема поступающих  сообщений.  Максимальный  размер
сообщения SPX составляет 534 байтов. В остальном эта подпрограмма
работает во многом аналогично SPXSendConn.
     
     Чтобы позволить неполную синхронизацию между передатчиком  и
приемником, может  оказаться  необходимым  вызывать SPXSendConn и
SPXListenConn из  циклов.  После  того,   как   соединение   было
установлено, передатчик посылает сообщение типа:
     
     
     function SendSPX(DataType : Byte;
                      MsgLen : Word;
                      var Msg) : Byte;
     var
       Status : Byte;
     begin
       SPXSend(SEvent, False, DataType, MsgLen, Msg);
       {Ожидание подтверждение приема сообщения}
       while not SPXEventComplete(SEvent, Status) do
         if KeyPressed then begin
           {Пользователю надоело ждать}
           SendSPX := 2;
           Exit;
         end;
       {При успешном завершении Status будет равен нулю}
       SendSPX := Status;
     end;
         
     Хотя эта подпрограмма во многом  напоминает  соответствующую
подпрограмму IPX,  существует важное различие. Когда подпрограмма
IPX возвращает нулевой результат,  это  означает,  что  сообщение
было послано   успешно.   Нулевой   результат   подпрограммы  SPX
означает, что сообщение было  успешно  принято.  Это  связано  со
свойствами гарантированной доставки, которыми обладает SPX.
     
     Также отметим,  что  вызывающая  программа  может задать для
сообщения тип данных (DataType).  Этот байт  позволяет  приемнику
уверенно классифицировать поступающие сообщения разных типов,  не
обращаясь для этого к содержимому самих сообщений.
     
     Подпрограмма для  приемника  несколько  отличается  от   тех
подпрограмм, что были рассмотрены выше.
     
     function ReceiveSPX(var DataType : Byte;
                         MaxLen : Word;
                         var Msg) : Byte;
     var
       Status : Byte;
       PoolIndex : Byte;
       P : Pointer;
     begin
       {Ожидание приема сообщения}
       while not SPXListenPooled(SEvent,Status,PoolIndex,DataType,P) do
         if KeyPressed then begin
           {Пользователю надоело ждать}
           ReceiveSPX := 2;
           Exit;
         end;
       if Status = 0 then
         {Сообщение принято и возвращается в вызывающую программу}
         Move(P^, Msg, MaxLen);
         {Перезапуск блока управления событием на ожидание приема}
         SPXReplenishPool(SEvent, PoolIndex);
         {При успешном завершении Status будет равен нулю}
         ReceiveSPX := Status;
     end;
     
                
     ReceiveSPX ждет,  пока не поступит сообщение  или  не  будет
нажата клавиша.   Если   принято   сообщение,  SPX  автоматически
подтверждает его  прием.  Модуль  NetWare   временно   буферизует
сообщение в  "куче",  а  ReceiveSPX  копирует  его  в  переменную
программы. Затем  она   добавляет   блок   управления   событием,
использованный для приема сообщения,  в пул блоков, доступных для
ожидания приема.
     
     Прежде чем прикладная программа завершится,  для передатчика
и приемника  важно разорвать соединение.  Каждый их них может для
этого выполнить следующий вызов:
     
     SPXTerminateConn(SEvent);
     
     При программировании с использованием SPX программисту также
доступны опции,  такие  как  передача  сообщений по прерываниям и
двунаправленные соединения.  Более  подробно   они   показаны   в
демонстрационных программах и в оставшейся части данного раздела.
     
Константы
---------
     
     AllNodes : PhysicalNodeAddress = ($FF, $FF, $FF, $FF, $FF, $FF);
                                                                    
     Будучи переданным в подпрограмму  передачи  SPX  в  качестве
адреса узла,  это значение указывает на то,  что сообщение должно
быть послано  всем  узлам.  Novell  предупреждает,  что  не   все
конфигурации аппаратного     обеспечения     поддерживают    этот
специальный адрес. Даже если он поддерживается, фактическ получат
сообщение только те узлы,  которые ожидают приема сообщения через
заданное гнездо. Адрес назначения  для сообщений SPX не
разрешен.
     
     MaxECBPool = 32;
     
     Максимальное число  блоков  управления  событием для данного
соединения SPX.
     
     PoolSocketLongevity : Boolean = False;
     
     Управляет продолжительностью,  в  течение  которой   гнезда,
используемые подпрограммами   SPX   верхнего   уровня,   остаются
открытыми. В случае значения True гнезда  остаются  открытыми  до
тех пор,  пока  не  будет  выполнено их явное закрытие;  в случае
значения False они будут  автоматически  закрыты  при  завершении
программы. Значение   True   должно  устанавливаться  только  для
резидентных программ,  обрабатывающих сообщения после  того,  как
они сделаны резидентными.
     
     SPXRetryCount : Byte = 0;
     
     Задает число  повторных  попыток  для операций SPX.  Нулевое
значение означает,  что SPX будет использовать свой  собственный,
предопределенный счетчик попыток;  любые другие значения задаются
явно.
     
     
Типы
----
     
     Многие типы,  описанные в данном  разделе,  не  используются
непосредственно прикладной программой. Описания их включены здесь
для того,  чтобы   проиллюстрировать   информационную   иерархию,
ведущую к  типам  верхнего  уровня,  передаваемым  в подпрограммы
NETWARE в качестве параметров.
     
     Хотя типы   данных   содержат    ссылки    на    стандартные
идентификаторы Паскаля,  вы должны знать, что NetWare реверсирует
последовательность байтов почти всех полей  Word  и  LongInt.  То
есть, наиболее  значащий байт хранится первым вместо того,  чтобы
храниться последним.  Подпрограммы верхнего уровня модуля NETWARE
реверсируют последовательность   байтов,  когда  это  необходимо,
например, при хранении номера гнезда,  который вы  передаете  как
параметр.
     
     FragmentDescriptor =
       record
         Address : Pointer;
         Size : Word;
       end;
     
     Содержит адрес  и  размер  "фрагмента".  Пакет  представляет
собой набор фрагментов,  которые часто исползуются для  упрощения
работы приемника по разделению компонентов пакета.
     
     IPXAddress =
       record
         NetWork : LongInt;
         Node : PhysicaNodeAddress;
         Socket : Word;
       end;
     
     Представляет три компонента адреса  IPX  в  составной  сети:
номер сети, физический адрес узла и номер гнезда.
     
     IPXECB =
       record
         Link : Pointer;
         ESRAddress : Pointer;
         InUse : Byte;
         CompletionCode : Byte;
         SocketNumber : Word;
         IPXWorkSpace : LongInt;
         DriverWorkSpace : Array[1..12] of Byte;
         ImmediateAddress : PhysicalNodeAddress;
         FragmentCount : Word;
         FD1 : FragmentDescriptor;
         FD2 : FragmentDescriptor;
         FD3 : FragmentDescriptor;
         FD4 : FragmentDescriptor;
       end;
     
     Управляющий блок для события IPX;  событием является процесс
посылки или  ожидания  приема сообщения.  Хотя модуль NETWARE сам
организует содержимое этой записи, небольшое описание поможет вам
лучше понять, как это все работает.
     
      может     содержать     адрес     "подпрограммы
обслуживания события".  Если этот указатель не пустой  (не  равен
nil), NetWare  по  завершении  события  вызовет подпрограмму,  на
которую установлен данный указатель.  Это свойство лежит в основе
мощных протоколов передачи сообщений, управляемых по прерываниям.
Более подробная информация относительно подпрограмм  обслуживания
событий дается в описании подпрограммы . Обычно
это поле записи инициализируется значением nil.
     
     Поле  перед подчинением IPX блока управления событием
инициализируется нулем.   IPX   устанавливает  поле  в  ненулевое
значение для того,  чтобы задать статус события. Когда поле снова
становится равным нулю, это означает завершение события.
     
     После того,  как  событие завершено,   будет
задавать его результат.  Список возможных значений этого поля см.
в описании функции .
     
      это гнездо, используемое для связи.
     
      содержит адрес узла в текущей сети.  Если
сообщение пришло  или  предназначено  для   узла   другой   сети,
 содержит адрес узла межсетевого моста.
     
     Пакет данных  может быть составлен из нескольких фрагментов.
Первый фрагмент всегда должен начинаться с . Остальные
фрагменты могут   содержать  фактические  данные  пакета.  Модуль
NETWARE всегда использует два фрагмента,  один  для  заголовка  и
один для данных. Сумма полей  (размер) отдельных фрагментов
не должна превышать 576 байтов.
     
     IPXHeader =
       record
         CheckSum : Word;
         Len : Word;
         TransportControl : Byte;
         PacketType : Byte;
         Destination : IPXAddress;
         Source : IPXAddress;
       end;
     
     Используется IPX  для  организации   сообщения.   
предназначена для  внутреннего использования для контроля ошибок.
 это длина переданного пакета,  включая заголовок и  данные.
Диапазон допустимых    значений    длины    от    30    до   576.
 предназначено для  внутреннего  использования.
 должно иметь значения либо 0 (тип неизвестен),  либо
4 (пакет  для  обмена  пакетами)   при   использовании   с   IPX.
 и    задают  межсетевой  адрес  приемника и
передатчика, соответственно.  Переменные  организуются
модулем NETWARE   внутренним  образом,  так  что  вам  они  могут
понадобиться только  для  информации,   если   вообще   они   вам
понадобятся.
     
     IPXRec =
       record
         IPXHead : IPXHeader;
         ECB : IPXECB;
       end;
     
     Тип верхнего  уровня,  используемый  NETWARE для организации
сообщений IPX.  Переменная  этого  типа  должна  быть   объявлена
вызывающей программой   и   передана   различным   подпрограммам,
работающим с сообщениями IPX. Поле  описывает источник и
адресат сообщения.    Поле      писывает   само   соообщение
с указателями на его содержимое и информацией о  маршрутизации  и
статусе сообщения. Подпрограммы NETWARE инициализируют эту запись
и возвращают информацию из ее внутренних полей.
     
     PhysicalNodeAddress = array[1..6] of Byte;
     
     Представляет физический  адрес  узла,  являющийся  одной  из
частей полного  адреса  узла  в составной сети.  Физический адрес
узла устанавливается физическими переключателями,  имеющимися  на
большинстве карт Ethernet.
     
     SPXHeader =
       record
         IPXPacket : IPXHeader;
         ConnectControl : Byte;
         DataStreamType : Byte;
         SourceConnID : Word;
         DestConnID : Word;
         Sequence : Word;
         Acknowledge : Word;
         Allocation : Word;
       end;
     
     Используется SPX   для  организации  сообщений.  
содержит информацию, передаваемую сервисным средствам IPX нижнего
уровня. За  одним  исключением,  остальные поля предназначены для
внутреннего использования  SPX.  Поле    содержит
определяемое пользователем    начение,    задающее   тип   пакета
(возможно, для    упрощения    классификации    данного    пакета
приемником). Допустимыми  являются  любые  значения,  кроме $FE и
$FF. Модуль NETWARE скрывает от вас детали  относительно  данного
типа, но   позволяет  задавать    в  подпрограмме
.
     
     SPXRec =
       record
         ConnID : Word;
         SPXHead : SPXHeader;
         ECB : IPXECB;
         PoolRec : SPXPoolRec;
       end;
     
     Тип верхнего уровня,  используемый NETWARE  для  организации
сообщений SPX.  Переменная  этого  типа  должна  быть объявлена в
вызывающей программе   и   передана   различным    подпрограммам,
работающим с  сообщениями  SPX.  Поле    содержит  "номер
соединения", которое представляет  собой  форму  верхнего  уровня
SPX, аналогичную гнезду IPX.  Поле  описывает источник и
адресат сообщения.  Поле    это  главный   блок   управления
событием, используемый    при   установлении   соединения.   Поле
 скрывает  сложную  структуру  данных;   эта   структура
организует переменное    число    блоков    управления   событием
(выделяемых в  "куче"),   которые   используются   при   ожидании
сообщения. Подробное  описание  типа  см.  в исходном
коде NETWARE.  Одна важная деталь здесь состоит в том, что ссылка
на каждый  из блоков управления событием выполняется с индексом в
диапазоне от 1 до  (параметр,  задаваемый  при
запросе соединения). Этот "номер индекса в пуле" возвращается при
приеме сообщения    и    должен    передаваться    в    процедуру
 для  того,  чтобы  разрешить  соответствующему
управляющему блоку снова начать ожидание приема сообщения.
     
     В целом,  вам не  требуется  самому  работать  с  содержимым
. Подпрограммы NETWARE инициализируют эту запись сами,  и
возвращают информацию из нее по  мере  необходимости.  Вы  можете
считать ее "файловой переменной" SPX.
                                     

IPXAssignUniqueSocket
-----------------------------------------------------------------
Объявление
----------

     function IPXAssignUniqueSocket(var SocketNum : Word;
                                    Forever : Boolean) : Byte;
                                                              
     
Параметры
---------
     
     SocketNum   Возвращаемое уникальное открытое гнездо.
     
     Forever     True, если по завершении программы гнездо должно
                 остаться откытым, и False, если NetWare будет
                 закрывать его автоматически.
     
     Результат   0 при успешном завершени, или код ошибки NetWare
                 в противном случае.

Описание
--------
                                    
     Возвращает допустимое открытое гнездо, не используемое любой
другой станцией   в   сети.   Данное   гнездо  может  быть  затем
использовано для  передачи  сообщений  IPX  или  SPX.  Прикладная
программа сама  должна связать номер гнезда со взаимодействующими
рабрчими станциями.
     
      не требует  инициализации  при  входе  в  данную
подпрограмму. Описание   параметра   Forever>   см.   в  описании
подпрограммы .

Ошибки  (возвращается в качестве результата функции)
------
                             
     $FE    Таблица гнезд заполнена.
            (станция уже имеет 50 открытых гнезд).
                                                  
IPXCncelEvent
-----------------------------------------------------------------
Объявление
----------

     function IPXCancelEvent(var IPXEvent : IPXRec) : Byte;

Параметры
---------
 
     IPXEvent    Канцелируемое событие IPX
                   
     Результат   0 при успешном завершени, или код ошибки NetWare
                 в противном случае.
             
Описание
--------
             
     Канцелирует любое подвешенное событие IPX,  включая  события
посылки и  ожидания  приема  сообщения.  После того,  как событие
успешно канцелировано,      вернет    True    и
 со  значением  $FC.  Затем  прикладная программа
может повторно использовать переменную события .
                                                          
Ошибки
------
                                                          
     $FF   Событие не было активным.
     
     $F9   Событие было активным, но канцелтровать его не удалось.

Примечания
----------
           
     Существует возможность того,  что данное  событие  не  может
быть кнцелировано.  Это случается,  когда драйвер IPX находится в
процессе пересылки данных в буферы фрагментов пакета или  оттуда,
и в это время пришел запрос на канцелирование.
     
     При канцелировании  события передачи сообщения нет гарантии,
что назначенный приемник все же не получит пакет.
                                                 
     
IPXCloseSocket
-----------------------------------------------------------------
Объявление
----------

     procedure IPXCloseSocket(SocketNum : Word);

Параметры
---------
                                                
     SocketNum    Закрываемое гнездо.

Описание
--------
                                     
     Закрывает заданное   гнездо.    При    этом    автоматически
канцелируются любые  подвешенные  сообщения,  связанные  с данным
гнездом. Любые далее  поступающие  пакеты  игнорируются.  Попытка
закрыть гнездо,  которое  ранее  не  было  открыто,  не оказывает
никакого действия.
     
     Каждя рабочая станция может иметь не бошлее 50  одновременно
открытых гнезд.  Для  некоторых  прикладных  программ  это  может
означать, что  при  завершении  связанного  с   гнездом   события
желательно закрыть это гнездо.
     
     Нерезидентные прикладные  программы должны перед возвратом в
DOS закрывать все свои гнезда.  Даже если гнезда были  открыты  с
флагом ,  установленным  в  значение  FAlse,  существует
небольшое временное окно после завершения прикладной программы  и
до того  момента,  как  менеджер  IPX  сможет  закрыть гнездо,  в
течение которого поступление пакета может привести  к  сбою  всей
системы. В   программе  на  Turbo  Pascal  желательно  определить
процедуру выхода, которая бы закрывала все открытые в ней гнезда,
независимо от того, каким образом завершилась программа.

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

     function IPXEventComplete(var IPXEvent : IPXRec;
                               var CompletionCode : Byte) : Bolean;

Параметры
---------
                                                                  
     IPXEvent       Структура данных для организации сообщения IPX.
     
     CompletionCode Конечный статус события.

     Результат      True при завершении события, иначе False.
     

Описание
--------

     Возвращает статус  подвешенного события посылки или ожидания
приема сообщения IPX. Если  возвращает True, то
событие было завершено. В этом случае  возвращает
статус события.
     
      может возвращать следующие значения:
     
     0     Пакет был послан или принят успешно.
     
     $FC   Запрос посылки или ожидания приема был канцелирован.
     
     $FD   Неправильно сформированный пакет
           (слишком мал, слишком велик, неверный размер или число
           фрагментов).
     
     $FE   Пакет не может быть доставлен (не обнаружен адресат,
           недоступен межсетевой мост или произошел аппаратный
           сбой).
     
     $FF   Пакет не может быть послан (сбой аппаратного обеспечения
           или сбой в сети).

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

     procedure IPXInternetAddress(var Address : IPXAddress);

Параметры
---------

     Address    Возвращаемые адреса сети и физического узла
                вызывающей станции.

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

                 
IPXListen
-----------------------------------------------------------------
Объявление
----------

     function IPXListen(var IPXEvent : IPXRec;
                        Socket : Word;
                        WaitForCompletion : Boolean;
                        MaxPacketSize : Word;
                        var DataPacket) : Byte;
Параметры
---------
                                               
     IPXEvent             Структура данных для организации сообщений IPX.
       
     Socket               Номер гнезда для связи.
     
     WaitForCompletion    True, если  не должна выполнить
                          возврат до завершения события.
     
     MaxPacketSize        Максимальное число байтов, принимаемых
                          в DataPacket (0..546).
     
     DataPacket           Нетипированная переменная для хранения
                          принятых данных.
     
     Результат            0 в случае успешного завершения;
                          иначе код ошибки NetWare.

Описание
--------
                                                   
     Инициализирует структуры данных  IPX  для  приема  пакета  и
запускает событие  IPX.  Вызывающая программа должна задать номер
гнезда   для  связи.   Передатчик   и   приемник   должны
согласовать между собой номер гнезда.  Подробности см. в описании
.  откроет гнездо,  если  оно  к  этому
моменту еще не открыто.
     
     Когда  имеет значение False,  
выполнит возврат немедленно после  запуска  запроса  на  ожидание
приема. В  этом  случае  вызывающая  прикладная  программа  может
продолжить работу с другими  задачами,  но  она  должна  опросить
функцию ,   чтобы   определить,   завершено  ли
событие. Если       имеет    значение    True,
 сама  опрашивает  завершение  событие,  пока  оно  не
произойдет.
     
      задает   максимальное   число    принимаемых
байтов, не  включая сюда информацию заголовка пакета,  внутренним
образом обрабатываемую . Максимально допустимый размер
пакета равен  546 байтам.   может являться переменной
любого типа,  лишь бы она имела  достаточный  размер  для  любого
числа байтов, заданного в .
     
      инициализируется  в    и  содержит всю
информацию, требуемую для организации сообщения.
     
     И ,  и  должны  являться  переменными,
статическими в  течение  длительности события.  Если они являются
глобальными переменными  (либо  если     имеет
значение True),  это  требование  удовлетворяется  автоматически.
Если они выделены в "куче",  то это выделение должно  сохраняться
до тех  пор,  пока  не  завершится  событие.  Если  они  являются
локальными переменными, то подпрограмма, в которой они объявлены,
не должна выполнять возврат до завершения события.  (Однако, сама
она может вызывать другие подпрограммы).  Если эти требования  не
выполняются, драйвер  IPX  испортит память,  что может привести к
сбою программы.
     
               
Ошибки
------

     $01    Значение MaxPacketSize слишком велико.
     
     $FE    Таблица гнезд заполнена.

Примечания
----------
                                    
     Гнездо не  закрывается  автоматически  до завершения события
ожидания приема. См. .
     
     Код завершения,  возвращаемый , сообщает о
том, произошел ли фактический прием сообщения.
     
     
     

     
IPXOpenSocket
-----------------------------------------------------------------
Объявление
----------

     function IPXOpenSocket(SocketNum : Word; Forever : Boolean) : Byte;
     
Параметры
---------
     
     SocketNum   Открываемое гнездо.
     
     Forever     True, если гнездо должно остаться открытым после
                 завершения программы, и False, чтобы NetWare
                 закрывала его автоматически.

     Результат   0 в случае успешного завершения;
                 иначе код ошибки NetWare.

Описание
--------
                                          
     Открывает гнездо для использования IPX или SPX. Передатчик и
приемник должны  для того,  чтобы связь между ними была возможна,
согласовать между собой номер гнезда.  Гнезда с номерами от $4000
до $7FFF доступны для использования в любой прикладной программе.
Любая рабочая станция может иметь  одновременно  до  50  открытых
гнезд.
     
     Когда    имеет   значение   True,  гнездо  остается
открытым до тех пор,  пока не будет выполнено его явное закрытие,
даже после  завершения  текущей  программы.  В  противном  случае
NetWare закроет гнездо автоматически,  при завершении  программы.
Установка  в значение True будет полезна для резидентных
программ, которым требуются сервисные средства IPX.

Ошибки
------
                                                   
     $FE   Таблица гнезд заполнена (станция уже имеет 50 открытых
           гнезд).
     
     $FF   Гнездо уже было открыто.

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

     procedure IPXRelinquish;


Описание
--------
                            
     Временно передает  управление NetWare.  Эта процедура служит
для одной или двух целей,  в зависимости от  того,  была  ли  она
запущена файл-сервером,  или же рабочей станцией.  На сервере эта
функция временно  приостанавливает  процесс   вызова,   так   что
программа сервера   немедленно   получает   доступ   к   ресурсам
центрального процессора.  Аналогично, на рабочей станции оболочка
NetWare временно получает управление,  и может проверять входящие
и выходящие сообщения.
     
     Данная процедура должна часто вызываться во  время  ожидания
прикладной программой  завершения  события  IPX  или SPX.  Обычно
вызов имеет следующую форму:
     
     repeat
       {прикладная программа выполняет некоторую работу}
       ...
       IPXRelinquish;
       {прикладная программа выполняет последующую работу}
       ...
     until IPXEventComplete(IPXEvent, CompletionCode);
     
      сама      вызывает       .
Следовательно, вызов      необходим   только  если
прикладная программа  выполняет  между  вызовами  большое   число
задач.
     
     
IPXSend
-----------------------------------------------------------------
Объявление
----------

     function IPXSend(var IPXEvent : IPXRec;
                      Receiver : IPXAddress;
                      Socket : Word;
                      WaitForCompletion : Boolean;
                      DataPacketSize : Word;
                      var DataPacket) : Byte;
Параметры
---------

     IPXEvent             Структура данных для организации сообщений IPX.
     
     Receiver             Межсетевой адрес приемника, не включающий
                          в себя Socket.

     Socket               Номер гнезда для связи.

     WaitForCompletion    True, если  не должна выполнить
                          возврат до завершения события.

     DataPacketSize       Число байтов в DataPacket (0..546).

     DataPacket           Нетипированная переменная с
                          передаваемыми данными.

     Результат            0 в случае успешного завершения;
                          иначе код ошибки NetWare.

Описание
--------

     Инициализирует структуры  данных  IPX  для  посылки пакета и
запускает    событие    IPX.    Вызывающая    программа    должна
инициализировать    для  задания  адресата пакета.  См.
описание подпрограммы ,  где  рассматривается
один  из методов определения адреса .  Она также должна
задавать номер гнезда  для пересылки пакета. Передатчик и
приемник должны согласовать между собой номер гнезда. Подробности
см.  в описании .   откроет гнездо,  если
оно к этому моменту еще не открыто.

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

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

      инициализируется  в    и  содержит   всю
информацию, требуемую для организации сообщения.

     И ,  и  должны  являться  переменными,
статическими в  течение  длительности события.  Если они являются
глобальными переменными  (либо  если     имеет
значение True),  это  требование  удовлетворяется  автоматически.
Если они выделены в "куче",  то это выделение должно  сохраняться
до тех  пор,  пока  не  завершится  событие.  Если  они  являются
локальными переменными, то подпрограмма, в которой они объявлены,
не должна выполнять возврат до завершения события.  (Однако, сама
она может вызывать другие подпрограммы).  Если эти требования  не
выполняются, драйвер  IPX  испортит память,  что может привести к
сбою программы.

     
IPXServicesAvail
-----------------------------------------------------------------
Объявление
----------

     function IPXServicesAvail : Boolean;

Параметры
---------
                                        
     Результат    True, если сервисные средства IPX доступны;
                  иначе False.

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

     
SPXAbortConn
-----------------------------------------------------------------
Объявление
----------

     procedure SPXAbortConn(var SPXEvent : SPXRec);

Параметры
---------

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


                                         
SPXEstablishConn
-----------------------------------------------------------------
Объявление
----------

     function SPXEstablishConn(var SPXEvent : SPXRec;
                               Receiver : IPXAddress;
                               Socket : Word;
                               WaitForCompletion : Boolean;
                               MaxListenDataSize : Word;
                               NumListenPoolECBs : Byte;
                               PoolESR : Pointer) : Byte;
Параметры
---------

     SPXEvent             Структура данных для организации сообщений SPX.
     
     Receiver             Межсетевой адрес приемника, не включающий
                          в себя Socket.

     Socket               Номер гнезда для связи.

     WaitForCompletion    True, если  не должна выполнить
                          возврат до завершения события.

     MaxListenDataSize    Наибольший размер принимаемого
                          пакета данных (0..534).

     MaxListenPoolECBs    Число блоков управления событием для
                          ожидания приема (2..32).
     
     PoolESR              Указатель опциональной подпрограммы
                          обслуживания события.

     Результат            0 в случае успешного завершения;
                          иначе код ошибки NetWare.

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

     Когда       имеет     значение     False,
  выполнит  возврат  немедленно  после  запуска
запроса   на  установку  соединения.  В  этом  случае  вызывающая
прикладная программа может продолжить работу с другими  задачами,
но   она   должна   опросить  функцию  ,  чтобы
определить,  завершено ли событие. Если  имеет
значение  True,    сама  опрашивает  завершение
события, пока оно не произойдет.
                                                                  
      задает размер наибольшего пакета данных,
принимаемого по  двунаправленному  соединению  SPX.  По умолчанию
станция, вызывающая ,  может только  передавать
сообщения. В этом случае правильным значением 
будет ноль,  поскольку  единственными  принисмаемыми  сообщениями
будут являться  пакеты - квитанции приема нулевого размера.  Если
для установления  двустороннего  соединения  использован   метод,
продемонстрированный в    программах   NSEND   и   NRECEIVE,   то
 должен содержать размер наибольшего пакета  с
данными прикладной программы.
     
      всегда  должен  иметь  значение не менее
двух. Это позволяет  блоку  управления  событием  ожидать  приема
квитанции подтверждения соединения,  плюс еще один запасной блок,
рекомендуемый Novell.  Если  передатчик  не  является   также   и
приемником,   не требуется делать равным более
двух.
     
      это  указатель   на   опциональную,   поставляемую
пользователем подпрограмму    обслуживания    события.   Передача
значения nil  деактивирует  данное  средство.  Задание  
желательно только   тогда,   когда   требуется   быстродействущее
двустороннее соединение   SPX.   Подробности   см.   в   описании
.
     
     "Идентификатор соединения SPX", установленный в итоге данной
функцией, записывается в переменную .
     

Ошибки
------
     
     $EF   Локальная таблица соединений заполнена.
     
     $FD   Неправильно сформированный пакет
           (внутренняя ошибка NETWARE).
     
     $FE   Таблица гнезд заполнена.


Примечания
----------
     
     Поскольку SPX   неявно  обрабатывает  выдержки  времени,  не
вызывайте  для  того,  чтобы  абортировать  вызов
, находящийся  в  процессе  выполнения.  Вместо
этого следует вызвать .
     
                                     
SPXEventComplete
-----------------------------------------------------------------
Объявление
----------

     function SPXEventComplete(var SPXEvent : SPXRec;
                               var CompletionCode : Byte) : Boolean;

Параметры
---------
                               
     SPXEvent        Структура данных для организации сообщения SPX.
     
     CompletionCode  Статус последнего события после его завершения.
     
     Результат       True, когда событие завершилось; иначе False.

Описание
--------
                                                                  
     Опрашивает статус  события  SPX,  что  позволяет  прикладной
программе определить момент завершения события.  Это  необходимо,
поскольку сервисные  средства  передачи  сообщений  SPX  являются
асинхронными. Когда  прикладная  программа  вызывает   любую   из
следующих подпрограмм   (а   параметр    имеет
значение False),  SPX ставит  заголовок  сообщения  в  очередь  и
немедленно возвращается:
     
     SPXEstablishConn
     SPXListenForConn
     SPXSend
     
     Только позднее, когда сообщение проделало свой путь по сети,
событие считается завершенным.  В это время вызывающая  программа
может проверить   результат,  например,  произошла  ли  установка
соединения или успешная посылка сообщения.
     
     Всегда небезопасно  начинать   следующее   событие   SPX   с
использованием той   же  самой  переменной  ,  пока  не
завершится предыдущее  событие.  Для   того,   чтобы   стартовать
перекрывающиеся вызовы  SPX,  может  быть  использована отдельная
переменная .
     
      всегда возвращает 0,  указывая на  то,  что
событие закончилось  успешно.  В случае ошибки он возвращает одно
из следующих значений.

Ошибки
------
                      
     $EC   Соединение закрыто удаленным партнером.
     
     $ED   Адресат не отвечает.
     
     $EE   Неверный идентификатор соединения в переменной .
     
     $EF   Локальная таблица соединений заполнена.
     
     $FC   Событие канцелировано.
     
     $FD   Неправильно сформированный пакет (слишком мал, слишком
           велик, неправильный размер или число фрагментов).
     
     $FE   Таблица гнезд заполнена.
     
     $FF   Гнездо не было открыто (внутренняя ошибка NETWARE).

Примечания
----------
                                                              
     При опросе  для определения того,  завершено ли событие SPX,
прикладная программа может выполнять другую полезную работу.  SPX
требует только, чтобы вызов  выполнялся регулярно,
так чтобы можно было  проверить  наличие  поступивших  сообщений.
Типичный цикл опроса имеет вид:
     
     ... вызов подпрограммы SPX ...
     repeat
       {прикладная программа выполняет некоторую работу}
       ...
       IPXRelinquish;
       {прикладная программа выполняет следующую работу}
       ...
     until SPXEventComplete(SPXEvent, CompletionCode);
     
      сама      вызывает       .
Следовательно, вызов      необходим   только   при
выполнении прикладной программой между  вызовами  большого  числа
задач.
      
     
SPXListenCount
-----------------------------------------------------------------
Объявление
----------

     function SPXListenCount(var SPXEvent : SPXRec) : Byte;

Параметры
---------
                                                           
     SPXEvent        Структура данных для организации сообщения SPX.
     
     Результат       Число блоков управления событием, доступных
                     для ожидания приема.

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

                                                
SPXListenForConn
-----------------------------------------------------------------
Объявление
----------
     
     function SPXListenForConn(var SPXEvent : SPXRec;
                               Socket : Word;
                               WaitForCompletion : Boolean;
                               MaxDataSize : Word;
                               NumPoolECBs : Byte;
                               PoolESR : Pointer) : Byte;
Параметры
---------

     SPXEvent             Структура данных для организации сообщений SPX.

     Socket               Номер гнезда для связи.

     WaitForCompletion    True, если  не должна выполнить
                          возврат до завершения события.

     MaxDataSize          Наибольший размер принимаемого
                          пакета данных (0..534).

     MaxPoolECBs          Число блоков управления событием для
                          ожидания приема (2..32).
     
     PoolESR              Указатель опциональной подпрограммы
                          обслуживания события.

     Результат            0 в случае успешного завершения;
                          иначе код ошибки NetWare.

Описание
--------
                                               
     Данная функция     работает     совместно     с     функцией
. Для установки соединения одна сторона  должна
ожидать приема  при  помощи ,  а вторая сторона
должна выполнить вызов посредством .
             
      использует  в  качестве  рабочей  области
параметр  ,  аналогично  тому,  как  файловые  операции
используют  файловую  переменную.  Вы не обязаны инициализировать
этот  параметр.  Однако,  помните,  что    должен  быть
непрерывно  доступен  все  время,  пока активно данное соединение
SPX.  Безопаснее  всего  сделать   переменную,   передаваемую   в
параметре , глобальной.
     
     Вызывающая программа должна задавать номер  гнезда  
для  пересылки  пакета.  Передатчик и приемник должны согласовать
между  собой  номер  гнезда  (тем  самым  SPX  имеет  возможность
различать   множество   приходящих   запросов   на   соединение).
Информацию  о  номерах  гнезд  см.  в  описании  .
  откроет гнездо,  если оно к этому моменту еще
не открыто.
     
     Когда       имеет     значение     False,
  выполнит  возврат  немедленно  после  запуска
запроса   на  установку  соединения.  В  этом  случае  вызывающая
прикладная программа может продолжить работу с другими  задачами,
но   она   должна   опросить  функцию  ,  чтобы
определить,  завершено ли событие. Если  имеет
значение  True,    сама  опрашивает  завершение
события, пока  оно  не  произойдет.  Затем  прикладная  программа
должна вызвать  ,  чтобы  определить  результат
события.
     
      задает размер наибольшего пакета данных,
принимаемого по  двунаправленному  соединению   SPX.   Если   это
значение слишком  мало,  то  приходящие  сообщения могут затереть
память, что   даст   непредсказуемые   последствия.    Наибольший
возможный размер пакета равен 534 байта.
     
      всегда  должен  иметь  значение не менее двух.
Один из блоков  управления  событием  временно  используется  для
приема квитанции  подтверждения  соединения  NetWare.  Этот  блок
затем становится доступным для организации  сообщений  прикладной
программы. Второй  блок  нужен  для надежной обработки приходящих
сообщений: если  первый   блок   связан   обработкой   прикладной
программой одного  сообщения,  второй блок является доступным для
приема другого сообщения.  Обычно двух блоков  обработки  события
бывает достаточно.  Более  подробное  рассмотрение  этого вопроса
находится во введении к данному разделу.
                                        
      выделяет для хранения  блоков  управления
событием и  пакетов  данных  область "кучи".  Для этого требуется
память размером
     
     *<106+).
     
     Число 106   это   SizeOf(PoolECB),   тип   нижнего   уровня,
определенный в модуле NETWARE.
     
      это  указатель   на   опциональную,   поставляемую
пользователем подпрограмму    обслуживания    события.   Передача
значения nil  деактивирует  данное  средство.  Задание  
желательно только   тогда,   когда   требуется   быстродействущее
двустороннее соединение   SPX.   В   этом   случае   подпрограмма
обслуживания события  получает управление немедленно после приема
каждого сообщения,  избегя тем  самым  необходимости  иметь  цикл
опроса, следящий за поступающими данными.
     
     Подпрограмма обслуживания события должна  быть  объявлена  в
точности следующим образом:
     
     {$F+}
     procedure SPXESR(var SPXEvent : SPXRec;
                      CompletionCode : Byte;
                      PoolIndex : Byte;
                      DataType : Byte;
                      DataPtr : Pointer);
     begin
       ...
     end;
     {$F-}
     
     Подпрограмма должна компилироваться с моделью памяти  FAR  и
не может  быть  вложенной  в  любые другие процедуры или функции.
Прикладная программа  передает  адрес  подпрограммы  (@SPXESR)  в
параметре .  Подпрограмма получает управление фактически
при тех же условиях,  что и подпрограмма обслуживания  аппаратных
прерываний: прерывания   центрального   процессора  на  входе  ее
отменяются; не-реентерабельные функции DOS не могут быть  вызваны
безопасным образом;  время, занимаемое этой подпрограммой, должно
быть строго  ограничено;  и  область  стека  при  входе   в   эту
подпрограмму неизвестна,  но  предположительно имеетмалый размер,
возможно менее 100 байтов. Чтобы избежать проблем, контроль стека
Turbo Pascal должен быть отключен при помощи директивы {$S-}.
     
     Перед вызовом    определяемой    пользователем    ,
обработчик прерываний нижнего уровня NETWARE  сохраняет  регистры
центрального процессора  и  извлекает  важные  параметры из блока
управления событием.  Эти  параметры  передаются  в  подпрограмму
пользователя.
     
     SPXEvent        Структура данных верхнего уровня, связанная
                     с данным соединением.
     
     CompletionCode  Статус происшедшего события ожидания приема.
     
     PoolIndex       Индекс блока управления для данного события.
     
     DataType        Тип принятого пакета в случае успешного
                     события.
     
     DataPtr         Указатель пакета данных.
     
                                             
      содержит  ноль,  указывающий  на   успешный
прием пакета   данных.   Описание   других  кодов  ошибки  см.  в
.  должен использоваться как параметр
, чтобы   сделать   блок   управления  событием
доступным для  другого  сообщения.    это  определяемое
пользователем значение,  позволяющее различать тип пакета. Это то
самое значение,  которое задает передатчик при вызове  .
 это указатель на сам пакет.
     
     Наипростейший полезный  обработчик  событий должен содержать
как минимум следующее:
     
     {$F+}
     procedure SPXESR(var SPXEvent : SPXRec;
                      CompletionCode : Byte;
                      PoolIndex : Byte;
                      DataType : Byte;
                      DataPtr : Pointer);
     begin
       if CompletionCode = 0 then begin
         {Обработка данных типа DataType, находящихся в DataPtr^}
         ...
       end else
         {Установка флага ошибки}
       {Возврат блока управления событием в пул свободных блоков}
       SPXReplenishPool(SPXEvent, PoolIndex);
     end;
     {$F-}
     
     Подпрограмма обслуживания     события     может    разрешать
прерывания; ей не требуется восстанавливать их.  Она также  может
переключиться на  другой  (больший)  стек,  но  она  должна перед
выходом вернуться  к  исходному  стеку.  (Для   этого   идеальной
является подпрограмма  Turbo  Professional  -  SwapStackAndCall).
Подпрограмма обслуживания событий  может  вызывать  любую  другую
сервисную подпрограмму    IPX    или    SPX,    за    исключением
.
     
     Подпрограммы обслуживания   событий   SPX   являются   очень
продвинутым средством NetWare.  Возможно, они вам не понадобятся,
но на всякий случай мы сделали их доступными для вас.
                                                     
     "Идентификатор соединения SPX", установленный в итоге данной
функцией, записывается в переменную .
     

Ошибки
------
     
     $EF   Локальная таблица соединений заполнена.
     
     $FE   Таблица гнезд заполнена.


                                                         
SPXListenPooled
-----------------------------------------------------------------
Объявление
----------

     function SPXListenPooled(var SPXEvent : SPXRec
                              var CompletionCode : Byte;
                              var PoolIndex : Byte;
                              var DataType : Byte;
                              var DataPtr : Pointer) : Boolean;
     
Параметры
---------
     
     SPXEvent        Структура данных для организации
                     сообщения SPX.
     
     CompletionCode  Статус происшедшего события ожидания приема.
     
     PoolIndex       Индекс блока управления для данного события.
     
     DataType        Тип принятого пакета в случае успешного
                     события.
     
     DataPtr         Указатель пакета данных.
     
     Результат       True, если произошло событие ожидания приема;
                     иначе FAlse.
                                 
Описание
--------
     
     Возвращает True,  если  было  принято  сообщение SPX.  после
установки соединения станция, ожидающая сообщения SPX, циклически
вызывает  до тех пор, пока та не вернет значение
True. Затем  прикладная  программа  может  оценить   возвращенные
параметры, чтобы определить статус и содержимое сообщения.
     
      всегда  вызывает  0,  указывая  на то,  что
сообщение было принято успешно. В случае же ошибки она возвращает
код6 как показано ниже. Параметры  и  являются
достоверными только  при   нулевом   значении   .
 всегда является достоверным.
     
      возвращает тип принятого пакета данных. Это то же
самое значение,  которое  задается,  когда  передатчик   вызывает
.
     
      это   указатель   на  пакет  данных.  Подпрограммы
NETWARE не знают о содержимом пакета; следовательно, возвращаемое
значение является нетипированным указателем. Прикладная программа
должна выполнить  приведение   типа   указателю   к   конкретному
определяемому пользователем  типу.  Прикладная  программа  должна
также скопировать данные  из    в  другой  адрес,  либо
полностью завершить    обработку    этих    данных    до   вызова
 для  перезапуска  блока  управления  событием.
Область хранения пакета в  может быть затерта следующим
сообщением.
     
     Пример использования    см.  во  введении   к
данному разделу.
                
Ошибки
------
     
     $EC   Соединение закрыто удаленным партнером.
     
     $EE   Неверный идентификатор соединения в переменной .
     
     $FC   Событие канцелировано.
     
     $FD   Неправильно сформированный пакет (слишком мал, слишком
           велик, неправильный размер или число фрагментов).
     
     $FF   Гнездо не было открыто (внутренняя ошибка NETWARE).
     
    
SPXReplenishAll
-----------------------------------------------------------------
Объявление
----------

     procedure SPXReplenishAll(var SPXEvent : SPXRec);

Параметры
---------
     
     SPXEvent        Структура данных для организации
                     сообщения SPX.
     
Описание
--------
     
     Активирует все блоки управления событием на ожидание приема.
Подпрограммы NETWARE   SPX  автоматически  активируют  все  блоки
управления, когда     соединение     устанавливается     впервые;
следовательно,   требуется вызывать только после
приема одного или более пакетов.
     
     В целом,  безопаснее  вызывать  ,   нежели
. Если  сообщение  принято непосредственно перед
вызовом , то оно будет потеряно.
     
     
SPXReplenishPool
-----------------------------------------------------------------
Объявление
----------

     procedure SPXReplenishPool(var SPXEvent : SPXRec;
                                PoolIndex : Byte);

Параметры
---------
     
     SPXEvent        Структура данных для организации
                     сообщения SPX.
     
     PoolIndex       Индекс перезапускаемого
                     блока управления события.
     
     
Описание
--------
     
     Активирует заданный блок  управления  событием  на  ожидание
приема.  Подпрограммы  NETWARE  SPX  автоматически активируют все
блоки  управления,  когда  соединение  устанавливается   впервые;
следовательно,  требуется вызывать только после
приема пакета.
             
      это  значение,  возвращаемое  ,
когда сообщение было принято.
     
     Использование     показано    в   примере,
приведенном в начале данного раздела.

                                     
SPXSend
-----------------------------------------------------------------
Объявление
----------

    procedure SPXSend(var SPXEvent : SPXRec;
                      WaitForCompletion : Boolean;
                      DataType : Byte;
                      DataPacketSize : Word;
                      var DataPacket);
Параметры
---------

     SPXEvent             Структура данных для организации сообщений SPX.
     
     WaitForCompletion    True, если  не должна выполнить
                          возврат до завершения события.
                                      
     DataType             Определяемый пользователем тип данных
                          ($00..$FD).
     
     DataPacketSize       Число посылаемых байтов (0..534).

     DataPacket           Посылаемые данные.

Описание
--------

     Посылает пакет  данных,  используя  сервисные  средства SPX.
Пакет имеет  любой  определяемый  пользователем  тип  данных,  не
превышающий по   размеру   534   байта.   При  пересылке  пакетов
изменяющихся типов прикладная программа должна использовать  поле
, указывающий  приемнику тип данных.  Отметим,  что SPX
резервирует два   последних   типа   данных   для    собственного
использования.
     
     Если для  данного типа пакета длина пакета будет изменяться,
то прикладная  программа  должна  передавать  фактическую   длину
пакета в  первых  двух  байтах самого пакета,  так чтобы приемник
имел возможность определить эту длину.  Параметр 
приемнику недоступен.
     
      это  переменная,  инициализируемая  в  предыдущем
успешном вызове .
     
     Отметим, что событие  является  асинхронным  в  том
смысле, в  которым  является асинхронным установление соединения.
Следовательно, если  имеет значение False,  то
за       должны     следовать     циклические     вызовы
. Аналогичным образом,  переменная 
должна оставаться статической до завершения .
     
     Пример использования    см.  во  введении к данному
разделу.
     
        
SPXServicesAvail
-----------------------------------------------------------------
Объявление
----------

     function SPXServicesAvail(var Version : Word;
                               var MaxSPXConn : Word;
                               var AvailSPXConn : Word) : Boolean;

Параметры
---------
     
     Version      Номер версии SPX, главная часть старшего байта.
     
     MaxSPXConn   Максимально возможное число соединений SPX.
     
     AvailSPXConn Текущее доступное число соединений SPX
                                        
     Результат    True, если сервисные средства SPX доступны;
                  иначе False.

Описание
--------
                              
     Проверяет доступность  сервисных  средств  SPX  и возвращает
информацию о версии,  если средства  доступны.  Любая  прикладная
программа,  использующая  сервисные средства SPX,  должна сначала
вызвать эту функцию, чтобы убедиться в доступности SPX.
     
     Сообщения SPX   используют   ресурсы,   которые   называются
"идентификаторами соединений".  (Их  не  нужно  путать с номерами
соединений, присваиваемыми каждой рабочей станции при регистрации
ее на сервере).  Каждый идентификатор соединения SPX представляет
собой уникальный номер,  присваиваемый  коммуникационному  каналу
SPX при  его  создании.  Их  число  ограничено,  но это не должно
приводить к проблемам в случае обычных прикладных программ.
     
     
SPXTerminateConn
-----------------------------------------------------------------
Объявление
----------

     procedure SPXTerminateConn(var SPXEvent : SPXRec);

Параметры
---------
                                                      
     SPXEvent    Структура данных для организации сообщений SPX.
     

Описание
--------
                 
     Это наиболее  очевидный  способ  для  закрытия существующего
соединения.    посылает   на    другой    конец
соединения пакет,   указывающий   на  то,  что  соединение  будет
разорвано. SPX  обрабатывает   квитанцию   подтверждения   приема
сообщения приемником  и  также  завершает  процесс  разъединения.
Связанный с  данным  соединением  идентификатор  возвращается   в
свободный пул.
     
     Также закрывается  принадлежащее  данному  соединению гнездо
IPX. Освобождается  область   "кучи",   выделенная   при   помощи
 или   .   Отметим,   что   и
передатчик, и  приемник   должны   вызвать   со   своей   стороны
, чтобы  освободить области "кучи",  выделенные
для обеих станций.  Закрытие соединения дважды не  имеет  вредных
последствий (для сети).


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


B. NetBIOS
----------

     NetBIOS означает "Сетевая базовая система ввода/вывода". Она
представляет собой  интерфейс  для  прикладных  программ   (API),
поддерживающий обмен  данными  между  рабочими  станциями в сети.
NetBIOS был представлен IBM в  1984  г.  и  на  сегодняшний  день
получил широкое распространение. Он стал промышленным стандартным
протоколом и   реализован    наиболее    современными    сетевыми
операционными системами   для  микрокомпьютеров.  Таким  образом,
программа, написанная с использованием сервисных средств NetBIOS,
может выполняться без изменений во многих сетях.

     Модуль NETBIOS     реализует    сервисные    средства    для
использования в программах, написанных на Turbo Pascal 4.0 и 5.0.
Данный модуль  позволяет  программисту  отказаться  от  работы на
уровне вызова  функций  NetBIOS.  Он  предназначен  для  создания
совместимых с  NetBIOS программ на Паскале.  (Отметим,  что когда
NETBIOS написано заглавными  буквами,  то  речь  идет  о  модуле,
поставляемом в  составе  B-Tree  Filer;  смешанное же написание -
NetBIOS отновится собственно к расширению операционной системы.

     В отличие от подпрограмм  NetWare,  подпрограммы  NetBIOS  в
большой степени   независимы  от  сетевой  операционной  системы.
Другими словами,  они будут работать в  любой  сети,  реализующей
функции, совместимые   с  NetBIOS.  (Novell  поставляет  эмулятор
NetBIOS со всеми версиями NetWare.  Отметим,  однако,  что каждая
рабочая станция   должна  загружать  дополнительные  программы  -
обычно это NETBIOS.EXE и INT2F.COM,- которые активируют эмулятор).

     По контрасту  с  NetWare,  интерфейс  NetBIOS  компактен   и
сфокусирован только  на  коммуникациях между отдельными станцими.
Полный NetBIOS API определяет только 19 функций, и модуль NETBIOS
реализует и документирует почти все из них.

     Фундаментальной частью  программирования  с NetBIOS является
концепция "имени". Каждая рабочая станция может иметь до 17 имен,
каждое длиной  в 16 байтов.  Одно из этих имен представляет собой
"перманентное имя узла".  Перманентное имя узла - это собственная
уникальная сигнатура физической карты сетевого адаптера.  Это имя
запрограммировано на аппаратном уровне и не может  быть  изменено
прикладной программой.   Поскольку  это  имя  существует  всегда,
иногда бывает удобно обращаться к нему при вызовах NetBIOS.

     Карта адаптера каждой станции (или эмулятор  NetBIOS)  также
поддерживает "таблицу  локальных  имен",  которая  содержит до 16
программно выбыраемых  имен.  Каждое  их   них   может   являться
"уникальным именем",    резервируемым    станцией    для   своего
исключительного использования в  сети,  или  "групповым  именем",
которое могут  разделять  и  другие  станции.  При сравнении имен
NetBIOS важен регистр,  в котором  набрано  имя.  При  добавлении
имени в  таблицу  NetBIOS  выдает  широковещательное  сообщение о
своем намерении зарегистрировать это имя всем прочим  станциям  в
сети. Если  было запрошенно уникальное имя,  а уже другая станция
имеет то  же  имя  в  своей  локальной  таблице,  то  запрос   не
удовлетворяется. Если  имя  успешно  добавлено  в  таблицу  имен,
NetBIOS возвращает позицию таблицы, в которой оно записано. Такой
"номер имени"  используется  многими командами NetBIOS в качестве
быстрого способа сослаться на имя,  о котором известно,  что  оно
записано в таблице.

     Наиболее простой    способ    использования    NetBIOS   для
коммуникаций между станциями состоит  в  посылке  так  называемых
"датаграмм". Датаграмма это небольшой блок необработанных данных.
Максимальный размер датаграммы зависит от конкретной  реализации,
но наиболее  часто  встречающееся  ограничение  равно 512 байтам.
Сообщение с датаграммой может быть послано на уникальное имя,  на
групповое имя   или   всем   участникам  сети  (широковещательная
датаграмма). Датаграммы требуют очень небольшого  дополнительного
расхода ресурсов   и  просты  в  использовании.  Однако,  подобно
сервисным средствам   NetWare   IPX,   датаграммы   не   вызывают
автоматического подтверждения их получения NetBIOS приемника, и в
том случае,  если приемник  не  готов  к  их  получению,  то  они
теряются.

     Второй, более помехозащищенный протокол NetBIOS,  называется
"сеансом". Пакеты  сеанса  подтверждаются  при   получении,   что
обеспечивает гарантированную  доставку  данных.  Сеансы позволяют
передавать большие куски данных - до 64К,  и даже более того,  за
счет улучшенных методов.  Разумеется, такая повышенная надежность
требует больших затрат ресурсов.  Другое ограничение  сеансов  по
сравнению с датаграммами состоит в том,  что они работают лишь по
индивидуальным соединениям - широковещательные посылки этот метод
не позволяет.

     Модуль NETBIOS поддерживает как датаграммы,  так и сеансы. В
следующем списке сведены функции, реализуемые этим модулем:

     - определение того, инсталлирован ли NetBIOS;

     - сброс сетевого адаптера;

     - добавление уникального имени в таблицу локальных имен;

     - добавление группового имени в таблицу локальных имен;

     - удаление имени из таблицы локальных имен;

     - посылка датаграммы;

     - прием датаграммы;

     - установление сеанса;

     - посылка сообщения в сеансе;

     - прием сообщения в сеансе;

     - закрытие сеанса.

     Вызовы NetBIOS выполняются одним из двух способов.  В  обоих
случаях пара  регистров  ES:BX  указывает  на  инициализированную
запись, называемую  блоком  управления   NetBIOS   (NCB).   Затем
вызывается функция  $2A  по  прерываниям  int  $5C  или $21(DOS).
Модуль NetBIOS  инициализирует  NCB   и   выполняет   прерывание.
(NETBIOS использует вызов int $5C вместо int $21).

     Многие вызовы   NetBIOS   могут   работать   в  режиме  "без
ожидания". Это  означает,  что  возврат  из   вызова   происходит
немедленно после  выполнения  запроса,  не  дожидаясь  завершения
операции (аналогично работе  IPX  для  NetWare).  В  этом  случае
переменная NCB,  переданная  в  подпрограмму  NETBIOS  в качестве
аргумента, должна не подвергаться в памяти никаким изменениям  до
самого завершения  вызова.  Требуется  обратить  внимание  на то,
чтобы NCB не использовался повторно,  и если  NCB  это  локальная
переменная, то  чтобы не происходыл возврат из подпрограммы,  где
она была объявлена  до  окончания  работы  функции  NetBIOS.  При
использовании вызовов  "без  ожидания"  самая безопасная методика
состоит в том,  чтобы объявить одну NCB на каждый запрос NetBIOS,
объявить NCB   как   глобальные   переменные   и  проверять  поле
 в NCB перед ее повторным использованием.

     Модуль NETBIOS   позволяет   опциональные   операции    "без
ожидания" только  при  посылке  и  приеме  датаграмм.  Все прочие
подпрограммы не возвращаются,  пока не  будет  завершена  команда
NetBIOS.

     Следующая литература по NetBIOS может быть вам полезной:

     C Programmer's Guide to NetBIOS
       W.David Schwaderer, Howard W.Sams & Co., 1988.

     Inside NetBIOS
       J.Scott Haugdahl, Architecture Technology Corp, Minneapolis,MN.

     NetBIOS Applications Development Guide
       IBM Manual #68X2270.


Примеры
-------

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

     На стороне  передатчика  сообщение  типа  датаграммы   будет
организовано следующим образом:


     const
       SenderName : NbNameStr = 'SenderName';
       ReceiverName : NbNameStr = 'ReceiverName';

     function SendOneDatagram(MsgLen : Word;
                              var Msg) : Byte;

     var
       Status : Byte;
       NameNumber : Byte;
       N : NCB;
     begin
       {Добавить имя для последующих ссылок}
       Status := NetBiosAddName(SenderName, NameNumber);
       if Status <> 0 then begin
         {Проблема с именем передатчика}
         SendOneDatagram := Status;
         Exit;
       end;
       {Посылка сообщения}
       SendDatagram(N, NameNumber, ReceiverName, False, MsgLen, Msg);
       {Ожидание подтверждения, что оно было передано}
       while N.CmdComplete = NbeCommandPending do
         if KeyPressed then begin
           {Пользователю надоело ждать}
           Status := NetBiosDeleteName(SenderName);
           SendOneDatagram := 2;
           Exit;
         end;
       Status := NetBiosDeleteName(SenderName);
       {Возврат статуса; ноль при успешном выполнении}
       SendOneDatagram := N.RetCode;
     end;

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

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


     function ReceiveOneDatagram(MaxLen : Word;
                                 var Msg) : Byte;

     var
       Status : Byte;
       NameNumber : Byte;
       N : NCB;
     begin
       {Добавить имя для последующих ссылок}
       Status := NetBiosAddName(ReceiverName, NameNumber);
       if Status <> 0 then begin
         {Проблема с именем приемника}
         ReceiveOneDatagram := Status;
         Exit;
       end;
       {Ожидание приема сообщения}
       ReceiveDatagram(N, NameNumber, False, MaxLen, Msg);
       {Ожидание приема сообщения}
       while N.CmdComplete = NbeCommandPending do
         if KeyPressed then begin
           {Пользователю надоело ждать}
           Status := NetBiosDeleteName(ReceiverName);
           ReceiveOneDatagram := 2;
           Exit;
         end;
       Status := NetBiosDeleteName(ReceiverName);
       {Возврат статуса; ноль при успешном выполнении}
       ReceiveOneDatagram := N.RetCode;
     end;

     Отметим, что приемнику не известно, какова фактическая длина
сообщения. Если его длина превысит MaxLen,  то NetBIOS возвращает
код ошибки  и приемник может снова вызвать ReceiveOneDatagram для
получения не поместившейся части.

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

     function CallSession(var Session : Byte) : Byte;

     var
       Status : Byte;
       NameNumber : Byte;
     begin
       {Добавить имя для последующих ссылок}
       Status := NetBiosAddName(SenderName, NameNumber);
       if Status <> 0 then begin
         {Проблема с именем передатчика}
         CallSession := Status;
         Exit;
       end;
       {Открыть сторону передатчика для сеанса}
       repeat
         Status := NetBiosCall(ReceiverName, SenderName, 5, 5, Session);
         if Status <> 0 then
           if KeyPressed then begin
             {Пользователю надоело ждать}
             Status := NetBiosDeleteName(SenderName);
             CallSession := 2;
             Exit;
           end;
       until Status = 0;
       {Если программа дошла до этого места, это означает
        успешное завершение}
       CallSession := Status;
     end;

     Два числа   5,   переданные  в  ,  задают,  что
уставки выдержки времени при последующих  посылках  и  получениях
будут равны  2.5  секунды  в  каждую  сторону  (5  полу-секундных
интервалов).

     На стороне приемника функция будет выглядеть так:


     function ListenSession(var Session : Byte) : Byte;

     var
       Status : Byte;
       NameNumber : Byte;
     begin
       {Добавить имя для последующих ссылок}
       Status := NetBiosAddName(ReceiverName, NameNumber);
       if Status <> 0 then begin
         {Проблема с именем приемника}
         ListenSession := Status;
         Exit;
       end;
       {Открыть сторону приемника для сеанса}
       repeat
         Status := NetBiosListen(SenderName, ReceiverName, 5, 5, Session);
         if Status <> 0 then
           if KeyPressed then begin
             {Пользователю надоело ждать}
             Status := NetBiosDeleteName(ReceiverName);
             ListenSession := 2;
             Exit;
           end;
       until Status = 0;
       {Если программа дошла до этого места, это означает
        успешное завершение}
       ListenSession := Status;
     end;


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

     Status := NetBiosSend(Session, MsgLen, Msg);

     Сеансы позволяют передавать и принимать сообщения до 64Кбайт
длиной. Любое не-нулевое значение  Status  указывает  на  ошибку.
Аналогичным образом, сообщение принимается так:

     Status := NetBiosListen(Session, MaxLen, Msg);

     Ни один   из   этих   вызовов   не   позволяет  пользователю
абортировать операцию  до  истечения  предопределенной   выдержки
времени.

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

     procedure TerminateSession(NameToDelete : NbNameStr);
     var
       Status : Byte;
     begin
       Status := NetBiosHangUp(Session);
       Status := NetBiosDeleteName(NameToDelete);
     end;

     Рабочие примеры  данной  концепции  приводятся  в  программа
MESEXAMP, NSEND и NRECEIVE.


Константы
---------

     DefaultAdapterNum : Byte = 0;

     Номер сетевого адаптера,  используемый  во  всех  вызовах  в
модуле NETBIOS.  Допустимыми значениями являются 0 и 1, где 0 это
первичный адаптер.

     NbCall             = $10;
     NbListen           = $11;
     NbHangup           = $12;
     Nbsend             = $14;
     NbReceive          = $15;
     NbReceiveAny       = $16;
     NbChainSend        = $17;
     NbSendDatagram     = $20;
     NbReceiveDatagram  = $21;
     NbSendBDatagram    = $22;
     NbReceiveBDatagram = $23;
     NbAddName          = $30;
     NbdeleteName       = $31;
     NbResetWaitOnly    = $32;
     NbCancelWaitOnly   = $35;
     NbAddGroupName     = $36;
     NbSendNoAck        = $71;
     NbChainSendNoAck   = $72;
     NbFindName         = $78;
     NbInvalidCommand   = $7F;{Неправильная команда, предназначенная
                               для тестирования установки NetBIOS}

     Значения, используемые в поле Command в NCB.

     NbeCommandPending  = $FF;

     Будучи записанной в поле   в  ,  означает,
что имеется подвешенная команда.

     NbeSuccess                = $00;
     NbeInvalidBufferLength    = $01;
     NbeInvalidCommand         = $03;
     NbeTimedOut               = $05;
     NbeIncomplete             = $06;
     NbeLocalNoAckFailed       = $07;
     NbeInvalidLsn             = $08;
     NbeNoResourceAvail        = $09;
     NbeSessionClosed          = $0A;
     NbeCommandCanceled        = $0B;
     NbeDuplicateName          = $0D;
     NbeNameTableFull          = $0E;
     NbeNameHasActive          = $0F;
     NbeLocalSessionTableFull  = $11;
     NbeSessionNoListen        = $12;
     NbeIllegalNameNumber      = $13;
     NbeCannotFindName         = $14;
     NbeNoAnswer               = $14;
     NbeInvalidName            = $15;
     NbeNameInUseOnRemote      = $16;
     NbeNameDeleted            = $17;
     NbeSessionAbnormal        = $18;
     NbeNameConflict           = $19;
     NbeIncompatibleDevice     = $1A;
     NbeInterfaceBusy          = $21;
     NbeTooManyCommands        = $22;
     NbeInvalidLanA            = $23;
     NbeCompletedWhileCancel   = $24;
     NbeReservedName           = $25;
     NbeNotValidCancel         = $26;
     NbeSystemError            = $40;
     NbeHotCarrierFromRemote   = $41;
     NbeHotCarrier             = $42;
     NbeNoCarrier              = $43;
     NbeUnexpectedAdaptClose   = $FD;

                                    
     Коды ошибки NetBIOS,  возвращаемые в поле  в .
Более подробную  информацию о том,  каким образом они участвуют в
каждой конкретной подпрограмме,  см.  в описаниях  подпрограмм  в
этой главе.  Многие команды NetBIOS могут генерировать ошибки $21
и $22.  Когда это происходит,  соответствующая реакция состоит  в
том, чтобы   выждать   некоторое  время  и  попытаться  повторить
операцию. Команды могут также генерировать  ошибки  $40-$FE.  Эти
ошибки указывают  на  аппаратный  сбой  или  на внутреннюю ошибку
NetBIOS. Соответствующая реакция состоит в том,  чтобы прекратить
работу программы и исправить аппаратное обеспечение.
     
     NbNameMax = 16;
     
     Максимальная длина имениNetBIOS.
     
     NoWait = $80;
     
     Битовая маска,  используемая  для  установки  старшего  бита
значений, хранимых в поле  в ,  указывающего на то,
что NetBIOS  не  должен  ожидать  завершения  события.  В  модуле
NETBIOS эта  константа  используется  опционально,  с   командами
посылки и приема датаграмм.
     
   
Типы
----
     
     CallNameType = Array[1..NbNameMax] of Char;
     
     Внутренний формат, используемый NetBIOS для хранения имен.
     
     NCB =
       record
         Command : Byte;
         RetCode : Byte;
         LSN : Byte;
         NameNum : Byte;
         Buffer : Pointer;
         BufLen : Word;
         CallName : CallNameType;
         Name : CallNameType;
         RTO : Byte;
         STO : Byte;
         PostRoutine : Pointer;
         LanaNum : Byte;
         CmdComplete : Byte;
         Reserved : Array[1..14] of Byte;
       end;
     
     Блок управления NetBIOS.  Эта структура данных размером в 64
байта является сердцем всех  запросов  NetBIOS.  Ниже  приводится
краткое описании ее полей:
     
     Command     Задает, какую команду NetBIOS выполнить.
     
     RetCode     Конечный результат команды. Допустимо только
                 если CmdComplete <> $FF.
     
     LSN         Локальный номер сеанса, чвязанный с командой.
     
     NameNum     Номер имени, связанный с командой.
     
     Buffer      Указатель на буфер с данными для команды.
     
     BufLen      Длина буфера данных.
     
     CallName    Обычно это имя удаленной станции, связанное
                 с командой.
     
     Name        Локальное имя, связанное с командой.
     
     RTO         Граничное значение выдержки времени для приема;
                 в единицах по 0.5 секунды.
     
     STO         Граничное значение выдержки времени для передачи;
                 в единицах по 0.5 секунды.
                                                                 
     PostRoutine Указатель подпрограммы, выполняемой при
                 завершении команды, работающей "без ожидания".
     
     LanaNum     Используемый сетевой адаптер, обычно 0.
     
     CmdComplete $FF, если команда подвешена, и любое другое
                 значение, если завершена.
     
     Reserved    Предназначается для внутреннего использования
                 NetBIOS.
     
      это указатель на подпрограмму,  которую должен
написать сам  пользователь.  Правильное  использование этого поля
позволяет организовывать  сложные,  управляемые  по   прерываниям
связи. Однако,  из-за  сложности правильного написания корректных
сервисных подпрограмм  модуль  NETBIOS  не  поддерживает   данную
концепцию. Поле    устанавливается  в  значение  nil
всеми подпрограммами, входящими в состав NETBIOS.
     
     NbNameStr = String[NbNameMaxc];
     
     Строковый тип, используемый для хранения имен NetBIOS.
                                                           
     
CancelRequest
-----------------------------------------------------------------
Объявление
----------

     function CancelRequest(var N : NCB) : Byte;

Параметры
---------
                                                
     N           Блок управления NetBIOS канцелируемой команды.

     Результат   0 в случае успешного завершения;
                 иначе код ошибки из .

Описание
--------
                                                   
     Канцелирует подвешенный   запрос   NetBIOS.    это  
команды, которая  должна  быть  канцелирована.  Поскольку  модуль
NETBIOS обеспечивает  работу  "без ожидания" только для сервисных
средств передачи    датаграмм,    единственными    канцелируемыми
командами могут        являться               и
, когда опция  имеет значение False.

Ошибки
------
     
     $24   В момент канцелирования команда завершилась.
     
     $26   Канцелирование данной команды невозможно.


Примечания
----------
     
     Невозможно ни  при  каких  условиях  канцелировать следующие
команды: ,, ,
, ,             и
.
     
                
ClearNCB
-----------------------------------------------------------------
Объявление
----------

     procedure ClearNCB(var N : NCB);

Параметры
---------
                                     
     N   Очищаемый блок управления NetBIOS.

Описание
--------
                                           
     Инициализирует  всеми нулями.  Это всегда требуется  до
использования NCB.  Подпрограммы верхнего уровня в модуле NETBIOS
вызывают данную процедуру для инициализации всех используемых ими
. Данная  процедура также используется программистом,  когда
ему нужно выполнить прямой вызов NetBIOS.
     
     
NetBiosAddGroupName
-----------------------------------------------------------------
Объявление
----------

     function NetBiosAddGroupName(NameToAdd : NbNameStr;
                                  var NameNumber : Byte) : Byte;

Параметры
---------
                                                                
     NameToAdd  Групповое имя, добавляемое в локальную таблицу имен.
                                                               
     NameNumber Возвращаемый номер имени.
     
     Результат  0 в случае успешного завершения;
                иначе код ошибки NetBIOS.

Описание
--------
     
     Добавляет групповое имя в локальную  таблицу  имен  NetBIOS.
Прочие узлы  могут  использовать такое же групповое имя,  но не в
качестве уникального имени.  NetBIOS циклически широковещательным
методом передает  это  имя по сети.  Если после адекватного числа
попыток не получено каких-либо ответов,  говорящих  о  конфликте,
 завершается   успешно.  Данная  функция  не
выполняет возврата до завершения команды.
     
      представляет собой строку символов ASCII  длиной
до 16 символов.  IBM, однако, накладывает на имя ряд ограничений.
Оно не может начинаться с нуля (#0),  звездочки  ('*')  или  трех
букв 'IBM'. Шестнадцатый символ не может быть символом ASCII #31.
 дополняет строку нулями до 16 символов. При
сравнении имен NetBIOS играет роль регистр.
     
      возвращает   ячейку   локальной  таблицы  имен,
назначенную этому имени.  Это число используется затем при вызове
подпрограмм, работающих с датаграммами.
                                       
Ошибки  (возвращаются в качестве результата функции)
------
     
     $0D   Дублирующееся имя в локальной таблице.
     
     $0E   Таблица имен заполнена.
     
     $15   Неверное имя.
     
     $16   Имя используется другой станцией.
     
     $19   Обнаружен конфликт между именами
            (дублирование данного имени где-то еще).


NetBiosAddName
-----------------------------------------------------------------
Объявление
----------

     function NetBiosAddName(NameToAdd : NbNameStr;
                             var NameNumber : Byte) : Byte;

Параметры
---------
                                                          
     NameToAdd  Уникальное имя, добавляемое в локальную таблицу имен.
                                                               
     NameNumber Возвращаемый номер имени.
     
     Результат  0 в случае успешного завершения;
                иначе код ошибки NetBIOS.

Описание
--------
     
     Добавляет уникальное  имя  в локальную таблицу имен NetBIOS.
NetBIOS циклически широковещательным методом передает это имя  по
сети. Если после адекватного числа попыток не получено каких-либо
ответов,  говорящих  о  совпадении  имен,   то   
завершается  успешно.  Данная  функция  не  выполняет возврата до
завершения команды.
     
      представляет собой строку символов ASCII  длиной
до 16 символов.  IBM, однако, накладывает на имя ряд ограничений.
Оно не может начинаться с нуля (#0),  звездочки  ('*')  или  трех
букв 'IBM'. Шестнадцатый символ не может быть символом ASCII #31.
 дополняет строку  нулями  до  16  символов.  При
сравнении имен NetBIOS играет роль регистр.
     
      возвращает   ячейку   локальной  таблицы  имен,
назначенную этому имени.  Это число используется затем при вызове
подпрограмм, работающих с датаграммами.
                                       
Ошибки  (возвращаются в качестве результата функции)
------
     
     $0D   Дублирующееся имя в локальной таблице.
     
     $0E   Таблица имен заполнена.
     
     $15   Неверное имя.
     
     $16   Имя используется другой станцией.
     
     $19   Обнаружен конфликт между именами
            (дублирование данного имени где-то еще).

     
NetBiosCall
-----------------------------------------------------------------
Объявление
----------

     function NetBiosCall(RemoteName, LocalName : NbNameStr;
                          SendTimeOut, RecTimeOut : Byte;
                          var SessionLSN : Byte) : Byte;

Параметры
---------
                                                        
     RemoteName    Имя NetBIOS удаленного партнера в сеансе.
     
     LocalName     Имя NetBIOS локального партнера по сеансу.
     
     SendTimeOut   Число полу-секундных интервалов выдержки
                   времени ожидания при посылке.
                                                
     RecTimeOut    Число полу-секундных интервалов выдержки
                   времени ожидания при приеме.
                                              
     SessionLSN    Возвращаемый локальный номер сеанса.
     
     Результат     0 в случае успешного завершения;
                   иначе код ошибки NetBIOS.

Описание
--------
                   
     Используется для вызова другой станции,  чтобы начать сеанс.
Удаленная станция  должна  вызвать  ,  прежде  чем
локальная станция вызовер . Для успешного выполнения
соединения каждая команда как правило вызывается в цикле (который
также должен  предусматривать  выход  из   него   по   инициативе
пользователя.) Как  только  сеанс  создан,  каждая  станция имеет
возможность посылать и принимать сообщения.
     
      задает  существующее   имя   из   таблицы   имен
локального адаптера.       задает   имя   в   таблице
принимающей станции.  Для  создания  сеанса  имена  должны   быть
согласованы между   сторонами.   В   целом,   имена  должны  быть
уникальными, поскольку  сеанс  не  может  соединять  более   двух
станций. Также   возможна  ситуация,  когда  обе  стороны  сеанса
находились на одной и той же станции.
     
      и      задают   в   полу-секундных
приращениях период времени,  в течение которого будут повторяться
попытки  связи  при  последующих  операциях  посылки  или  приема
сообщений. Нулевое значение этих параметров означает, что попытки
будут повторяться неограниченное время.
      
     После успешного    завершения    данной    подпрограммы    в
 будет  возвращен  локальный номер сеанса.  Это число
затем используется в вызовах для передачи или приема сообщений, а
также для разрыва сеанса.
     
Ошибки
------
      
     $05   Команда исчерпала установленную выдержку времени.
     
     $09   Удаленна таблица сеанса заполнена.
     
     $11   Локальная таблица сеанса заполнена.
     
     $12   Ни одна станция не ожидает приема.
     
     $14   Не найдено имя вызываемой станции, или нет ответа.
     
     $15   Неверное имя.
     
     $18   Ненормальное окончание сеанса.
     
     $19   Найдено конфликтующее имя (дублирующееся имя
           где-либо еще в сети.

Примечания
----------
                               
     Стратегия выбора имен NetBIOS аналогична  выбору  уникальных
номеров гнезд  в NetWare.  Самая простая,  и обычно самая  лучшая,
стратегия состоит в том, чтобы закодировать имя прямо в прикадной
программе, но   при   этом   сделать   его   установку  доступной
администратору сети. В случае нежелательного конфликта с именем в
другой работающей  в  сети  прикладной  программой  администратор
тогда имеет возможность выбрать другое имя.
     
     Альтернативные стратегии   заключаются    в    использовании
широковещательных датаграмм    или    разделяемых    файлов   для
установления приемлемого набора имен NetBIOS.
                                             
     
NetBiosDeleteName
-----------------------------------------------------------------
Объявление
----------

     function NetBiosDeleteName(NameToDelete : NbNameStr) : Byte;

Параметры
---------
                                                                 
     NameToDelete   Имя, удаляемое из локальной таблицы имен.

     Результат      0 в случае успешного завершения;
                    иначе код ошибки NetBIOS.

Описание
--------
                    
     Удаляет уникальное  или  групповое  имя из локальной таблицы
имен NetBIOS.

Ошибки
------
     
     $0F   Имя имеет активные сеансы. Удаление отложено.
     
     $15   Неверное имя.
                        
Примечания
----------
                        
     Если имя удаляется в то время,  как оно активно используется
в сеансе,  то  фактическое  удаление  откладывается до завершения
сеанса, обычно  командой   .   
возвращает в  этом  случае  код  ошибки  $0F.  Даже  хотя область
таблицы имен при этом не освобождается,  имя "разрегистрируется",
так что датаграммы и новые сеансы не могут его использовать.
     
     Все имена,  добавленные  в  таблицу  имен,  перед выходом из
прикладной программы должны быть удалены.  NetBIOS  не  выполняет
этого автоматически.   См.  демонстрационные  программы  NSEND  и
NRECEIVE, в  которых  имеются  примеры  использования   процедуры
выхода Turbo Pascal для удаления имен.
                                      
     
NetBiosHangUp
-----------------------------------------------------------------
Объявление
----------

     function NetBiosHangUp(SessionLSN : Byte) : Byte;

Параметры
---------
                                                     
     SessionLSN    Локальный номер завершаемого сеанса.

     Результат     0 в случае успешного завершения;
                   иначе код ошибки NetBIOS.

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

Ошибки
------

     $05   Команда исчерпала установленную выдержку времени.
        
     $08   Неверный локальный номер сеанса.
     
     $0A   Сеанс уже был закрыт.

     $0B   Команда была канцелирована.
     
     $18   Ненормальное окончание сеанса.

Примечания
----------
     
     NetBios при   вызове   данной  подпрограммы  завершит  любые
подвешенные команды NetBIOS,  использующие заданные  сеанс,  хотя
это и может вызвать задержку возврата из .
                                                         
     
NetBiosInstalled
-----------------------------------------------------------------
Объявление
----------

     function NetBiosInstalled : Boolean;

Параметры
---------

     Результат   True, если NetBIOS инсталлирован; иначе False.

Описание
--------
                                                               
     Данная подпрограмма определяет, был ли инсталлирован NetBIOS
или совместимый  с  ним  эмулятор.  Выполняется  проверка   того,
содержит ли  вектор  int $5C адрес nil,  или же указывает на BIOS
компьютера, защитый в ПЗУ.  В любом из этих случаев можно сделать
вывод о   том,  что  NetBIOS  не  загружен.  В  противном  случае
выполняется неправильный запрос NetBIOS ($7F). Эта команда вернет
константу    в   ,  если  NetBIOS
инсталлирован. Существует небольшая вероятность того,  что данный
метод войдет  в  конфликт  с  другим  обработчиком  int  $5C,  но
поскольку данное прерывание резервировано IBM  для  NetBIOS,  это
маловероятно.

             
NetBiosListen
-----------------------------------------------------------------
Объявление
----------

     function NetBiosListen(RemoteName, LocalName : NbNameStr;
                            SendTimeOut, RecTimeOut : Byte;
                            var SessionLSN : Byte) : Byte;

Параметры
---------
                                                        
     RemoteName    Имя NetBIOS удаленного партнера по сеансу.
     
     LocalName     Имя NetBIOS локального партнера по сеансу.
     
     SendTimeOut   Число полу-секундных интервалов выдержки
                   времени ожидания при посылке.
                                                
     RecTimeOut    Число полу-секундных интервалов выдержки
                   времени ожидания при приеме.
                                              
     SessionLSN    Возвращаемый локальный номер сеанса.
     
     Результат     0 в случае успешного завершения;
                   иначе код ошибки NetBIOS.

Описание
--------
                   
     Используется для  ожидания  вызова  другой  станции,  котоый
начнет  сеанс.  Локальная станция должна вызвать ,
прежде чем удаленная станция вызовет . Для успешного
выполнения  соединения  каждая  команда  как правило вызывается в
цикле (который также должен  предусматривать  выход  из  него  по
инициативе пользователя.) Как только сеанс создан, каждая станция
имеет возможность посылать и принимать сообщения.
     
      задает  существующее   имя   из   таблицы   имен
локального адаптера.       задает   имя   в   таблице
вызывающей  станции.  Для  создания  сеанса  имена  должны   быть
согласованы между   сторонами.   В   целом,   имена  должны  быть
уникальными, поскольку  сеанс  не  может  соединять  более   двух
станций. Также   возможна  ситуация,  когда  обе  стороны  сеанса
находились на одной и той же станции.
     
      и      задают   в   полу-секундных
приращениях период времени,  в течение которого будут повторяться
попытки  связи  при  последующих  операциях  посылки  или  приема
сообщений. Нулевое значение этих параметров означает, что попытки
будут повторяться неограниченное время.
      
     После успешного    завершения    данной    подпрограммы    в
 будет  возвращен  локальный номер сеанса.  Это число
затем используется в вызовах для передачи или приема сообщений, а
также для разрыва сеанса.
     
Ошибки
------
      
     $05   Команда исчерпала установленную выдержку времени.
     
     $09   Удаленна таблица сеанса заполнена.
     
     $11   Локальная таблица сеанса заполнена.
     
     $15   Неверное имя.
     
     $18   Ненормальное окончание сеанса.
     
     $19   Найдено конфликтующее имя (дублирующееся имя
           где-либо еще в сети.)

                          
NetBiosReceive
-----------------------------------------------------------------
Объявление
----------

     function NetBiosReceive(SessionLSN : Byte;
                             PacketSize : Word;
                             var Packet) : Byte;

Параметры
---------
     
     SessionLSN    Используемый номер активного сеанса.
     
     PacketSize    Максимальный размер пакета данных (0..65535).
     
     Packet        Буфер для приема данных.
     
     Результат     0 в случае успешного завершения;
                   иначе код ошибки NetBIOS.


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

Ошибки
------
     
     $05   Команда исчерпала установленную выдержку времени.
     
     $06   Не полностью принятое сообщение (буфер мал).
     
     $08   Неверный локальный номер сеанса.
     
     $0A   Сеанс был закрыт.

     $0B   Команда была канцелирована.
     
     $18   Ненормальное окончание сеанса.


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

     procedure NetBiosRequest(var N : NCB);

Параметры
---------
                                           
     N    Блок упрвление NetBIOS.

Описание
--------
                                 
     Выполняет вызов  NetBIOS,  установив  для  этого  ES:BX  как
указатель на    и  затем вызвав прерывание $5C.   перед
этим должен быть инициализирован вызовом  с последующей
установкой соответствующих полей. Обычно прикладным программам не
требуется вызывать данную подпрограмму нижнего уровня.  Она нужна
программисту только  при  необходимости  выполнить  прямой  вызов
NetBIOS.
                    
Примечания
----------
     
     Данная подпрограмма    реализована    в   виде   встроенного
макрорасширения, которое фактически  использует  меньшее  кодовое
пространство, по   сравнению   с   выполнением   дальнего  вызова
отдельной подпрограммы.

     
NetBiosSend
-----------------------------------------------------------------
Объявление
----------

     function NetBiosSend(SessionLSN : Byte;
                          PacketSize : Word;
                          var Packet) : Byte;

Параметры
---------
     
     SessionLSN    Используемый номер активного сеанса.
     
     PacketSize    Максимальный размер пакета данных (0..65535).
     
     Packet        Посылаемые данные.
     
     Результат     0 в случае успешного завершения;
                   иначе код ошибки NetBIOS.


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

     Пересылаемые данные   передаются   в   параметре   .
поскольку это   нетипированный  параметр-переменная,  при  вызове
данной подпрограммы здесь можно использовать  любой  тип  данных.
Обычно лучше  всего  использовать  операцию Turbo Pascal SiseOf()
для задания размера переменной, как в следующем примере:
     
     var
       Buffer : Array[1..1000] of Char;
     ...
     Status := NetBiosSend(SessionNumber, SizeOf(Buffer), Buffer);
     
Ошибки
------
     
     $05   Команда исчерпала установленную выдержку времени.
     
     $08   Неверный локальный номер сеанса.
     
     $0A   Сеанс был закрыт.

     $0B   Команда была канцелирована.
     
     $18   Ненормальное окончание сеанса.

     
ReceiveBDataGram
-----------------------------------------------------------------
Объявление
----------

     procedure ReceiveBDatagram(var N : NCB; ReceiverNameNum : Byte;
                                Wait : Boolean; DGSize : Word;
                                var Datagram);
     
Параметры
---------
                                              
     N               Блок управления NetBIOS.
     
     ReceiverNameNum Номер имени приемника.
     
     Wait            True, если требуется ждать завершения.
     
     DGSize          Максимальный размер датаграммы.
     
     DataGram        Буфер для приема данных.
                                             
Описание
--------
                                             
     Эта команда  работает   аналогично   ,   но
принимает только  сообщения,  посланные в .  Более
подробную информацию см. в описании .

                                                      
ReceiveDatagram
-----------------------------------------------------------------
Объявление
----------

     procedure ReceiveDatagram(var N : NCB;
                               ReceiverNameNum : Byte;
                               Wait : Boolean;
                               DGSize : Word;
                               var Datagram);
     

Параметры
---------

     N               Блок управления NetBIOS.
     
     ReceiverNameNum Номер имени приемника.
     
     Wait            True, если требуется ждать завершения.
     
     DGSize          Максимальный размер датаграммы (обычно 0..512).
     
     DataGram        Буфер для приема данных.


Описание
--------
     
     Принимает нормальную  датаграмму,  направленную   по   имени
NetBIOS с   заданным  .  Датаграмма  могла  быть
передана любой другой станцией. Передача могла быть адресована на
уникальное имя  или  на  групповое  имя,  разделяемое несколькими
станциями.
     
     Хотя данная команда не позволяет принимать широковещательные
датаграммы, ее  можно  настроить  на прием нормальной датаграммы,
задав в  значение $FF.
     
     Вызов  должен быть уже подвешен в  момент,
когда передатчик   посылает   сообщение.  Если  это  не  так,  то
сообщение теряется.
     
     Если  имеет значение True,  то вызов 
не возвратится до тех пор,  пока сообщение не будет получено. Эту
опцию нужно  использовать   осторожно,   поскольку   максимальная
выдержка времени на прием датаграммы не определяется.
     
     В большинстве  случаев  установка    в  значение False
предпочтительна. Тогда   возврат   из   подпрограммы   происходит
немедленно. Вызывающая   прикладная  программа  может  продолжить
другие работы,  ожидая  прихода  сообщения.  Тем  временем   блок
управления NetBIOS      и   буфер   данных    должны
оставаться в памяти без изменений, так как в конце концов NetBIOS
запишет в них статус и данные.
     
     Для того,   чтобы   определить,   завершено   ли   действие,
прикладная программа должна опрашивать поле  в 
следующим образом:
     
     while (N.CmdComplete = NbeCommandPending) and not TimedOut
     do begin
       {Выполняем другую работу}
       {Если прошло слишком много времени,
        то TimedOut устанавливается в значение True}
     end;
     if TimedOut then
       {Канцелирование запроса на прием}
       Status := CancelRequest(N)
     else if N.RetCode <> 0 then
       {Обработка ошибки}
     else
       {Сообщение принято};

     В нетипированном  параметре    может быть передана
переменная любого типа. Максимальный размер датаграммы зависит от
конкретной реализации,   но   обычно   составляет   512   байтов.
Убедитесь, что размер буфера не меньше  ,  иначе  NetBIOS
затрет чужую область памяти.
              
Ошибки
------
     
     $06   Не полностью принятое сообщение.
     
     $0B   Команда была канцелирована.
     
     $13   Неверный номер имени.
     
     $17   Имя было удалено.
     
     $19   Обнаружены конфликтующие имена.

Примечания
----------
     
     Если получена  ошибка  $06,  то  сообщение было больше,  чем
. Оставшаяся часть сообщения будет потеряна.
     
     
ResetAdapter
-----------------------------------------------------------------
Объявление
----------

     function ResetAdapter(SessionCount : Byte;
                           CommandCount : Byte) : Byte;

Параметры
---------
                                                      
     SessionCount   Максимально допустимое число сеансов.
     
     CommandCount   Максимальное число подвешенных команд NetBIOS.
                                                                  
     Результат      0 в случае успешного завершения;
                    иначе код ошибки NetBIOS.
     

Описание
--------
     
     Сбрасывает адаптер NetBIOS, заданный глобальной типированной
константой ,  по  умолчанию  равной   0.   Эта
команда была  первоначально  разработана  для  сброса аппаратного
сетевого адаптера  для  IBM  PC  LAN;  эмуляторы  NetBIOS   могут
обрабатывать эту команду по-разному. Одна из ее функций состоит в
очистке локальных таблиц  имен  и  сеансов;  все  версии  NetBIOS
выполняют данную акцию.
     
      это число одновременных сеансов,  позволенных
для текущей  рабочей  станции.  (По  умолчанию  для  PC  LAN  это
значение равно  6).   это число подвешенных команд.
(Значение по  умолчанию  12).  Если  сервисные  подпрограммы  для
передачи датаграмм  модуля  NETBIOS  не используются с параметром
, установленным в False,  то  ни  на  что  не
влияет.
       
Ошибки
------
     
     $23   Неверный номер адаптера.

                                   
     
SendBDataGram
-----------------------------------------------------------------
Объявление
----------

        procedure SendBDatagram(var N : NCB;
                                SenderNameNum : Byte;
                                Wait : Boolean;
                                DGSize : Word;
                                var Datagram);
     
Параметры
---------
                                              
     N               Блок управления NetBIOS.
     
     SenderNameNum   Номер имени передатчика.
     
     Wait            True, если требуется ждать завершения.
     
     DGSize          Размер датаграммы (обычно 0..512).
     
     Datagram        Посылаемые данные.
                                             
Описание
--------
                                             
     Эта команда работает аналогично ,  но посылает
сообщения всем узлам.  Получат  сообщение  только  те  узлы,  что
ожидают приема при помощи подпрограммы .  Более
подробную информацию см. в описании .

                                         
     
SendDatagram
-----------------------------------------------------------------
Объявление
----------

     procedure SendDatagram(var N : NCB;
                            SenderNameNum : Byte;
                            ReceiverName : NbNameStr;
                            Wait : Boolean;
                            DGSize : Word;
                            var Datagram);
     

Параметры
---------

     N               Блок управления NetBIOS.
     
     SenderNameNum   Номер имени передатчика.
                                            
     ReceiverName    Имя NetBIOS приемника.
     
     Wait            True, если требуется ждать завершения.
     
     DGSize          Размер датаграммы (обычно 0..512).
     
     DataGram        Пересылаемые данные.


Описание
--------
     
     Посылает датаграмму  по  заданному   имени   NetBIOS.   Если
 это уникальное имя,  то сообщение получит максимум
одна станция.  Если  это групповое  имя,  сообщение
может попасть  на несколько станций одновременно.  
может ссылаться на имя в пределах текущей рабочей станции; в этом
случае, и  если  станция  ожидает  приема,  то  она  получит свое
собственное сообщение.

      это  номер,  связанный   с   именем,   ранее
добавленным в  локальную  таблицу  имен  передатчика.  Этот номер
используется NetBIOS для организации пересылки сообщения. Номер 1
таблицы всегда  безопасно  использовать,  поскольку  он  связан с
постоянным именем адаптера.
     
     Сообщение будет  игнорироваться6  если   станция-адресат   в
момент посылки    датаграммы   не   имеет   подвешенного   вызова
.
                                    
     Если   имеет  значение  True,  то  вызов  NetBIOS   не
возвратится до тех пор,  пока сообщение не будет передано.  Чтобы
определить,  успешно ли  прошла  передача,  прикладная  программа
может  проверять  значение  в  .  (Было  ли  сообщение
получено,  это другой вопрос;  передатчик датаграммы не  получает
уведомление  о  приеме сообщения,  если только приемник не пошлет
ответ явно.  Для сообщений,  требующих подтверждение, используйте
сервисные средства сеансов NetBIOS).
     
     Если  имеет значение False,  то происходит немедленный
возврат из подпрограммы после ее  вызова.  Вызывающая  прикладная
программа может продолжать другую работу, ожидая, пока произойдет
передача.  Тем временем  переменная    должна  оставаться  в
памяти  без  изменений,  так как в конце концов NetBIOS запишет в
нее информацию о статусе.
                                 
     Для того,   чтобы   определить,   завершено   ли   действие,
прикладная программа должна опрашивать поле  в 
следующим образом:
     
     while N.CmdComplete = NbeCommandPending do begin
       {Выполняем другую работу}
     end;
     if N.RetCode <> 0 then
       {Обработка ошибки} ;
     
     Нетипированный параметр   может  содержать  данные
любого типа. Максимальный размер датаграммы зависит от конкретной
реализации, но обычно составляет 512 байтов.
     

Ошибки
------
     
     $01   Неверная длина буфера (слишком большой ).
     
     $13   Неверный номер имени
           (номер имени передатчика не существует).
     
     $19   Обнаружены конфликтующие имена (дублирующиеся имена
           еще где-либо в сети).

                                
     

     
C. SHARE
--------
     
     Модуль SHARE  реализует  разнообразные  сете-ориентированные
функции. Многие из них работают с  версиями  DOS  3.1  и  старше.
прочие требуют  загрузки  утилиты  SHARE.EXE,  входящей  в  ту же
версию DOS. Некоторые функции требуют, чтобы рабочая станция была
подключена к MS-NET - совместимой сети,  например 3Com 3+. Novell
NetWare эмулирует большинство из этих интерфейсов,  поэтому почти
все функции работают с NetWare. Мы будем сообщать все особенности
для каждой функции.  Часто будет говориться о том, что необходима
загрузка SHARE.EXE,   но   фактически   многие  сетевые  оболочки
реализуют эту функцию в других файлах.
     
     Ниже приводится список возможностей,  обеспечиваемых модулем
SHARE:
     
     - определение того, загружена ли SHARE;
     
     - запирание и отпирание любой части файла;
     
     - установка числа попыток при ошибках доступа к запертому
       файлу;
     
     - сброс буферов DOS на диск;
     
     - получение расширенной информации об ошибках DOS;
     
     - определение того, находится ли заданный дисковод или файл
       на удаленной машине;
     
     - получение имени текущей рабочей станции;
     
     - определение того, загружена ли PC LAN;
     
     - получение информации о версии PC LAN;
     
     - переназначение дисковода или принтера в сети на локальное
       имя;
     
     - канцелирование переназначения.
     
     Все эти   концепции,    за    исключением,    может    быть,
"переназначения",  должны  быть  ясны  для  программистов.  Здесь
термин "переназначение"  используетя в несколько ином смысле, чем
в DOS,  где  он  обычно обозначает изменение направления канала к
стандартному устройству ввода  или  вывода  на  некоторое  другое
устройство. В  контексте MS-NET переназначение представляет собой
процесс, в ходе которого сетевой ресурс  (принтер  или  дисковод)
делается доступным  рабочей  станции.  Переназначение  записывает
имя, имеющее смысл для рабочей станции,  в таблицу6  используемую
"сервисными средствами  переназначения"  MS-NET,  так  что  затем
MS-NET может   транслировать   ссылку   на   локальное   имя    и
переназначить запрос  к  ресурсу  в  соответствующую  точку сети.
Более подробную информацию см.  в описаниях 
и .
     
     Дальнейшую информацию   о   вызовах   в   модуле   SHARE  мы
рекомендуем смотреть в следующей литературе:
     
     Advanced MS-DOS Programming, 2nd Edition
       Ray Duncan, Microsoft Press, 1988.
     
     DOS Programmer's Reference
       Terry R.Dettman, Que Corporation, 1988.
     
     PC Network Technical Reference
       IBM manual #632205.
     
     Большинство подпрограмм  возвращает  стандартные коды ошибок
DOS. Модуль SHARE  определяет  три  дополнительных  кода  ошибки,
описанные ниже в разделе "Константы". Список кодов ошибок DOS см.
в описании , ниже в данной главе.
     
     
Константы
---------
     
     PrinterSetupMax = 64;
     
     Максимальная длина установочной строки принтера.
     
     WrongDosVersion = $FFFD;
     FileNotOpen     = $FFFE;
     ShareNotLoaded  = $FFFF;
     
     Не принадлежащие DOS коды  ошибок,  возвращаемые  некоторыми
функциями SHARE.
     
     
Типы
----
     
     DeviceType = (DevPrinter, DevDrive);
     
     Типы устройств,    связанные    с    сервисными   средствами
переназначения устройств.
     
     NetworkStr = String[28];
     
     Строковый тип, используемый для имени сетевого ресурса.
     
     PathName = String[79];
     
     Строковый тип,  используемый для представления  имен  полных
маршрутов DOS.
     
     PCLanOpType = (LanUnknown, LanRedirector, LanReceiver,
                    LanMessenger, LanServer);
     
     Строковый тип, используемый в установочных строках принтера.
     
     
Переменные
----------
     
     DosMajor : Byte;
     DosMinor : Byte;
     
     Старший и  младший  номера  версии  MS-DOS.  Эти  переменные
устанавливаются блоком инициализации SHARE.
     
     
CancelRedirection
-----------------------------------------------------------------
Объявление
----------

     function CancelRedirection(LocalName : NbNameStr) : Word;

Параметры
---------
                                                             
     LocalName   Устройство, переназначение к которому канцелируется.

     Результат   0 в случае успешного завершения;
                 иначе код ошибки DOS.

Описание
--------
     
     Канцелирует переназначение,     ранее     установленное    в
.    должно   соответствовать    ранее
заданному имени. Требует DOS 3.1 или старше, совместимой с MS-NET
сети и загрузки SHARE.EXE.


Ошибки  (возвращаются в качестве результата функции)
------
                                                    
     См. .

                            
DosLockRec
-----------------------------------------------------------------
Объявление
----------

     function DosLockRec(var F; LockPosition,LockLength : LongInt) : Word;

Параметры
---------
     
     F             Запираемый файл.
     
     LockPosition  Смещение в файле, начиная с которого
                   запирается файл.
     
     LockLength    Число запираемых байтов.

     Результат     0 в случае успешного завершения;
                   иначе код ошибки DOS.

Описание
--------
      
     Использует вызов DOS  $5C  для  запирания  всего  или  части
файла. Требует DOS 3.0 или старше и загрузки программы DOS SHARE.
     
     Параметр   нетипированный,  что  позволяет передачу здесь
любой файловой переменной Turbo Pascal. Вызывающая программа сама
отвечает за   то,   чтобы   переданная  переменная  действительно
являлась файловой переменной.  Файл  при  этом  уже  должен  быть
открыт.
     
      задает   начало   запираемой  области  файла.
Первый байт файла имеет  позицию  0.    задает  число
запираемых байтов. Запирание за концом файла ошибкой не является.
При отпирании файла  должны  быть  использованы  те  же  значения
 и .
                              
Ошибки  (возвращаются в качестве результата функции)
------
     
     См. .
     
Примечания
----------
     
     Перед закрытием  файла  не  забудьте  отпереть  все запертые
места файла. Если этого не сделать, то результаты непредсказуемы.
     
                                                                 
GetExtendedError
-----------------------------------------------------------------
Объявление
----------

     function GetExtendedError(var Class, Action, Locus : Byte) : Word;

Параметры
---------
                                                                       
     Class      Класс (тип) последней ошибки DOS.
     
     Action     Рекомендуемое действие.
     
     Locus      Устройство, сообщившее об ошибке.

     Результат  Код самой последней ошибки DOS.

Описание
--------
                                               
     Возвращает расширенную информацию о самой  последней  ошибке
DOS. Требуется DOS 3.0 или старше.  (В случае более ранних версий
DOS возвращает нули).
     
     Следующая ниже таблица расширенных кодов ошибки  может  быть
использована для интерпретации кодов ошибки, возвращаемых другими
функциями модуля SHARE.

Ошибки
------
                       
Расширенные коды ошибки
-----------------------
     
     $01   Неверный номер функции DOS.
     
     $02   Файл не найден
     
     $03   Маршрут не найден.
     
     $04   Слишом много открытых файлов.
     
     $05   Доступ отвергнут.
     
     $06   Неверный логический номер.
     
     $07   Разрушены блоки управления памятью.
     
     $08   Недостаточно памяти.
     
     $09   Неверный адрес блока памяти.
     
     $0A   Неверный контекст.
     
     $0B   Неверный формат.
     
     $0C   Неверный код доступа.
     
     $0D   Неверные данные.
     
     $0E   Неизвестный модуль.
     
     $0F   Неверный дисковод.
     
     $10   Попытка удаления текущей директории.
     
     $11   Не то же самое устройство.
     
     $12   Больше файлов нет.
     
(Коды критических ошибок, отображаемые DOS)
     
     $13   Диск защищен от записи.
     
     $14   Неизвестный модуль.
     
     $15   Дисковод не готов.
     
     $16   Неизвестная команда.
     
     $17   CRC-ошибка в данных (циклического избыточного кода).
     
     $18   Неправильная дина структуры запрса.
     
     $19   Ошибка поиска.
     
     $1A   Неизвестный тип носителя.
     
     $1B   Сектор не найден.
     
     $1C   На принтере кончилась бумага.
     
     $1D   Сбой при записи.
     
     $1E   Сбой при чтении.
     
     $1F   Общий сбой.
     
(Коды, новые для DOS версии 3)
     
     $20   Нарушение разделения.
     
     $21   Нарушение запирания.
     
     $22   Неправильная смена диска.
     
     $23   Недоступен FCB (блок управления файлом).
     
     $24   Превышен размер буфера разделения.
     
     $32   Неподдерживаемый сетевой запрос.
     
     $33   Удаленная машина не находится в режиме ожидания приема.
     
     $34   Имя дублируется в сети.
     
     $35   Сетевое имя не найдено.
     
     $36   Сеть занята.
     
     $37   Устройство больше не существует в сети.
     
     $38   Превышен лимит команд NetBIOS.
     
     $39   Аппаратная ошибка сетевого адаптера.
     
     $3A   Неверный ответ от сети.
     
     $3B   Непредвиденная ошибка сети.
     
     $3C   Несовместим удаленный адаптер.
     
     $3D   Очередь принтера заполнена.
     
     $3E   Недостаточно места для файла печати.
     
     $3F   Файл печати канцелирован.
     
     $40   Сетевое имя удалено.
     
     $41   Доступ к сети отвергнут.
     
     $42   Неверный тип сетевого устройства.
     
     $43   Сетевое имя не найдено.
     
     $44   Превышен лимит сетевых имен.
     
     $45   Превышен лимит сеансов NetBIOS.
     
     $46   Разделение файла временно приостановлено.
     
     $47   Сетевой запрос не принят.
     
     $48   Переназначение принтера или дисковода приостановлено.
     
     $50   Файл уже существует.
     
     $52   Невозможность создания директории.
     
     $53   Сбой по критической ошибке.
     
     $54   Слишком много переназначений.
     
     $55   Дублирование переназначений.
     
     $56   Неверный пароль.
     
     $57   Неверный параметр.
     
     $58   Сбой на сетевом устройстве.
     
     $59   Функция, не поддерживаемая в сети.
     
     $5A   Требуемый компонент системы не установлен.
        
     
Классы ошибок
-------------
     
     $01   Недостаточность ресурсов (например, дисковой памяти
           или логических номеров).
     
     $02   Временная проблема (например, заперт файл).
     
     $03   Проблема приоритетов доступа.
     
     $04   Внутренняя ошибка системного программного обеспечения.
     
     $05   Аппаратный сбой.
     
     $06   Сбой системного программного обеспечения
           (например, отсутствует файл конфигурации).
     
     $07   Ошибка прикладной программы.
     
     $08   Файл или элемент данных не найден.
     
     $09   Неверный тип или формат файла или элемента данных.
     
     $0A   Файл или элемент данных заперт.
     
     $0B   Неверный или неисправный диск.
     
     $0C   Элемент уже существует.
     
     $0D   Неизвестная ошибка.
     
     
Рекомендуемые действия
----------------------
     
     $01   Повторить попытку разумное число раз, а затем запросить
           абортирование операции.
     
     $02   Повторить попытку разумное число раз с задержками между
           попытками, а затем запросить абортирование операции.
     
     $03   Принять скорректированную информацию от пользователя.
     
     $04   Очистить (например, освободить запирания и закрыть
           файлы) и абортировать прикладную программу.
     
     $05   Немедленно абортировать прикладную программу.
     
     $06   Игнорировать ошибку.
     
     $07   Повторить попытку после вмешательства пользователя
           для исправления ошибки.
     
     
Коды устойств, сообщивших об ошибке
-----------------------------------
     
     $01   Неизвестно.
     
     $02   Устройство6 работающее с блоками (диск).
     
     $03   Сеть.
     
     $04   Последовательное устройство.
     
     $05   Оперативная память.
     
     
GetMachineName
-----------------------------------------------------------------
Объявление
----------

     function GetMachineName(var MachName : NbNameStr;
                             var MachNum : Byte) : Boolean;

Параметры
---------
     
     MachName    Возвращаемый номер машины рабочей станции.
     
     MachNum     Возвращаемфй номер имени NetBIOS, связанный с именем.
                                                                      
     Результат   True, если вызов завершился успешно; иначе False.

Описание
--------
     
     Возвращает имя  машины  и его индекс в таблице имен NetBIOS.
Требует DOS 3.1 и старше, а также сеть, совместимую с MS-NET.
     
     Функция возвращает False  только  если  DOS  возвращает  код
ошибки. Она  может иметь значение True,  даже если для машины имя
не определено.  В этом случае  будет представлять собой
пустую строку, а  будет равен нулю.
     
     Гарантии, что   будет уникальным для разных рабочих
станций, не существует,  поскольку это  просто  индекс  локальной
таблице имен  NetBIOS.  Вопрос  о том,  как определить уникальные
номера рабочих станций, рассматривается в разделе 5.С.
     
     
GetPrinterSetup
-----------------------------------------------------------------
Объявление
----------

     function GetPrinterSetup(var SetUpStr : PrinterSetUpStr;
                              RedirIndex : Word) : Boolean;

Параметры
---------
                                                          
     SetUpStr      Возвращаемая установочная строка принтера.
     
     RedirIndex    Индекс принтера в таблице переназначений.

     Результат   True, если вызов завершился успешно; иначе False.
     
Описание
--------
     
     Возвращает установочную   строку   принтера   для  заданного
устройства  в  таблице   переназначений.   В   случае   успешного
завершения  возвращает  True.  Требует DOS 3.1 и старше,  а также
сеть, совместимую с MS-NET.
     
     Установочная строка принтера посылается перед печатью любого
файла на  заданном принтере сети.  Тем самым разные станции имеют
возможность настраивать  рабочий   режим   принтера   по   своему
усмотрению.
     
      первоначально    устанавливается   при   вызове
 для переназначения порта локального принтера  на
сетевое устройство. Первый переназначенный ресурс получает индекс
0, следующий  получает  индекс  1,   и   т.д.   Если   во   время
переназначения индекс  не был запомнен в программе,  то его можно
выяснить, вызывая   для  каждого  индекса  и
сравнивая полученную информацию с желаемым устройством.
     
     Функция возвращает  False  только  если    не
задает переназначенный принтер.

                               
GetRedirectionEntry
-----------------------------------------------------------------
Объявление
----------

     function GetRedirectionEntry(RedirIndex : Word;
                                  var LocalName : NbNameStr;
                                  var NetName : NetworkStr;
                                  var UserParam : Word;
                                  var Valid : Boolean;
                                  var Dev : DeviceType) : Word;

Параметры
---------
                                                               
     RedirIndex    Индекс в таблице переназначений.
     
     LocalName     Возвращаемое локальное имя устройства.
     
     NetName       Возвращаемое сетевое имя ресурса.
     
     UserParam     Возвращаемый параметр пользователя.
     
     Valid         True, если это допустимое устройство;
                   иначе False.
     
     Dev           Тип устройства (DevPrinter или DEvDrive).
                                                            
     Результат     0 в случае успешного завершения;
                   иначе код ошибки DOS.
     
Описание
--------
     
     Возвращает информацию    о    заданном    элементе    списка
переназначений.  Первый переназначенный элемент  имеет  номер  0.
Требует DOS 3.1 или старше,  совместимой с MS-NET сети и загрузки
SHARE.EXE.
     
      это  имя  принтера,  например  'LPT1',  или  имя
дисковода, например 'G:'.
     
      это  имя сетевого ресурса,  связанного с локальным
именем.
     
      это  тоже   самое   определяемое   пользователем
значение, что  было  назначено  элементу  переназначения  при его
создании.
     
      возвращает   значения:   либо    ,    либо
.

Ошибки  (возвращаемые в качестве результата функции)
------
                                                    
     См. .

                            
GetTempFileName
-----------------------------------------------------------------
Объявление
----------

     function GetTempFileName(PathN : PathName;
                              var TempFileName : PathName) : Word;

Параметры
---------
                                                                  
     PathN          Директория, хранящая временный файл.
     
     TempFileName   Возвращаемое полное имя маршрута к временному
                    файлу.
     
     Результат      0 в случае успешного завершения;
                    иначе код ошибки DOS.
     
Описание
--------
     
     Возвращает имя  файла,  гарантированно  уникальное  в данной
директории. Файл этим вызовом создается и немедленно закрывается.
Прикладная программа  должна  ссылаться  на  возвращенное имя при
открытии на пересоздание  или  на  чтение,  используя  для  этого
соответствующую файловую  переменную Turbo Pascal.  Требуется DOS
3.0 и старше.
     
      должен задавать существующие дисковод и директорию.


Ошибки
------
                                                                
     

Примечания
----------
     
     См. .
     
     
IBMPCLanLoaded
-----------------------------------------------------------------
Объявление
----------

     function IBMPCLanLoaded(var LanMode : PCLanOpType) : Boolean;

Параметры
---------
     
     LanMode    Режим функционирования PC LAN (если PC LAN загружена).


     Результат  True, если PC LAN загружена; иначе False.

Описание
--------
     
     Возвращает True,  если программа IBM PC LAN загружена.  Если
PC LAN  загружена,  то  параметр  содержит значение типа
. Этот тип обозначает  режим,  в  котором  находится
рабочая станция.  Допустимыми  режимами  являются  LanRedirector,
LanReceiver, LanMessenger   или   LanServer.   Более    подробную
информацию об этих режимах см. в документации по PC LAN.
                                                        
Примечания
----------
     
     Novell Advanced NetWare может передать тест для PC LAN. (Это
происходит при  загруженной  резидентной  программе  INT2F).  При
определении типа сетевой операционной системы  сначала  проверьте
Novell. Пример приводится в файле программы NETINFO.PAS.
     
                                                        
IsDriveLocal
-----------------------------------------------------------------
Объявление
----------

     function IsDriveLocal(Drive : Byte) : Boolean;

Параметры
---------
                                                  
     Drive       Номер желаемого дисковода (0:умолчание, 1:А, и т.д.)

     Результат   True, если это локальный дисковод, и False,
                 если он находится на удаленной машине.

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

                       
IsFileLocal
-----------------------------------------------------------------
Объявление
----------

     function IsFileLocal(var F) : Boolean;

Параметры
---------
                               
     F     Открытый файл Turbo Pascal.

Описание
--------
     
     Определяет, является ли заданный файл локальным по отношению
к  текущей рабочей станции,  или физически находится на удаленной
машине  (и  доступен   посредством   механизма   переназначения).
Требуется  DOS  3.1  и  старше.  Прикладная программа сама должна
обеспечивать,  чтобы  задавал файловую переменную Turbo Pascal
любого  типа,  и  файл  был уже открыт.   возвращает
True, если была задана недопустимая файловая переменная.

     
RedirectDevice
-----------------------------------------------------------------
Объявление
----------

     function RedirectDevice(TypeOfDev : DeviceType;
                             LocalName : NbNameStr;
                             NetworkName : NetworkStr;
                             Password : NetworkStr;
                             UserParam : Word) : Word;

Параметры
---------
                                                      
     TypeOfDev     Обозначает устройство - диск или принтер.
     
     LocalName     Имя локального дисковода или принтера.
     
     NetworkName   Имя переназначаемого сетевого ресурса.
     
     Password      Необязательный пароль для доступа к сетевому
                   ресурсу.
     
     UserParam     Необязательный параметр, возвращаемый
                   .

     Результат     0 в случае успешного завершения;
                   иначе код ошибки DOS.

Описание
--------
     
     Связывает локальное  имя с сетевым принтером или дисководом.
Требует DOS 3.1 или старше,  совместимой с MS-NET сети и загрузки
SHARE.EXE.
     
      это либо , либо , задающие
переназначения принтера или дисковода, соответственно.
     
     Для перенахначения принтера  это одно из:  'PRN',
'LPT1', 'LPT2'   или   'LPT3'.   Для   переназначения   дисковода
 это  обозначение  дисковода,  наприер   'F:'.   После
успешного выполнения  переназначения  программные  ссылки  на эти
имена будут вызывать доступ к сетевым ресурсам, а не к локальным,
как до переназначения.
     
      задает  имя  сетевого ресурса.  Например,  для
переназначения локального  дисковода  F:  на  директорию  '\WORK'
сервера MS-NET  с  именем 'MAIN'  следует установить
равным '\\MAIN\WORK',  а имя  должно быть равно  'F:'.
Синтаксис задание сетевых директорий может зависеть от конкретных
сетей.
     
      может  быть  потребован  сетью  для  того,  чтобы
получить доступ к заданному ресурсу. Если пароль вообще не нужен,
то в этом параметре следует задать пустую строку.
     
      игнорируется   сетью.   Любое   заданное   здесь
значение будет   возвращено   при  вызове  ,
возможно для использования в прикладной программе.
                                                  
Ошибки (возвращаемые в качестве результата функции)
------
     
     См. .

Примечания
----------
     
     Данная функция также работает  с  Novell  Advanced  NetWare.
Пример см. в NETINFO.PAS.
     
     Хорошая практика      программирования     заключается     в
восстановлении старых установок  при  выходе  из  программы.  Это
возможно благодаря    использованию      при
запуске программы и последующему сбросу всех сделанных  изменений
при помощи    при  завершении  работы  программы.
Отметим, однако,    что    значения        подпрограмма
 не  возвращает,  поэтому для восстановления
ресурса, защищенного паролем,  прикладная программа должна  знать
установленный пароль.
     
     
SetPrinterSetup
-----------------------------------------------------------------
Объявление
----------

     function SetPrinterSetup(SetUpStr : PrinterSetUpStr;
                              RedirIndex : Word) : Boolean;

Параметры
---------
                                                          
     SetUpStr      Новая установочная строка принтера.
     
     RedirIndex    Индекс принтера в таблице переназначений.

     Результат     True, если вызов завершился успешно; иначе False.
     
Описание
--------
     
     Определяет установочную   строку   принтера   для  заданного
устройства  в  таблице   переназначений.   В   случае   успешного
завершения  возвращает  True.  Требует DOS 3.1 и старше,  а также
сеть, совместимую с MS-NET.
     
     Установочная строка принтера посылается перед печатью любого
файла на  заданном принтере сети.  Тем самым разные станции имеют
возможность настраивать  рабочий   режим   принтера   по   своему
усмотрению.
     
      первоначально    устанавливается   при   вызове
 для переназначения порта локального принтера  на
сетевое устройство. Первый переназначенный ресурс получает индекс
0, следующий  получает  индекс  1,   и   т.д.   Если   во   время
переназначения индекс  не был запомнен в программе,  то его можно
выяснить, вызывая   для  каждого  индекса  и
сравнивая полученную информацию с желаемым устройством.
     
     Функция возвращает False в случае слишком старой версии  DOS
или если  не задает переназначенный принтер.

   
ShareInstalled
-----------------------------------------------------------------
Объявление
----------

     function ShareInstalled : Boolean;

Параметры
---------
                                      
     Результат    True, если программа SHARE.EXE инсталлирована;
                  иначе False.

Описание
--------
     
     Возвращает True, если модуль DOS разделения файлов SHARE.EXE
инсталлирован в памяти. Требуется DOS 3.0 или старше.


UnlockDosRec
-----------------------------------------------------------------
Объявление
----------

     function UnlockDosRec(var F; LockPosition,LockLength : LongInt) : Word;

Параметры
---------
     
     F             Отпираемый файл.
     
     LockPosition  Смещение в файле, начиная с которого
                   отпирается файл.
     
     LockLength    Число отпираемых байтов.

     Результат     0 в случае успешного завершения;
                   иначе код ошибки DOS.

Описание
--------
      
     Использует вызов DOS  $5C  для  отпирания  всего  или  части
файла. Требует DOS 3.0 или старше и загрузки программы DOS SHARE.
     
     Параметр   нетипированный,  что  позволяет передачу здесь
любой файловой переменной Turbo Pascal. Вызывающая программа сама
отвечает за   то,   чтобы   переданная  переменная  действительно
являлась файловой переменной.  Файл  при  этом  уже  должен  быть
открыт.
     
      задает  начало  отпираемой   области   файла.
Первый  байт  файла  имеет  позицию 0.   задает число
отпираемых байтов.  При отпирании файла должны быть  использованы
те  же  значения    и  ,  что и при его
запирании. Вы не можете, например, задать:
     
     Status := UnlockDosRec(F, 0, SizOf(F));
     
для того, чтобы убрать сразу все запирания в файле.
                              
Ошибки  (возвращаются в качестве результата функции)
------
     
     См. .
     
Примечания
----------
     
     Перед закрытием  файла  не  забудьте  отпереть  все запертые
места файла. Если этого не сделать, то результаты непредсказуемы.
     

UpdateFile
-----------------------------------------------------------------
Объявление
----------

     function UpdateFile(var F) : Word;

Параметры
---------
                                      
     F           Файл, буфер которого сбрасывается на диск.

     Результат   0 в случае успешного завершения;
                  иначе код ошибки DOS.
     

Описание
--------
                 
     Сбразывает буфер   открытого   файла  на  диск,  обеспечивая
физическое выполнение всех предыдущих операций записи.  Требуется
только DOS   2.0   и   старше.   Используемый   метод  состоит  в
принудительном дублировании логического номера  данного  файла  и
закрытии этого  дубликата.  Исходный же файл после данного вызова
остается открытым.
     
     Параметр  является нетипированным  и  позволяет  передачу
файловой переменной Turbo Pascal любого типа.
Вызывающая программа сама
отвечает за   то,   чтобы   переданная  переменная  действительно
являлась файловой переменной.  Файл  при  этом  уже  должен  быть
открыт на запись.  Если файл это текстовый файл Turbo Pascal,  то
прикладная программа должна сначала  вызвать  процедуру  Flush(),
чтобы гарантировать сброс на диск также и тексовых буферов Turbo.

Ошибки  (возвращаемые в качестве результата функции).
------
                                                     
     См. .

                            
D. Сетевые демонстрационные программы
-------------------------------------
     
     Вместе с   многопользовательской   весией    B-Tree    Filer
поставляются три   демонстрационные   программы.   NETINFO  может
работать в любой системе:  она пытается  определить,  какая  сеть
активна, и  сообщает  информацию о ней.  NSEND и NRECEIVE требуют
двух рабочих  станций,  зарегистрированных  в  сети  NetWare  или
совместимой с  NetBIOS.  NSEND  копирует  файлы  с  одной рабочей
станции на другую, где работает программа NRECEIVE.
     
     Все три  программы  управляются  при  запуске  из  командной
строки. NETINFO принимает командную строку следующего синтаксиса:
     
     NETINFO [опции]
     
     В настоящее  время доступна только одна опция,  /P,  которая
активирует вывод на принтер подробного отчета об инсталлированной
сети NetWare.  NETINFO  различает  следующие сетевые операционные
системы:
     
     NetWare
     
     NetWare с загруженным эмулятором NetBIOS
     
     NetBIOS
     
     PC LAN
     
     Другая система, или система не загружена.
     
     
     Поскольку многие  сети  пытаются  быть   совместимыми   (или
полу-совместимыми) друг  с другом,  весьма вероятно,  что NETINFO
может принять имеющуюся неизвестную сеть за  известную.  Обратите
внимание на  логику,  используемую  функцией  DetermineNetwork  в
NETINFO.PAS для распознавания вашей системе.
     
     NETINFO сообщает    самую    подробную    информацию,   если
обнаруживает NetWare. В этом случае она сообщает:
     
     - имя сервера и номер соединения;
     
     - дата/время сервера;
     
     - доступна ли трассировка транзакций;
     
     - номер соединения рабочей станции;
     
     - дата/время рабочей станции;
     
     - информация о версии NetWare;
     
     - привилегии рабочей станции, широковещательный режим,
       и режим запирания;
     
     - статус сетевого принтера по умолчанию;
     
     - активен ли перехват печати;
     
     - установочные строки сетевых принтеров.
     
     
     Поскольку NetBIOS представляет собой протокол гораздо  более
низкого уровня,  единственная  сообщаемая  в  этом случае NETINFO
информация касается имени машины рабочей станции  и  установочные
строки любых сетевых принтеров.
     
     Во всех  случаях  NETINFO  сообщает  список  переназначенных
устройств, так как эта  функция  может  успешно  вызываться  даже
вообще при отсутствии сети.  (См.  в разделе
9.С, где  приводится  более  подробная   информация   о   сетевых
переназначениях).
     
     NSEND и   NRECEIVE  работают  совместно  и  могут  выполнять
копирование файла с  одной  рабочей  станции  непосредственно  на
другую, не  используя  сервер в качестве промежуточного носителя.
Для посылки сообщений они используют  сервисные  средства  Novell
SPX или  NetBIOS,  в зависимости от того,  что доступно в текущий
момент.
     
     Если доступны средства SPX,  NSEND и NRECEIVE выдают  запрос
на получение  имени  пользователя на другой рабочей станции.  Это
имя транслируется в номер соединения, а затем в межсетевой адрес,
с которым работает SPX.
     
     Если используется NetBIOS, NSEND и NRECEIVE определяют общее
групповое имя   и   затем   пытаются   открыть   сеанс.   Запросы
пользователю здесь не нужны. Каждая программа циклически пытается
установить соединение, так что синхронизация их действий в данном
случае не  критична.  Если  вам  требуется  абортировать любую из
программ до того,  как  установлено  соединение,  просто  нажмите
.
     
     Безотносительно к методу коммуникаций,  передающая программа
запросит имя пересылаемого файла.  Передатчик должен задавать имя
существующего файла. приемник получит копию этого файла в текущей
директории. NRECEIVE  выдаст  предупреждение,  если  копия  может
заменить собой  существующий  файл.  Фактически  передатчик может
использовать символы-шаблоны DOS,  чтобы  задать  группу  файлов;
каждый файл,  подходящий  под данный шаблон,  будет скопирован на
приемник. Файл   копируется    с    передатчика    на    приемник
непосредственно, миную сервер.
     
     NSEND и  NRECEIVE  могут  вызываться  из  командной строки с
заданными им параметрами, которые обеспечивают ряд дополнительных
возможностей:
     
     NSEND [опции] [пересылаемый_файл[пересылаемый_файл]...]
     
     NRECEIVE [опции]
     
     
   Опции
   -----
     
     /?                   Получить список опций.
     
     /B                   Форсировать использование сервисных
                          средств NetBIOS.
                                          
     /W                   Форсировать использование сервисных
                          средств NetWare SPX.
     
     /A                   Автоматически найти приемник
                          (только NetWare).
     
     /Uимя_пользователя   Задать другое имя пользователя
                          (только NetWare).
     
     /V                   Описательный режим: отметить каждый
                          блок сообщения.
     
     /Rчисло_попыток      Задать максимальное число попыток
                          установить соединение (по умолчанию 8).
                                                                
     NSEND позволяет  задавать  в  командной  строке произвольное
число файлов.  Каждое  имя  может  содержать  имена  маршрутов  и
символы-шаблоны DOS.  Перед  копированием  файла  NSEND  посылает
NRECEIVE сообщение с именем копируемого файла.  NRECEIVE отсекает
от него  имя  директории,  если  оно  там  задано,  и  проверяет,
существуетт ли файл с таким именем  в  текущей  директории.  Если
такой файл существует,  NRECEIVE спрашивает у пользователя, можно
ли заменить  его  пересылаемым.  Затем  NRECEIVE  посылает   блок
сообщения с подтверждением назад к NSEND, сообщая ей о том, можно
или нельзя начинать передачу файла.
     
     Опции /B и  /W  применимы  только  к  системам  (таким,  как
NetWare), которые  способны  принимать как вызовы NetWare,  так и
NetBIOS. Опции /A и /U являются  взаимоисключающими.  /A  говорит
NSEND о том,  что найти другую станцию нужно, отправляя сообщение
по каналам всем соединениям и ожидая затем приема ответов; первая
ответившая станция становится мишенью при копировании.  /U служит
вместо запроса  у  пользователя  регистрационного  имени   другой
станции. /V   разрешает   описательный   режим   передачи,  когда
информация о каждом передаваемом блоке или файле отображается  на
мониторе. /R   задает  число  попыток  при  установке  программой
соединения, после которого программа абортируется.
     
     Ниже приводится несколько  примеров  использования  программ
NSEND и NRECEIVE с опциями командной строки:
     
     NSEND /Upete *.PAS *.INC
     NRECEIVE /Ujoe
     
     Джо (joe) посылает все файлы с расширениями PAS и  INC  Питу
(pete) в системе NetWare.
     
     NSEND /A *.PAS *.INC
     NRECEIVE /A
     
     В системе NetWare,  передача выполняется между любыми  двумя
взаимодействующими станциями.
     
     NSEND /V /R20 C:\DOC\NOTICE.TXT
     NRECEIVE
     
     В системе NetBIOS  посылка  C:\DOS\NOTICE.TXT  станции,  где
запущена программа NRECEIVE.  Допускается 20 попыток,  чтобы дать
время приемнику  подготовиться  к   получению,   и   используется
описательный режим,  чтобы  иметь  возможность  наблюдать процесс
пересылки файла в целом.
     
     


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