Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

книги из ГПНТБ / Система математического обеспечения ЕС ЭВМ

..pdf
Скачиваний:
24
Добавлен:
22.10.2023
Размер:
10.92 Mб
Скачать

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

Все последующие макрокоманды ввода-вывода в программе, относящиеся к набору данных, для которого был открыт блок уп­ равления данными, ссылаются на этот блок управления данными.

Во время выполнения операций ввода-вывода могут возникать ошибки ввода-вывода. Управляющая программа ОС ЕС анализи­ рует эти ошибки и, если имеется возможность их коррекции, пред­ принимает необходимые действия, обычно путем повторения опе­ раций ввода-вывода. Если коррекция не удается, ошибка иденти­ фицируется как постоянная ошибка ввода-вывода. При такой ошибке управляющая программа выполняет действия, которые по-разному управляются программистом в зависимости от исполь­ зуемого метода доступа. Независимо от используемого метода до­ ступа программист может предусмотреть в своей программе при обнаружении управляющей программой постоянных ошибок вво­ да-вывода выход на некоторую подпрограмму для анализа этой ошибки. Адрес такой подпрограммы задается в операнде SYNAD макрокоманды DCB или непосредственно помещается в блок уп­ равления данными. Управляющая программа предоставляет в рас­ поряжение программиста для анализа ошибки специальную мак­ рокоманду SYNADAF, результат анализа может быть сообщен в виде распечатки.

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

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

151

ски передает управление по адресу, указанному в поле DCBEODAD блока управления данными. Адрес может быть поме­ щен в блок управления данными с помощью операнда EODAD макрокоманды DCB или непосредственно засылкой.

Например:

C 1K L

E N D

I N D C B

A R E A

O P E N

( I N D C B )

G E T

I N D C B , A R E A

В '

C I K L

C L O S E

( I N D C B )

Щ • »

 

D C B

D S O R G = P S , M A C R F = ( G M ) , D D N A M E = H A K O P ,

D S

E O D A D = E N D

C L 8 0

В этом примере предусмотрено открытие блока управления данными INDCB, считывание набора данных, описанного в операн­ де DD с именем НАКОР и логически связанного с блоком управ­ ления данными INDCB. Каждая логическая запись набора данных пересылается в область AREA и там обрабатывается, после чего запрашивается следующая запись и т. д. Цикл замкнут, выход из него осуществляется управляющей программой по окончании входного набора данных, при этом управление передается по мет­ ке END.

После завершения обработки набора данных программист вы­ полняет процедуру закрытия блока управления данными с помо­ щью макрокоманды CLOSE. При закрытии блок управления дан­

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

же вид,

который он имел

до

открытия,

т. е. разрушается его логическая связь с определенным

набором

данных. После закрытия он может использоваться

для

обслужи­

вания другого набора

данных.

 

 

 

Во время выполнения процедуры закрытия блока управления

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

его состояния, осуществляются

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

Если программист не выдает в своей программе макрокоман­ ды CLOSE, она автоматически выдается управляющей програм­ мой по завершении шага задания.

Имеется специальный вариант закрытия блока управления данными, который выполняется только в том случае, когда в мак­ рокоманде указан операнд TYPE = T. Этот вариант может быть за­ прошен только при использовании базисного последовательного метода доступа. В этом варианте процедура закрытия блока уп­ равления данными используется лишь для подвода начала перво­ го или конца последнего блока набора данных на магнитной ленте

152

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

Выдав один раз макрокоманду CLOSE, можно закрыть не­ сколько блоков управления данными одновременно, при этом преимущества и недостатки те же, что и при аналогичном исполь­ зовании макрокоманды OPEN.

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

Например:

/ / М А К D D

//DD

//DD

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

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

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

153

мой, после чего управление передается по метке END (см. EODAD в макрокоманде DCB) и выполняется закрытие всех блоков уп­ равления данными. В примере содержится фиктивная секция SEK.T для иллюстрации использования фиктивных секций.

 

O P E N

C 1K L

G E T

 

P U T

 

U S I N G

 

' M V C

 

M V C

 

