#30 (48) $fcut
Удалить 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
…
#31 (49) $eadd
Добавить в конец файла 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$
…
#32 (50) $ecut
Удалить от конца файла 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
#33 (51) $g_cat
Подать в регистрах:
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, то выход
…
#34 (52) $find
Открыть файл по имени. Почти то же, что и $fopen, но не открывает каталог, если файл оказывается таковым. Вход: HL - 11 байт имени и расширения файла.
Выход: HL' - 32-байтовый системный описатель файла,
A=номер найденного файла.
Возможные ошибки:
81 - файл не найден
85 - ломаный блок описателя сегментов (текущего или искомого каталога)
86 - ломаный каталог
7 - ошибка чтения/записи (драйвер)
См. примеры из программ calc.com ($opnum(#26)) и tree.com ($rpart(#29)).
#35 (53) $bkfcb
Установить регистр 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).
#36 (54) $p_stat
Сохраняет значения текущего устройства, каталога и файла в 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)
#37 (55) $g_stat
Устанавливает среду по 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
#38 (56) $distr
Найти 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
…
#39 (57) $rtran
Единственный рестарт в этом уровне, не имеющий никакого отношения к файловой службе. Просто в свое время он не поместился в 0-ой уровень DOS. Рестарт перенастраивает резидент (драйвер) на новый адрес после перемещения последнего. Пользуется этим рестартом вроде бы только программа set.com при установке и снятии резидентов и драйверов.
Вход: BC=длина,
HL=старый адрес,
DE=новый адрес.
#3B (59) $crf__
Создание файла. То же что и $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
…
#3C (60) $erf__
Удаление открытого файла. Иногда бывает удобно. Действительно, зачем искать по имени файл, чтобы удалить его рестартом $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
;Интерактивный режим
…
#3D (61) $rvblk
Чтение одного блока открытого файла в буфер по адресу в HL. В DE - номер блока. Блок читается через кэш. Рестарт используется текстовым редактором, вьюером и программой печати текстовых файлов.
Возможные ошибки:
101 - попытка чтения за концом файла (т.е. DE больше длины файла в блоках-1).
106 - файл не открыт
7 - ошибка чтения/записи (драйвер)
#3E (62) $wvblk
Запись одного блока открытого файла из буфера по адресу в HL. В DE - номер блока. Блок пишется через кэш. Рестарт используется текстовым редактором, вьюером и программой печати текстовых файлов.
Возможные ошибки:
101 - попытка записи за концом файла (т.е. DE больше длины файла в блоках-1).
106 - файл не открыт
А также ошибки кэша и драйвера.
#3F (63) $free
Освободить 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$
…