Echo
#03
31 марта 1997 |
|
Маленькие хитрости-2 - О корректной обработке Retry/Abort/Ignore в TR-DOS.
┌════════════════════════════════════════┐ │░░░░░ О корректной обработке R/I/A ░░░░░│ └════════════════════════════════════════┘ VfNG/NEW В многих программах людям бывает необ- ходимо перехватить стандартное сообщение DOS об ошибке чтения/записи сектора чтобы открыть свое красивенькое окошко, сделать запрос Retry/Abort/Ignore, получить ответ и правильно продолжить или закончить вы- полнение программы. Далеко не все умеют это делать. Я попробую эту проблему осве- тить. По адресу #3F0A ДОС находится процеду- ра, обеспечивающая запись сектора, а по #3F0E-чтение. Как раз именно этими проце- дурами и осуществляется чтение/запись стандартными функциями. Рассмотрим эти процедуры внимательно: #3F0A LD A,#A0 ;Код команды записи ;сектора JR #3F10 #3F0E LD A,#80 ;Код команды чтения ;сектора #3F10 LD (#5CFE),A LD D,#0A ;число попыток ;чтение/записи #3F15 PUSH DE DI LD A,(#5CFF) INC A OUT (#5F),A ;номер сектора LD HL,(#5D00) ;буфер LD C,#7F ;порт данных LD A,(#5CFE) ;код команды OUT (#1F),A ;вызов команды CP #A0 ;запись? PUSH AF CALL Z,#3FBA ;вызов записи ;сектора POP AF CALL NZ,#3FD5 ;вызов чтения ;сектора POP DE EI IN A,(#1F) ;чтение регистра ;состояния LD B,A AND #7F RET Z ;выход, если нет ;ошибки LD HL,#29D8 ;адрес надписи ;"Read Only" AND #40 ;защита от записи? JR NZ,#3F4B ;да LD A,B AND 4 ;потеря данных? JR Z,#3FA0 ;нет. повторная ;попытка чтения. DEC D ;последняя попытка? JR NZ,#3F15 ;нет, еще одна LD HL,#29E2 ;адрес надписи ;"Disk error" LD A,#D0 OUT #1F,A ;прекращение ко- ;манды, если она ;продолжает выполнятся LD A,B AND 1 JP NZ,#3EE7 ;обработка ;"No disk" IN A,#3F ;чтение регистра ;дорожки OR A ;нулевая? JR NZ,#3F5F ;да IN A,#5F ;чтение регистра ;сектора CP #0A ;десятый? RET Z ;выход, если да #3F5F PUSH HL #3F60 CALL #1D97 ;вызов очистки ;экрана POP HL RST #18 LD HL,#2A13 ;адрес надписи ;"Trk." RST #18 ;вывод IN A,#3F ;чтение регистра ;дорожки CALL #1DA3 ;вывод номера ;дорожки LD HL,#2A18 ;адрес надписи ;"Sec." RST #18 ;вывод IN A,#5F ;чтение регистра ;сектора CALL #1DA3 ;вывод номера ;сектора LD HL,#29FE ;адрес надписи ;"Retry/Abort/Ignore?" RST #18 ;вывод надписи #3F7B CALL #1052 ;процедура #1052 ;возвращает в A ASCII-код нажатой на кла- виатуре клавиши #3F7E CP "I" ;Ignore? RET Z ;возврат, если ;да CP "R" ;Retry? JR Z,#3F94 ;да, выход в ;очередной цикл ;попыток CP "A" ;Abort? JR NZ,#3F7B ;нет, переход на ;чтение клавиа- ;туры #3F89 ;Abort Главное, что можно выделить из нарисо- ванного выше, это то, что в результате ошибки мы попадаем либо в #3F60, либо в #3EE7. Попрубуем рассмотреть #3F60 повни- мательнее. #3F60 CALL #1D97 #1D97 RST #20 DEFB #6B DEFB #0D #0020 JP #2F72 #2F72 LD (#5D02),HL LD (#5D04),DE POP HL LD E,(HL) INC HL LD D,(HL) INC HL PUSH HL LD HL,#3D2F PUSH HL PUSH DE LD HL,#5CC2 PUSH HL LD HL,(#5D02) LD DE,(#5D04) RET Таким образом, при дисковой ошибке, от- личной от "No disk", мы вылетаем в #5CC2. В #5CC2 стандартно торчит RET. Эта точка используется для вызова подпрограмм ПЗУ Бейсика. Два байта в #5CC3 и #5CC4 не ис- пользуются, значит мы законно можем впи- сать в #5CC2 команду из 3-х байт: JP куда- нибудь, например на драйвер обработки. Заметим, что после этого самого JP на стеке будет торчать число #0D6B. Значит, сделаем следующую вещичку: DRIVER EX (SP),HL PUSH AF LD A,H CP #0D JR Z,ERROR POP AF EX (SP),HL RET Догадайтесь сами, что тут произошло. Ну а теперь ERROR POP HL POP HL POP HL POP HL POP HL CALL PROC ;вызов собственной ;процедуры RIA возврат-в A "R","I","A" ;соответственно. LD HL,#3F7E EX (SP),HL JP #3D2F ;возврат в ДОС ;ответа! В простейшем случае CALL PROC заменяет- ся на LD A,"R"/"I"/"A", если ответ на ошибку определен одназначно. Аналогично, хотя и несколько сложнее, обстоит дело с обработкой "No disk" (#3EE7). В этом, а также куда вылетаем по "Abort", разбирайтесь сами, это не сложно сделать.
Другие статьи номера:
Похожие статьи:
В этот день... 21 ноября