В

 

E N D

C L O S E

A H A L

S Y N A D A F

 

S T

 

 

L R

 

 

P U T

 

 

S Y N A D R L S

 

L

 

 

R E T U R N

I N D C B

D C B

 

O U T D C B

D C B

 

E R R D C B

D C B

 

A R E A

D S

 

 

D S

 

S A V E

D S

 

S E K T

D S E C T

A

D S

 

A1

D S

 

A 2

D S

 

 

• •

 

6.3.

Б У Ф Е Р

( I N D C B , , O U T D C B , ( O U T P U T ) , E R R D C B ( O U T P U T ) ) I N D C B , A R E A

O U T D C B

S E K T , 1

A l , A R E A + 7 0

A 2, A R E A

C I K L

( I N D C B , , O U T D C B , . E R R D C B )

A C S M E T H = Q S A M 14, S A V E

0,1

E R R D C B , (0)

14, S A V E

D S O R G = P S , M A C R F = ( G M ) , D D N A M E = M A K 1 , E O D A D = E N D , S Y N A D = A H A L ,

R E C F M = F , B L K S I Z E = 8 0

D S O R G = P S , M A C R F = ( P L ) , D D N A M E = M A K 2 D S O R G = P S , D D N A M E = M A K 3 , M A C R F = ( P M ) C L 8 0

OF

F

0C L 8 0 CLIO

C L 70

И Б У Ф Е Р Н Ы Й П У Л

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

ферами:

управление буферами с привлечением

для этого

средств

 

 

 

управляющей

программы

и

уп­

Ьлон управление буферный пулон

равление без привлечения средств

буфера

буферов

буфера

управляющей

программы. Пер­

 

Число

Длина

 

 

 

 

 

 

 

 

 

 

вый способ управления буферами

 

Адрес следующего

предполагает

описание их в бло­

 

буфера

ке управления

данными.

Буфер­

 

 

 

 

Адрес следующего

ный пул представляет собой сово­

 

буфера

купность

связанных

в цепочку

 

нули

 

блока управления

буферным

пу­

 

 

лом и буферов

(рис. 26).

 

 

 

 

 

 

 

 

 

 

Блок

управления

буферным

Р и с . 26. С т р у к т у р а

б у ф е р н о г о п у л а

пулом содержит

информацию

о

154

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

6.4. П О С Т Р О Е Н И Е Б У Ф Е Р Н О Г О П У Л А

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

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

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

2. Если информация о числе и длине буферов для работы с не­ которым набором данных есть результат работы программы, то для построения буферного пула можно использовать макрокоман­ ду GETPOOL, которая сама осуществляет запрос на необходимый объем памяти и формирует буферный пул. Таким образом постро­ енный буферный пул может использоваться только для одного набора данных. После закрытия блока управления данными этого набора для освобождения памяти из-под буферного пула необхо­ димо выдать макрокоманду FREEPOOL.

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

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

Рассмотрим примеры построения буферного пула. Первый при­ мер иллюстрирует построение буферного пула с помощью макро­ команды BUILD.

Макрокоманда BUILD строит буферный пул в области PUL. Пул содержит 10 буферов длиной 80 байтов каждый. Запрошенный буферный пул используется двумя наборами данных: входным

(имя DCB—INDCB) и выходным (имя DCB—OUTDCB), причем первому требуются три буфера, а второму — семь буферов. В обе­

155

их макрокомандах DCB задан один и тот же адрес блока управ­ ления буферным пулом.

E N D

I N D C B

O U T D C B

P U L

B U I L D

O P E N

C L O S E

R E T U R N D C B

D C B

C N O P

D S

P U L , 10, 80

( I N D C B , , O U T D C B , ( O U T P U T ) )

( I N D C B , , O U T D C B )

D S O R G = P S , M A C R F = ( G L ) . B U F N O = 3 , B U F C B = P U L , E O D A D = E N D

D S O R G = P S , M A C R F = ( P M ) , B U F N O = 7 , B U F C B = P U L 0,8

C L 8 2 0

