Пакет документации о рестартах iS-DOS 1969 г.

Рестарты - DUD.SYS (#20...#2F).



ФАЙЛОВАЯ СЛУЖБА (DUD.SYS)

Для начала о структуре блочного устройства в iS-DOS'е. Любое блочное устройство (дискета, электронный диск или винчестер) с точки зрения iS-DOS'а представляет собой набор блоков размером в 256 байт и нумерующихся от 0 до 65535. Заголовок устройства содержится в 0-ом блоке. Подробно структура 0-го блока приводилась ранее при описании рестарта $binit(#0F), сейчас же повторим лишь следующее:

10(3)* "DSK": признак iS-DOS

18(2) Размер устройства в блоках

20(2) Номер первого блока главного каталога

Подробнее см. ПРИЛОЖЕНИЕ 1.

Размер устройства должен быть кратен 8. Связано это с представлением карты занятых и свободных блоков, в которой каждому блоку устройства соответствует 1 бит. Занятому блоку соответствует 1, свободному - 0. Карта начинается с 1-го блока диска и занимает столько блоков подряд, сколько необходимо для устройства соответствующего размера. Структура карты очень проста: по 1 биту на блок (8 блоков в байте, до 2048 блоков устройства на 1 блок карты), 0-му блоку устройства соответствует 7-ой бит 0-го байта карты, 1-му блоку - 6-ой бит и т.д. На обычном флоппи-диске карта занимает 2 блока. Максимально (на винчестере) карта может занимать 32 блока.

На устройстве должен находиться хотя бы один каталог, т.е. главный. Номер 0-го блока главного каталога указан в 0-ом блоке устройства со смещением 20.

Любой каталог в iS-DOS'е представляет собой файл, содержащий в себе 32-байтовые описатели файлов, первый из которых (0-ой) - это описатель самого каталога. Т.о. в iS-DOS'е у каталогов два описателя: внутренний и внешний. Исключение составляет лишь сам главный каталог, не имеющий внешнего описателя. У двух описателей должны быть одинаковые имена, основную же информацию о каталоге хранит внутренний описатель. Внешний же служит лишь для открывания каталога по имени и печати имени каталога в панели.

Любой файл (и каталог) в iS-DOS'е может быть непрерывным или сегментированным. Непрерывный файл (каталог) занимает на устройстве непрерывную последовательность блоков. Номер начального блока файла указывается в описателе файла со смещением 17. У сегментированных файлов здесь указывается номер блока описателя сегментов. Это специальный блок, имеющий следующую структуру:

0-й байт - число сегментов (от 0 до 85),

следующие 2 байта - номер начального блока 1-го сегмента,

3-й байт - размер сегмента в блоках (от 1 до 255).

Следующие 3 байта описывают следующий сегмент и т.д. (см. ПРИЛОЖЕНИЕ 22)

В iS-DOS'е существуют понятия текущего устройства (их может быть 8, они переключаются рестартом $swblk), текущего каталога (открывается рестартом $open1) и текущего файла.

#20 (32) $open

Этот рестарт открывает устройство и его главный каталог. Для этого считывается 0-й блок устройства и проверяется на наличие признака "DSK" со смещением 10 (13 для новой системы) в нём. Проверяется размер устройства на кратность 8 и неравенство 0. Затем рестарт пытается открыть главный каталог по номеру его начального блока, указанного в том же блоке со смещением 20.

Входных параметров нет. Выходных также. Возможные ошибки:

87 - нет признака "DSK" или неверный размер устройства

86 - каталог не открывается: ошибка в описателе каталога плюс все возможные ошибки драйвера

Пример: выход из программы fileshow. Ожидается нажатие клавиши. Если это <Cs/Ent>, то открывается новое устройство:

LD C,$kwait           ;ждем отпуска клавиш

RST 16

DEC C                  ;ждем нажатия клавиши

RST 16

CP #17                  ;Cs/Enter?

JR NZ,3$

LD C,$clear           ;очистить кэш

RST 16

; очистить буфер драйвера и настроить его на новую дискету:

LD C,$binit

RST 16

RET C

LD C,$open           ;открыть устройство

RST 16

RET C

;и, наконец, выход с перерисовкой экрана

3$          XOR A

LD A,#F4

RET

#21 (33) $open1

Открыть каталог. На входе в регистре DE подается номер начального блока каталога. Выходных параметров нет. Возможна ошибка с номером 86 (см. предыдущий рестарт). Считывается 0-й блок каталога и проверяется: байты 8..10 должны быть пробелами, в 11-ом байте 0-ой и 5-ый биты должны быть в 1, 19-й и 20-й байты должны содержать номер 0-го блока. При любом несоответствии получим ошибку 86.

Возможные ошибки:

81 - файл не найден

85 - ломаный блок описателя сегментов (текущего или искомого каталога)

86 - ломаный каталог

В качестве примера рассмотрим как программа coca.com открывает устройство и каталог альтернативной панели:

;достанем системный вектор оболочки (см. ПРИЛОЖЕНИЕ 17)

LD C,$gmpan               ;#87

RST 16

EXX

DEC BC

LD A,(BC)                    ;номер текущей панели

INC BC

OR A

JR NZ,$+3

INC BC

LD A,(BC)                    ;канал альтернативной панели

LD C,$stchn

RST 16

RET C

EXX

;HL=адрес тела канала альтернативной панели (см. ПРИЛОЖЕНИЕ 18)

LD B,(HL)                   ;номер устройства

INC HL

LD E,(HL)

INC HL

LD D,(HL)

; DE= номер 0-го блока каталога

LD C,$swblk

RST 16

RET C

LD C,$open1

RST 16

RET C

#23 (35) $crfil

Создать файл в текущем каталоге на текущем устройстве. В HL - адрес 32-байтового описателя файла. В нем необходимо указать имя, расширение файла, байт состояния (если непрерывный - 6-ой бит =1). Старший байт длины обнуляется, т.о. создать можно файл длиной не более 255 блоков (65280 байт). Если Вам требуется создать файл большей длины, пользуйтесь дополнительно рестартом $fadd(#2F) или $eadd(#31). После создания файл будет открыт. Следует помнить, что сей рестарт, равно как и большинство рестартов этого уровня работает через кэш. Поэтому:

1. Всегда следите за сохранностью кэша;

2. Так как результат действий рестарта будет также в кэше в виде модифицированных блоков, не забудьте по окончании работы программы сохранить эти модифицированные блоки на устройстве с помощью рестарта $flush(#02).

Возможные ошибки:

82 - файл с таким именем и типом уже существует

84 - переполнение каталога (128 файлов)

92 - на диске нет места

105 - каталог непрерывен и заполнен до краев.

А также любые ошибки кэша и драйвера.

Для примера предлагается кусок из программы move.com:

;Открыть выходной каталог:

CALL G_DEST

RET C

SBC HL,HL

LD (FLEN),HL          ;Обнулить длину

LD HL,FSTAT

SET 6,(HL)             ;Непрерывный файл

LD HL,FILE

LD C,$crfil

RST 16

RET C

;Копируем описатель файла:

EXX

EX DE,HL

LD HL,FILE+32

LD BC,32

LDIR

LD C,$putf               ;и сохраняем его

RST 16

RET C

FILE         EQU $

FSTAT    EQU FILE+11

FLEN     EQU FILE+14

#24 (36) $erfil

Найти файл по имени и уничтожить. Если файл не найден, не докладывать. В регистре HL подается адрес 11-байтового описателя: 8 байт имени и 3 байта расширения.

Возможные ошибки:

89 - файл защищен от удаления

85 - неверный блок описателя сегментов

93 - попытка освободить блоки за концом устройства

Пример из программы sv_image.com:

;текущая дата для создаваемого файла:

LD C,$g_com         ;#45

RST 16

EXX

DEC HL

DEC HL

LD D,(HL)

DEC HL

LD E,(HL)

LD (DATE),DE

;в зависимости от ключа: удалять или нет:

LD HL,FILE

OPTION  LD A,0

OR A

LD C,$erfil

CALL NZ,16

RET C

DEC C              ;$crfil

RST 16

RET C

#25 (37) $fopen

Найти и открыть файл по имени и расширению. В HL на входе подается адрес 11-байтового описателя файла. Если найденный файл - каталог, то он открывается.

Выход (если без ошибок, т.е. флаг C сброшен), то в регистре A:

#00 - открыт файл;

#20 - открыт каталог;

HL' - адрес системного 32-байтового описателя файла (этот адрес можно получить с помощью рестарта $bkfcb(#35)).

Возможные ошибки:

81 - файл не найден

85 - ломаный блок описателя сегментов (текущего или искомого каталога)

86 - ломаный каталог

Рассмотрим для примера кусочек программы unicolor.com в той части, где программа ищет подкаталог HELP и в нем файл с расширением .hlp:

;Текущий путь для печати его в окне:

LD HL,PATH+8           ;буфер для пути

PUSH HL

LD B,pathSZ              ;длина буфера

;Заполним буфер пробелами

LD (HL)," "

INC HL

DJNZ $-3

POP HL

XOR A

LD DE,56

LD C,$g_way             ;#47

RST 16

RET C

;Ищем конец пути, т.е. первый пробел:

1$          LD A,(HL)

CP " "

INC HL

JR NZ,1$

DEC HL

PUSH HL

;В системном описателе - текущий файл:

LD C,$bkfcb

RST 16

EXX

POP DE

;Перекодируем имя текущего файла в буфер пути:

LD C,$convr

RST 16

RET C

;Попытаемся найти HELP*.hlp

XOR A

LD (hlpCSR+1),A

;Копируем 8 байт имени текущего файла в буфер имени hlp-файла:

LD DE,hlpNAM

PUSH DE

LD BC,8

LDIR

; …и, наконец, пользуемся нашим рестартом fopen. Сперва откроем каталог:

LD HL,HELP

LD C,$fopen

RST 16

POP HL

JR C,GW_EX             ;уходим по ошибке

;а затем им же и файл:

RST 16

JR C,GW_EX

;не отходя далеко от кассы, достанем длину файла:

EXX

LD BC,14

ADD HL,BC

LD E,(HL)

INC HL

LD D,(HL)

hlpNAM  DEFS 8

DEFM "hlp"

HELP     DEFM "HELP"

#26 (38) $opnum

Открыть файл по номеру в регистре A.

На выходе, если все в порядке: A-сохраняется, HL' - адрес системного 32-байтового описателя файла.

Возможные ошибки:

80 - номер файла слишком велик (больше 21-го байта описателя каталога -1)

Пример из программы calc.com. С помощью рестарта $opnum программа открывает файл, на котором стоит курсор:

ORG 24000

;пытаемся открыть параметр:

LD C,$opcat

RST 16

RET C

JR Z,1$

;параметра в строке нет, следовательно, открываем файл под курсором:

LD C,$mwait          ;"Wait Please!"

RST 16

LD C,$g_cur            ;#8A

RST 16

;A=номер файла, на котором стоит курсор. Открываем файл по его номеру в каталоге:

LD C,$opnum

JR 2$

1$          EXX

;открываем параметр по имени:

LD C,$find

2$          RST 16

RET C

EXX

;каталоги не обслуживаем:

LD DE,11

ADD HL,DE

BIT 5,(HL)

RET NZ

LD DE,26-11

ADD HL,DE

;HL указывает на длину файла в его описателе

#27 (39) $gname

Считать в кэш или найти в кэше соответствующий блок каталога и установить регистровую пару HL' на описатель искомого файла в этом блоке.

Вход: E - номер файла.

Файл не открывается, т.е. сохраняется текущий открытый файл.

Возможные ошибки: см. предыдущий рестарт.

Пример из программы univ.res. Цикл подбора файлов, подходящих под маску:

PODBOR

LD DE,#100

1$          INC E                   ;номер файла

LD C,$gname

RST 16

JR C,2$

PUSH DE

EXX

;HL указывает на описатель файла в кэше

LD DE,TRAF         ;трафарет (11 байт)

;сравнение 11 байт по адресам в HL и DE:

LD C,$cpfil            ;#8F

RST 16

POP DE

JR NZ,1$

PUSH DE

CALL WIBCN         ;работа с файлом

POP DE

RET C

JR 1$

;Ошибка. В регистре A ее код:

2$          CP 80                    ;каталог кончился

RET Z

SCF                      ;иначе: что-то серьезное

RET

#28 (40) $putf

Сохранить в текущем каталоге измененный вектор текущего файла (тот, что доступен через $bkfcb(#35)). Полезно для переименования файла и тому подобных операций. Номер файла лежит по адресу bkfcb-1.

Возможные ошибки: ошибки файловые, ошибки кэша и драйвера:

80 - номер файла слишком велик

85 - неверный блок описателя сегментов (ломаный каталог)

7 - ошибка чтения/записи (драйвер)

62 - несоответствие числа модифицированных блоков (кэш)

Вот так выглядит применение этого рестарта на выходе из программы calc:

;в HL - контрольная сумма открытого файла

;в (ADRKK+1) - адрес контрольной суммы в системном описателе файла (bkfcb+26)

ADRKK    LD (0),HL

LD C,$putf

RST 16

RET C

LD C,$flush

RST 16

RET C

XOR A

RET

#29 (41) $rpart

Прочитать DE байт из текущего открытого файла со смещением AHL байт от начала файла по адресу в IX.

Возможные ошибки:

100 - попытка чтения за концом файла (т.е. AHL+DE больше длины файла).

106 - файл не открыт

170 - чтение 0 байт (DE=0)

171 - файл защищен от чтения

7 - ошибка чтения/записи (драйвер)

Пример из программы tree.com. Она открывает главный каталог, находит там файл treecat.txt, проверяет, влезет ли он в буфер под кэш и считывает его:

LD C,$open             ;главный каталог

RST 16

RET C

LD HL,FILE

LD C,$find               ;найти по имени файл

RST 16

RET C

EXX

LD BC,#000F

ADD HL,BC

LD D,(HL)

DEC HL

LD E,(HL)              ;DE=длина файла

LD HL,BUFF

;BUFF - буфер за концом программы

ADD HL,DE

; адрес конца файла в буфере

LD C,$g_cnf            ;#10

RST 16

PUSH DE                ;длина файла

EXX

LD BC,5

ADD HL,BC

LD E,(HL)

INC HL

LD D,(HL)

PUSH DE                ;адрес кэша

EXX

POP DE

EX DE,HL

XOR A

SBC HL,DE

LD A,130

POP DE                  ;длина файла

RET C                   ;не хватает памяти

XOR A

LD L,A

LD H,A                    ;AHL=0

LD IX,BUFF

LD C,$rpart

RST 16

RET C

#2A (42) $wpart

Записать DE байт в текущей открытый файл со смещением AHL байт от начала файла с адреса в IX.

Возможные ошибки:

100 - попытка записи за концом файла (т.е. AHL+DE больше длины файла).

106 - файл не открыт

170 - запись 0 байт (DE=0)

172 - файл защищен от записи

7 - ошибка чтения/записи (драйвер)

62 - несоответствие числа модифицированных блоков (кэш)

Для примера рассмотрим сохранение параметров программой date.com на выходе из программы:

;сохранение текущей среды в буфере curID

LD IX,curID

XOR A

LD C,$p_stat

RST 16

;Достать среду последнего запущенного com-файла, т.е. date.com

LD C,$g_com

RST 16

EXX

LD BC,#FFF7

ADD HL,BC

PUSH HL

POP IX

;открыть файл date.com:

XOR A

LD C,$g_stat

RST 16

RET C

;записать в него 1 байт со смещением 2 из WDCSR:

LD IX,WDCSR

LD DE,1

XOR A

LD HL,2

LD C,$wpart

RST 16

RET C

;сосчитать контрольную сумму date.com

LD HL,CALC

LD C,$run

RST 16

JR NC,0$

;ошибка:

CP 37                 ;нет резидентной задачи?

SCF

RET NZ

0$          LD C,$flush

RST 16

RET C


 

CALC     DEFM "@calc"

DEFB 13

#2B (43) $rifle

Прочитать B блоков открытого файла начиная с DE-го по адресу в HL. Чтение осуществляется мимо кэша, однако следует помнить, что если файл сегментированный, то система сама подчитывает в кэш блок описатель сегментов файла. Т.е. следите, чтобы ваша программа не повредила кэш к тому моменту, когда Вы соберетесь воспользоваться этим рестартом, равно как и большинством рестартов этого уровня системы.

Возможные ошибки:

101 - попытка чтения за концом файла (т.е. DE+B больше длины файла в блоках).

106 - файл не открыт

7 - ошибка чтения/записи (драйвер)

Пример из жизни копировщиков: начало цикла копирования программы image.com:

COPY

;B=размер буфера копирования

PUSH BC

;переключиться на входное устройство:

FROM    LD BC,$swblk

RST 16

POP BC

RET C

;Считать B блоков в буфер BUFF из открытого файла:

LD HL,BUFF

LD C,$rifle

RST 16

RET C

;переключиться на выходное устройство:

PUSH BC

DEST       LD BC,$swblk

RST 16

POP BC

RET C

;Записать B блоков на текущее устройство

LD C,$write

RST 16

RET C

#2C (44) $wifle

Записать B блоков в открытый файл начиная с DE-го с адреса в HL. Запись осуществляется мимо кэша. Посему после использования данного рестарта может возникнуть ситуация несоответсвия блоков в кэше блокам на устройстве, что чревато боком. Исправить дело можно очистив принудительно кэш рестартом $clear(#01) или пересоздав его рестартом $creat(#00).

Возможные ошибки:

101 - попытка чтения за концом файла (т.е. DE+B больше длины файла в блоках).

106 - файл не открыт

7 - ошибка чтения/записи (драйвер)

В качестве примера - кусок программы ibm_is.com:

;Открыть выходной файл:

O_FILE     LD A,0

CALL OPNUM

JR C,0$

EXX

LD BC,15

ADD HL,BC

LD E,(HL)

INC HL

LD D,(HL)

;DE=длина файла в блоках

LD A,(OBUFSZ+2)

LD B,A

;A=B=размер выходного буфера в блоках.

;Добавить в конец файла A блоков:

LD C,$fadd

RST 16

JR C,0$

;Записать B блоков в файл начиная с DE-го блока из буфера O_BUF:

LD C,$wifle

LD HL,O_BUF

RST 16

0$          POP HL

POP DE

POP BC

RET

;Подпрограмма открывает файл по номеру в регистре A.

OPNUM  CP 0

RET Z                   ;файл уже и так открыт

LD (OPNUM+1),A

LD C,$opnum

RST 16

RET

#2D (45) $qrvbl

Прочитать один блок номер DE открытого файла в кэш.

Выход (если все O.K.):

HL' - адрес блока в кэше. (Если блок уже находился в кэше, то считывания с устройства не происходит, рестарт просто находит его и сообщает адрес. Тогда A=1, иначе A=0.)

DE'- адрес описателя блока в кэше. Необходим для рестарта $modo(#2E).

Возможные ошибки:

101 - попытка чтения за концом файла (т.е. AHL+DE больше длины файла).

106 - файл не открыт

170 - чтение 0 байт (DE=0)

171 - файл защищен от чтения

7 - ошибка чтения/записи (драйвер)

Пример: очистка каталога при его создании программой mkdir.com:

LD HL,(FILE+14)

;HL=длина файла-каталога в байтах

LD A,L

OR A

LD A,H

JR NZ,$+3

DEC A

OR A

RET Z

LD B,A

;B=A=число блоков, которые нужно очистить

LD DE,1           ;номер блока

1$          LD C,$qrvbl       ;прочитать блок

RST 16

RET C

EXX

;HL=адрес блока в кэше

XOR A

LD B,A

;256 нулей:

LD (HL),A

INC HL

DJNZ $-2

PUSH DE            ;адрес описателя блока

EXX

POP HL

EX DE,HL

LD C,$modo

RST 16

RET C

EX DE,HL

INC DE               ;номер блока

DJNZ 1$

RET

#2E (46) $modo

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

Вход: DE - адрес описателя блока в кэше. Этот адрес выдается на выходе рестартами $quard(#06) и $qrvbl(#2D). Обычно рестарт $modo используется сразу после этих рестартов. Именно сразу, поскольку блок может сместиться или вообще быть вытеснен из кэша при вызове многих рестартов, считывающих блоки в кэш, например: $open, $open1, $fopen, $find, $rpart, $gname, $opnum, $crfil и др.

Возможные ошибки:

62 - несоответствие числа модифицированных блоков (кэш)

7 - ошибка чтения/записи (драйвер)

Вот что делает программа arzt+.com, когда сдвигает файл is_dos.sys:

;Прочитать 0-ой блок устройства в кэш:

LD DE,0

LD C,$quard

RST 16

RET C

EXX

LD BC,32+17

ADD HL,BC

LD BC,(FR1ST+1)

;BC=номер блока, где после сдвига находится файл is_dos.sys:

LD (HL),C

INC HL

LD (HL),B

;Сосчитаем новую контрольную сумму описателя файла is_dos.sys:

LD BC,31-18

ADD HL,BC

LD B,#20

XOR A

XOR (HL)

DEC HL

DJNZ $-2

;Контрольная сумма также помещается в 0-ом блоке устройства:

DEC HL

DEC HL

DEC HL

DEC HL

LD (HL),A

;И, наконец, модифицируем блок в кэше:

LD C,$modo

RST 16

RET C

#2F (47) $fadd

Добавить A блоков к сегментированному файлу. Добавленные блоки вставляются перед блоком номер DE (первый добавленный блок становится DE-ым). Если DE слишком велик, то добавление все равно производится в конец файла.

Возможные ошибки:

62 - несоответствие числа модифицированных блоков (кэш)

92 - нет места на диске

94 - переполнение блока описателей сегментов (85 сегментов)

102 - непрерывный файл

103 - добавить/удалить 0 блоков (A=0)

106 - файл не открыт

7 - ошибка чтения/записи (драйвер)

Пример из программы wet.com. Добавление специального блока в начало текстового файла и заполнение его вектором:

EXIT       XOR A

LD E,A

LD D,A               ;DE=0: номер блока

INC A                  ;A=1: число блоков

LD C,$fadd

RST 16

RET C

LD HL,BUFF     ;буфер блока

;Очистка буфера:

PUSH HL

XOR A

LD B,A

LD (HL),A

INC HL

DJNZ $-2

LD HL,VECTOR              ;вектор редактора

LD C,VECSZ                    ;размер вектора

LD DE,BUFF+#80+edcsr   ;+смещение

LDIR

POP HL                          ;буфер

LD D,B

LD E,B                             ;DE=0

LD C,$wvblk                     ;записать 1 блок

RST 16

RET C




СОДЕРЖАНИЕ:


  Оставте Ваш отзыв:

  НИК/ИМЯ
  ПОЧТА (шифруется)
  КОД



Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Железо - Из-за чего происходят помехи в модемной связи.
Demo Party - обзор демосцены за 1999 год.
Проходилка - прохождение игры Die Feuerfaust 2.
Дискуссия - Рецензия.
Открытые письма Nemo №4.1

В этот день...   21 ноября