Удалить A блоков из сегментированного
файла. Номер блока задается в DE.
Возможные ошибки:
62 -
несоответствие числа модифицированных блоков (кэш)
94 -
переполнение блока описателей сегментов (85 сегментов)
102 -
непрерывный файл
103 -
добавить/удалить 0 блоков (A=0)
106 - файл
не открыт
7 - ошибка чтения/записи (драйвер)
Пример из
программы dry.com. Удаление первого блока wet-файла для превращения его обратно
в текстовый:
…
XOR A
LD D,A
LD E,A ;DE=0: номер блока
INC A ;A=1: число блоков
LD C,$fcut
RST 16
RET C
…
Добавить в конец файла DE байт. Если
при этом произойдет увеличение длины файла в блоках, тогда файл должен быть
сегментированным.
Возможные ошибки:
92 - нет
места на диске
94 -
переполнение блока описателей сегментов (85 сегментов)
102 -
непрерывный файл
103 -
добавить/удалить 0 байт (DE=0)
106 - файл
не открыт
А также ошибки 7,20,62
Пример из
программы sv_image.com, копирующей устройство в файл. Если размер файла более
255 блоков, то после его создания приходится в цикле добавлять блоки. В данном
случае по 128 блоков.
…
LD HL,FILE
LD C,$crfil
RST 16
RET C
FADD LD BC,$eadd ;B=число циклов
DEC B
INC B
JR Z,1$
LD DE,#8000 ;128 блоков (D=128)
RST 16
RET C
DJNZ $-2
1$
…
Удалить от конца файла DE байт. Файл
может быть непрерывным.
Возможные ошибки:
103 -
добавить/удалить 0 байт (DE=0)
104 - DE
больше длины файла
106 - файл
не открыт
А также ошибки 7,20,62
Пример окончания программы is_ibm.com:
…
LD DE,(SHIFT+1)
;DE=смещение
в выходном буфере=число байт, которые надо добавить в конец файла.
LD A,E
OR D
JR Z,FLUSH
;Добавим
и запишем весь буфер:
LD HL,(OBUFSZ+1)
DEC HL
LD (SHIFT+1),HL
CALL PRINT
RET C
;Удалим
всё лишнее: DE=(SHIFT+1)
LD HL,(OBUFSZ+1)
XOR A
SBC HL,DE
EX DE,HL
LD C,$ecut ;отрезать DE байт
RST 16
RET C
FLUSH LD C,$flush ;выгрузка на диск
RST 16
RET C
EXIT XOR A
LD A,#F4 ;перепечатка экрана
RET ;выход в
iS-DOS
Подать в регистрах:
HL'= номер
0-го блока текущего каталога (байты 19,20 описателя каталога или bkfcb+51,+52),
BC'=номер
0-го блока старшего каталога (байты 12,13 описателя каталога или bkfcb+44,+45),
D'=
уровень вложенности текущего каталога (байт 16 описателя каталога или
bkfcb+48),
E'=
количество файлов в каталоге включая удаленные и сам каталог (байт 21 описателя
каталога или bkfcb+53).
Флаг C
сохраняется и признаком ошибки не является.
Вот так выглядит начало программы mkdir.com
(mkdir.res). Поскольку панели не в состоянии правильно
отобразить каталоги с уровнем вложенности более шести (точки не поместятся), в
программу встроен следующий ограничитель:
ORG 25000
LD C,$g_cat
RST 16
EXX
LD A,D ;уровень вложенности
CP 6
;Сбросить
флаг Z, дабы выйти в iS-DOS без приключений:
INC A ;NZ
RET NC ;если >6, то выход
…
Открыть файл по имени. Почти то же,
что и $fopen, но не открывает каталог, если файл оказывается таковым. Вход:
HL - 11 байт имени и расширения файла.
Выход: HL'
- 32-байтовый системный описатель файла,
A=номер найденного файла.
Возможные ошибки:
81 - файл
не найден
85 -
ломаный блок описателя сегментов (текущего или искомого каталога)
86 -
ломаный каталог
7 - ошибка чтения/записи (драйвер)
См. примеры из
программ calc.com ($opnum(#26)) и tree.com ($rpart(#29)).
Установить регистр HL' на адрес
системного описателя файла и каталога (см. ПРИЛОЖЕНИЕ 9). Флаг C не
изменяется.
В качестве примера - начало резидента
calc.res:
DEFS 4 ;стандартное
начало резидентов - адреса точек входа:
;0. инициализации (вызывается после перемещения
резидента программой set.com.
;Если 0, то не вызывается.
;2. Рабочая точка входа. Если 0, то с 4-го байта.
LD C,$bkfcb
RST 16
EXX
LD IX,-1 ;здесь будет сумма
LD BC,14
ADD HL,BC
LD A,(HL) ;DEA = длина файла
INC HL
LD E,(HL)
INC HL
LD D,(HL)
LD C,10
ADD HL,BC ;адрес контрольной суммы
LD B,A
LD C,$qrvbl
OR A
JR NZ,$+3
L1 DEC
DE ;следующий (предущий) блок
RST 16 ;читаем блок в кэш
RET C
…
См. также пример к
рестарту $fopen(#25) (unicolor.com).
Сохраняет значения текущего
устройства, каталога и файла в 4-х байтах. Если на входе A=0, то заполняются 4
байта по адресу в IX, иначе - в канале номер A.
Возможные ошибки: (если A<>0)
124 -
испорчена область каналов
125 - нет
канала
Пример с
каналом из программы exebat.com. При запуске программа создает канал, в котором
сохраняет среду (устройство, каталог, файл) рабочего batch-файла, а также
указатель в нем и ссылку на предыдущий batch-канал.
…
LD DE,9 ;длина канала, байт
LD C,$newch ;создать канал
RST 16
RET C
EXX
PUSH AF ;номер канала
PUSH HL ;адрес тела канала
POP IX
CALL KETTE ;A=(g_com-1) - номер
LD (IX+4),A ;bat-файла в цепочке
XOR A
LD (IX+chr),A ;смещение в блоке
LD (IX+blk),A ;номер блока
POP AF ;номер канала
LD
(HL),A
; и,
наконец, сохраняем среду в канале:
LD C,$p_sta
RST 16
RET C
…
См. также пример к
рестарту $w_part(#2A) (date.com)
Устанавливает среду по 4-байтовому вектору:
0 - устройство
1,2 - каталог
3 - файл
Если на входе A=0, то берутся 4 байта по адресу в IX,
иначе - из канала номер A.
Возможные ошибки:
121 - нет устройства
86 - каталог не открывается
80 - номер файла слишком велик
124 - испорчена область каналов
125 - нет канала
7 - ошибка чтения/записи (драйвер)
Пример из
программы date.com. Восстановление среды на выходе из программы. Причем не
только текущей, но и среды для рестарта $fmrst(#41), т.к. с его помощью
восстанавливает среду exebat.com:
…
LD C,$flush ;выгрузка на диск
RST
16
RET C
LD IX,curID ;4 байта, в которых
мы сохранили текущую среду в начале работы
XOR A
LD C,$g_stat
RST
16
RET C
;копируем
среду curID в системный вектор:
LD C,$g_com ;#45
RST 16
EXX
LD HL,curID
LD BC,4
LDIR
RET
См. также пример к рестарту $w_part(#2A) date.com
Найти A свободных блоков подряд на
текущем устройстве и занять их.
Выход:
BC'= номер начального блока найденной области.
Возможные ошибки:
92 - нет
места на диске
162 -
занять 0 блоков (A=0)
А также ошибки кэша и драйвера.
Пример
преобразования непрерывного файла в сегментированный из программы rename.com.
Для этого надо занять на диске 1 блок, и сделать в нем описатель сегментов
файла.
$FLIP LD C,$bkfcb ;#35
RST 16
EXX
LD BC,#B
ADD HL,BC
BIT 6,(HL)
JR Z,S_C ;обратное преобразование
LD A,1 ;число
блоков
LD C,$distr
RST 16
RET C
;У
каталогов старший байт длины обнулять
BIT 5,(HL) ;NZ-каталог, Z-файл
INC HL
INC HL
INC HL
LD A,(HL)
INC HL
LD E,(HL)
INC HL
LD D,(HL)
JR Z,$+4
LD D,0 ;каталог
;Округление
длины файла до блока:
OR A
JR Z,$+3
INC DE
LD (FLENG+1),DE
INC HL
LD E,(HL)
INC HL
LD D,(HL)
LD (FSDBN+1),DE ;начало файла
;Прочитаем
этот блок в кэш:
EXX
PUSH BC ;номер блока
LD D,B
LD E,C ; DE=BC
LD C,$quard
RST 16
POP IX
RET C
…
Единственный рестарт в этом уровне, не
имеющий никакого отношения к файловой службе. Просто в свое время он не
поместился в 0-ой уровень DOS. Рестарт перенастраивает резидент (драйвер) на
новый адрес после перемещения последнего. Пользуется этим рестартом вроде бы
только программа set.com при установке и снятии резидентов и драйверов.
Вход: BC=длина,
HL=старый адрес,
DE=новый адрес.
Создание файла. То же что и
$crfil(#23), но без проверки на существование файла с такими же именем и
расширение, что позволяет ускорить процесс копирования файлов и не проверять
наличие двойников файла дважды в копировщиках copy.com, filecopy, from_trd
и т.п.
Возможные ошибки:
84 -
переполнение каталога (128 файлов)
85 -
ломаный блок описателя сегмента каталога
92 - на
диске нет места
105 -
каталог непрерывен и заполнен до краев.
А также любые ошибки кэша и драйвера.
Пример из
программы treecat.com. Старый файл treecat.txt в главном каталоге удаляется, а
по сему незачем еще раз искать его при создании:
…
LD HL,FILE
LD C,$erfil ;удалить старый файл
RST 16
RET C
PUSH HL
LD HL,(PTR+1)
LD (HL),3 ;код 3 в конец файла
INC HL
LD DE,BUFF ;буфер с текстом
PUSH DE
POP IX
SBC HL,DE
LD (FLENG),HL ;длина файла
EX DE,HL
POP HL ; FILE
LD C,$crf__ ;создать новый файл
RST
16
RET C
;записать
в него текст из буфера (файл открыт)
XOR A
SBC HL,HL
LD C,$wpart
RST 16
RET C
…
FILE DEFM "treecat txt"
DEFB #41
DEFW 0
FLENG DEFW 0
DEFS 14
DATE DEFW 0
…
Удаление открытого файла. Иногда
бывает удобно. Действительно, зачем искать по имени файл, чтобы удалить его
рестартом $erfil(#24), если файл уже и так открыт?
Возможные ошибки:
89 - файл
защищен от удаления
85 -
неверный блок описателя сегментов
93 -
попытка освободить блоки за концом устройства
А также ошибки кэша и драйвера.
Вот как выглядит упрощенный вариант начала программы
delete.com в той части, которая удаляет файл, указанный как параметр:
;Обработка командной строки:
START LD C,$opcat ;#43
RST 16
JR NZ,OPEX ;конец строки
OR A
JR NZ,START ;ключ игнорируем
;A=0:Файл.
Командный режим:
EXX ;в HL - описатель файла
LD C,$find ;ищем этот файл
RST 16
JR NC,ER__F
;ошибка
поиска:
CP 81 ;нет файла
SCF
RET NZ ;другая ошибка
JR FILEX ;нормальный
выход
;удаляем
найденый файл:
ER__F LD C,$erf__
RST 16
RET C
LD C,$flush ;выгрузка на
диск
RST
16
RET C
;восстановить
среду до вызова $opcat:
FILEX LD C,$fmrst ;#41
RST 16
XOR A
LD A,#F4 ;перерисовать экран
RET ;выход
OPEX
;Интерактивный режим
…
Чтение одного блока открытого файла в
буфер по адресу в HL. В DE - номер блока. Блок читается через кэш. Рестарт
используется текстовым редактором, вьюером и программой печати текстовых
файлов.
Возможные ошибки:
101 -
попытка чтения за концом файла (т.е. DE больше длины файла в блоках-1).
106 - файл
не открыт
7 - ошибка чтения/записи (драйвер)
Запись одного блока открытого файла из
буфера по адресу в HL. В DE - номер блока. Блок пишется через кэш. Рестарт
используется текстовым редактором, вьюером и программой печати текстовых
файлов.
Возможные ошибки:
101 -
попытка записи за концом файла (т.е. DE больше длины файла в блоках-1).
106 - файл
не открыт
А также ошибки кэша и
драйвера.
Освободить A блоков на текущем
устройстве, начиная с DE-го. Парный к рестарту $distr(#38).
Возможные ошибки:
93 -
освободить блоки за концом устройства (DE+A больше размера диска)
163 -
освободить 0 блоков (A=0)
А также ошибки кэша и драйвера.
Пример из
программы is_gens.com. Под конец работы программа пытается сделать выходной
файл непрерывным. Заметим, что он однозначно сегментированный ибо создается
таковым. Поэтому здесь нет проверки на сегментированность.
CONTIG
;Прочитаем блок описатель сегментов файла:
LD C,$bkfcb
RST 16
EXX
LD BC,17
ADD HL,BC
LD E,(HL)
INC HL
LD D,(HL)
LD C,$quard
RST 16
RET C
EXX ;DE'=(FSDBN),
HL'=FSDBN+1
LD A,(HL) ;число сегментов
INC HL
LD E,(HL)
INC HL
LD D,(HL)
DEC A ;A=число сегментов=1?
JR NZ,1$
;1
сегмент: освобождаем блок-описатель:
PUSH DE ;первый блок файла
EXX ;DE=(FSDBN)
LD A,1 ;число блоков
LD C,$free
RST 16
POP DE ;первый блок файла
RET C
LD (HL),D
DEC HL
LD (HL),E
;поднимем
бит непрерывности:
LD BC,-6
ADD HL,BC
SET 6,(HL)
1$
…