Второй пример иллюстрирует построение буферного пула с помощью макрокоманды GETPOOL. Две макрокоманды GETPOOL строят два буферных пула. Первая — для входного набора данных (имя DCB—INDCB), буферный пул содержит пять буфе­ ров длиной 80 байтов. Вторая — для выходного набора данных (имя DCB—OUTDCB), буферный пул содержит три буфера дли­ ной 120 байтов. После закрытия блоков управления данными па­ мять из-под буферных пулов освобождается . с помощью макро­ команд FREEPOOL.

 

G E T P O O L I N D C B , 5, 80

 

G E T P O O L O U T D C B , 3 , 1 2 0

 

O P E N

( I N D C B , , O U T D C B , ( O U T P U T ) )

E N D

C L O S E

( I N D C B , , O U T D C B )

F R E E P O O L I N D C B

F R E E P O O L O U T D C B

R E T U R N I N D C B D C B

O U T D C B D C B

D S O R G = P S , M A C R F =* ( G L ) , B F A L N = F , R E C F M E O D A D = E N D , B L K S I Z E = 8 0

D S O R G = P S , M A C R F = ( P M ) , L R E C L = 40, B L K S I Z E = 120, R E C F M = F B

6.5. У П Р А В Л Е Н И Е Б У Ф Е Р А М И

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

Методы доступа с очередями предусматривают два способа уп­ равления буферами — простую и обменную буферизацию. Оба способа применимы только в последовательном методе доступа с очередями. При работе с индексно-последовательным методом доступа с очередями применима только простая буферизация.

166

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

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

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

Базисные методы доступа предусматривают три способа управ­ ления буферами. Программист может самостоятельно отвести бу­ фер в своей программе и указать его адрес в макрокомандах READ или WRITE, тем самым освобождая управляющую про­ грамму от управления буферами. Кроме этого, он может исполь­ зовать либо непосредственное, либо динамическое управление бу­ ферами. Непосредственное управление буферами осуществляется с помощью макрокоманд GETBUF и FREEBUF. С помощью пер­ вой из них получается буфер из буферного пула, а с помощью вто­ рой — буфер возвращается в- буферный пул.

Динамическое управление буферами может применяться толь­ ко при использовании базисного индексно-последовательного или базисного прямого метода доступа. Этот способ управления буфе­ рами состоит в том, что управляющая программа сама выделяет буферы из буферного пула для макрокоманды READ. При запро­ се динамической буферизации всегда предполагается автоматиче­ ское построение буферного пула. Если с помощью последующей макрокоманды WRITE производится обновление записей того же набора данных, то после выполнения WRITE буфер автоматически возвращается в буферный пул. При работе с индексно-последова­ тельными наборами данных каждая последующая макрокоманда READ вызывает возврат буфера в буферный пул. В остальных случаях для возврата буфера в буферный пул можно использовать макрокоманду FREEDBUF. Если в программе выдается только мак­ рокоманда WRITE, динамическая буферизация не может быть ис­ пользована. I

157

6.6.

Р А Б О Т А С П О С Л Е Д О В А Т Е Л Ь Н Ы М И

Н А Б О Р А М И Д А Н Н Ы Х

Для работы

с последовательными наборами данных можно

использовать последовательный метод доступа с очередями и ба­ зисный последовательный метод доступа.

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

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

Программист должен выбрать только режим обработки за­ писей.

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

В режиме указания запись не перемещается, после макрокоман­ ды GET в регистре 1 выдается адрес этой логической записи во входном буфере, после макрокоманды PUT в регистре 1 выдается адрес в буфере для вывода, куда можно поместить логическую запись. При обработке сегментированных записей в режиме ука-< зания единицей обработки одной макрокоманды GET или PUT является сегмент логической записи. Если же программист обес­ печит построение своей области для всей логической записи, задав в макрокоманде DCB или операторе DD параметр BFTEK=A или выдав в программе макрокоманду BUILDRCD, то единицей рабо-. ты макрокоманды GET или PUT станет вся логическая запись.

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

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

158

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

Базисный последовательный метод доступа обеспечивает боль­ шую гибкость при работе с последовательным набором данных, но налагает на программиста больше обязанностей по программиро­ ванию ввода-вывода. Этот метод доступа предусматривает обмен с программой пользователя физическими записями. При его ис­ пользовании программист должен заниматься управлением буфе­ рами, объединением логических записей в блоки или выделением их из блоков, сегментированием логических записей, добиваться совмещения обработки записей с их вводом или выводом, следить за завершением операций ввода-вывода. Макрокоманды READ и ■WRITE только инициируют операции ввода-вывода. Для осущест­ вления контроля за завершением этих операций обычно использу­ ется макрокоманда CHECK.

Чтобы

добиться совмещения обработки

записей

с их вводом,

нужно иметь возможность выдавать подряд

несколько

макро­

команд READ, не ожидая завершения операций ввода, инициируе­

мых ими.

Для этого программист должен

использовать операнд

NCP макрокоманды DCB или параметр NCP оператора DD. Этот

параметр

определяет число макрокоманд

READ,

которые

можно выдать без промежуточных макрокоманд

CHECK. При

этом необходимо также следить за соотношением параметра NCP

и числа буферов.

 

 

 

 

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

Рассмотрим пример использования базисного последовательно­ го метода доступа для построения последовательного набора дан­ ных из 800 записей. Набор содержит записи фиксированной дли­ ны, длина каждой записи 120 байтов.

Описание набора данных содержится в макрокоманде DCB. Если во время создания набора данных обнаруживается постоян­ ная ошибка вывода, управление получает подпрограмма ANAL, которая выдает макрокоманду ABEND для прекращения выпол­ нения программы. При этом выдается дамп памяти. Формирова­ ние набора данных осуществляется с помощью макрокоманды WRITE, которая ссылается на имя блока управления данными,

159

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

 

O P E N

 

L A

C I K L

W R I T E

 

C H E C K

 

B C T

 

C L O S E

A H A L

M V I '

 

В

D A M P

S R

 

IC

 

A B E N D

I N D

D C

B U F

D C

O U T D C B

D C B

( O U T D C B , ( O U T P U T ) ) 5,800

B L O K , S F , O U T D C B , B U F

B L O K 5, C I K L

( O U T D C B )

I N D , X ’l l ’

D A M P

L 1

I, I N D

( 1 ) , D U M P

X ’00'

2 0 С Д А Н Н Ы Е ’

D S O R G = P S , M A C R F = W ,

B L K S I Z E = 120, R E C F M = 1F, S Y N A D = A H A L

6.7. С Т Р У К Т У Р А Б И Б Л И О Т Е Ч Н О Г О Н А Б О Р А Д А Н Н Ы Х

Набор данных с библиотечной организацией (или просто биб­ лиотека) состоит из последовательно организованных разделов, каждый из которых имеет свое имя. Кроме того, библиотека содер­ жит оглавление, которое размещается в начале набора данных.

Оглавление библиотеки имеет последовательную структуру. Оно представляет собой совокупность блоков с ключами. Длина ключа 8 байтов, длина поля данных 256 байтов. Оглавление соз­ дается в момент выделения внешней памяти под библиотеку. Ме­ сто под оглавление запрашивается в параметре SPACE оператора DD, описывающего библиотеку, причем запрос делается путем указания числа блоков оглавления.

Каждый блок оглавления содержит один или несколько эле­ ментов разделов библиотеки. Максимальный размер элемента оглавления 74 байта, минимальный— 12 байтов. Элемент каждого раздела библиотеки включает его имя и относительный адрес внутри библиотеки. Элемент раздела библиотеки может также со­ держать относительные адреса некоторых внутренних точек разде­ ла. Таким образом, через оглавление можно найти адрес любого раздела библиотеки и даже некоторой точки внутри определенно­ го раздела, с которой можно начать обработку раздела.

Элементы оглавления упорядочены в алфавитном порядке. Ключ каждого блока оглавления есть имя раздела из последнего элемента этого блока. Ключ последнего использованного блока оглавления равен FF.

160

Соседние файлы в папке книги из ГПНТБ