;///////////////////////////////////////////////////
;
; DIR. Вывод списка файлов и папок
; !TODO убрать баг если в параметре маски указан путь до папки или даже до другого диска
;///////////////////////////////////////////////////
cmd_dir: push de
;;;; [ ] поддержка параметров
; зануляем все параметры на старте
xor a
ld (read_disk_info.full),a
ld (.key_p),a
; выполняем/настраиваем все найденные параметры в строке
LD C,256-3 ;!HARDCODE длина строки с командой
.parse: ld hl,cmd_dir_options
call RUN_OPTION
jr nc,.end_opt
jp (hl)
.end_opt: ; выводим строку о расчёте свободного места так, чтоб она затёрлась
ld a,(read_disk_info.full)
and a
jr z,.skip
LD DE,MAIN_MSG.CALCULATING
CALL MESSAGE
;
.skip: ld c,Dss.CurDisk ; узнать тек. диск
RST ToDSS
call read_disk_info ; прочитать метку и серийный номер диска
;
pop de
xor a
ld h,a
ld l,a
ld (FILES),hl
ld (dir_number),hl
ld (S_LOW),hl
ld (S_MED),hl
ld (S_HIGH),a
;
ex de,hl
ld de,work_buffer1 ; 80
ld c,Dss.GSwitch ; выделить параметр ком-строки
RST ToDSS
;!TODO тут в work_buffer1 лежит путь и/или/либо маска файла
; надо разобрать её Dss.EX_Path выделить если есть диск, путь и маску, после чего уже
; отпечатывать путь в шапке, узнавать CurDisk как в .skip выше. Делать это до вызова
; процедуры read_disk_info. Лучше делать это после метки .skip
;
ld a,(work_buffer1)
or a
jr nz,.skipMask ; задана маска имён
;
ld hl,mask_fname ; "*.*"
ld de,work_buffer1
call copy_string
; [ ] 1/10/23
.skipMask: ld hl,work_buffer1 ; имя файла
ld de,work_buffer1 ; 80 буфер
ld a,FAT_ATTR.NoVolID ; атрибут (все, кроме метки тома)
ld bc,Dss.F_First.FATname ; f_first (формат 11)
RST ToDSS
JR C,.Dir_Empty ;R14
CALL Print_Header
;
LD A,32-5 ; количество строк до ожидания клавиши (с вычетом заголовка) ;!HARDCODE
PUSH AF
; цикл вывода списка файлов/папок
.loop: POP AF
.key_p+1: and #ff
dec a
jr nz,.skip_wait
ld de,MAIN_MSG.PAUSE
call MESSAGE ; вывести строку
ld c,Dss.WaitKey
rst ToDSS
dec d
ld de,MAIN_MSG.DIR_ESCAPE
jp z,MESSAGE ; закончить по ESC
;jr nz,.skip_esc
;xor a
;ld (.key_p),a ; отменяем ESC
.skip_esc: ld a,32-1
.skip_wait: PUSH AF
ld hl,work_buffer1+33 ; 80
;push af
;ld de,33
;add hl,de
call PRNNAME
;
ld ix,work_buffer1 ; 80
ld a,(ix+32) ; атрибут тек. записи
and FAT_ATTR.DIRECTORY ; папка ?
jr z,.Calc_Size ; нет
; считаем папки
; не считаем папкой служебные "." и ".."
ld d,(ix+33)
ld e,(ix+34)
ld hl,-('..')
add hl,de
ld a,h
or l
jr z,.next
ld hl,-('. ')
add hl,de
ld a,h
or l
jr z,.next
; увеличиваем счётчик папок
ld hl,(dir_number)
inc hl
ld (dir_number),hl
jr .next
;;R14
.Dir_Empty: push af
CALL Print_Header
pop af
CALL print_err_message
jr .print
;;R14
; прибавить размер тек. файла
.Calc_Size: ld hl,(FILES)
inc hl
ld (FILES),hl
ld e,(ix+FAT_DIRECTORY_RECORD.F_SIZE+2)
ld d,(ix+FAT_DIRECTORY_RECORD.F_SIZE+3)
ld hl,(S_MED)
ld a,(S_HIGH)
exx
ld e,(ix+FAT_DIRECTORY_RECORD.F_SIZE)
ld d,(ix+FAT_DIRECTORY_RECORD.F_SIZE+1)
ld hl,(S_LOW)
add hl,de
ld (S_LOW),hl
exx
adc hl,de
ld (S_MED),hl
;exx
adc a,0
ld (S_HIGH),a
;exx
.next: ld de,work_buffer1 ; 80 буфер
ld c,Dss.F_Next ; поиск след.
RST ToDSS
jp nc,.loop ; назад в цикл, если не конец списка
pop af ; баланс стека
; Десятичный вывод
.print: ld hl,(FILES)
ld ix,PRM3 ; количество файлов
call PDIGIT
;
ld a,(S_HIGH)
ld hl,(S_MED) ; ст. разряд
exx
ld hl,(S_LOW) ; мл. разряд
;exx
;
;CALL PRINT_DWORD
CALL PRINT_5BYTES
;
; [ ] вывод количества папок
; [x] вывод общего количества свободного места
ld hl,SIZE_BUFFER.high ; "000 000 000 000"
ld de,PRM1; + PRM2 ; размер файлов в каталоге
ld bc,SIZE_BUFFER.bytes
call ncopy_string.start ; скопир. строку (с нулем), макс. SIZE_BUFFER.bytes симв.
;
;!TEST
;ld hl,(dir_number)
;ld de,PRM3
;call hex2dec_ascii_16bit.n10000
; Десятичный вывод
ld hl,(dir_number)
ld ix,PRM4 ; кол-во каталогов в каталоге
call PDIGIT
;xor a
;ld (de),a
;
; full capacity
ld a,(full_space_high)
ld hl,(full_space_medium) ; ст. разряд
exx
ld hl,(full_space_low) ; мл. разряд
CALL PRN_DISK_SIZE
; ;
ld de,MAIN_MSG.DIR_2 ; индекс " %1 file(s), %2 bytes, %3 Dir(s)"
CALL MESSAGE ; вывести строку
;
ld a,(read_disk_info.full)
and a
;ld de,MAIN_MSG.CRLF
;jp z,MESSAGE
RET Z
;
; free space
ld a,(free_space_high)
ld hl,(free_space_medium) ; ст. разряд
exx
ld hl,(free_space_low) ; мл. разряд
;
CALL PRN_DISK_SIZE
;
ld de,MAIN_MSG.DIR_4 ; индекс " %6 bytes free"
jp MESSAGE
;
PRN_DISK_SIZE: call PRINT_5BYTES
ld hl,SIZE_BUFFER.high ; "000 000 000 000"
ld de,PRM5 ; and PRM6 ; куда
ld bc,SIZE_BUFFER.bytes
jp ncopy_string.start ; скопир. строку (с нулем), макс. SIZE_BUFFER.bytes симв.
;
Print_Header: ; %1
ld hl,PRM1
ld a,'"'
ld (hl),a
inc hl
ld a,(screen_path) ; диск
ld (hl),a
inc hl
ld a,'"'
ld (hl),a
inc hl
;ld (hl),":"
ld (hl),0
; %2
ld hl,serial_string ; строка серийного номера диска
ld de,PRM2 ; куда
call ncopy_string ; скопир. строку (с нулем)
; %3
ld hl,screen_path ; !FIXIT если ввести "DIR gamez\*.*", то отображаемый путь в заголовке будет неверным
ld de,PRM3 ; 16 буфер
CALL copy_string ; скопир. строку (с нулем)
;
ld de,MAIN_MSG.DIR_1 ; индекс "Volume in drive %1..."
JP MESSAGE ; вывести строку
;
; Подготовить строку списка файлов/папок
PRNNAME: dec hl
ld a,(hl)
and FAT_ATTR.DIRECTORY
call z,.set_small
inc hl
;
ld bc,8
ld de,PRM1 ; буфер
ldir
xor a
ld (de),a
ld de,PRM2 ; куда
ldi
ldi
ldi
ld (de),a
ld ix,work_buffer1
call PRNSIZE ; вывести в буфер имя файла и его размер (у папки
)
call PRNDATE ; вывести в буфер дату файла/папки
call PRNTIME ; вывести в буфер время файла/папки
ld de,MAIN_MSG.DIR_3 ; индекс "%1 %2 %3 %4 %5"
jp MESSAGE ; вывод строки
;
.set_small:
ld d,h
ld e,l
ld b,11 ;!HARDCODE длина имени DOS
.loop: inc hl
ld a,(hl)
cp 'A'
jr c,.next
cp 'Z'+1
jr c,.letter
;
cp 'А' ;#80
jr c,.next
cp 'Я'+1 ;#9F + 1
jr nc,.next
;
.letter: or %0010'0000
ld (hl),a
.next: djnz .loop
ex de,hl
ret
; Вывести в буфер имя файла и его размер (у папки )
PRNSIZE: ld a,(ix+32)
ld hl,DIRIDD ; " "
and FAT_ATTR.DIRECTORY ; папка ?
jr nz,.PRZ ; да
ld l,(ix+FAT_DIRECTORY_RECORD.F_SIZE) ; мл. разряд
ld h,(ix+FAT_DIRECTORY_RECORD.F_SIZE+1)
exx
ld l,(ix+FAT_DIRECTORY_RECORD.F_SIZE+2) ; ст. разряд
ld h,(ix+FAT_DIRECTORY_RECORD.F_SIZE+3)
exx
push ix
call MAKE_LN ; десятичный 32-х разрядный вывод
.not_zero: ld de,SIZE_BUFFER.low ; "0 000 000 000"
ld hl,L32BIT_ ; "0000000000"
ldi
ld a," "
ld (de),a
inc de
ldi
ldi
ldi
ld (de),a
inc de
ldi
ldi
ldi
ld (de),a
inc de
ldi
ldi
ldi
ld hl,SIZE_BUFFER.low ; "0 000 000 000"
pop ix
.PRZ: ld de,PRM3 ; 16 буфер
jp ncopy_string ; скопир. строку (с нулем), макс.15 симв.
; Скопировать в буфер дату файла/папки
PRNDATE: ld c,(ix+FAT_DIRECTORY_RECORD.DATE)
ld b,(ix+FAT_DIRECTORY_RECORD.DATE+1)
ld hl,SIZE_BUFFER.low ; "0 000 000 000"
call MAKE_DATE ; вывод в буфер даты
ld (hl),0
ld hl,SIZE_BUFFER.low ; "0 000 000 000"
ld de,PRM4 ; 16 куда
; ld a,(hl)
; cp "0"
; jr nz,$+4
; ld (hl)," "
jp ncopy_string ; скопир. строку (с нулем), макс.15 симв.
; Скопировать в буфер время файла/папки
PRNTIME: ld b,(ix+22)
ld c,(ix+23)
ld hl,SIZE_BUFFER.low ; "0 000 000 000"
call MAKE_TIME ; скопир. в буфер время файла/папки
ld (hl),0
ld hl,SIZE_BUFFER.low ; "0 000 000 000"
ld de,PRM5 ; 80 буфер строки
; ld a,(hl)
; cp "0"
; jr nz,$+4
; ld (hl)," "
jp ncopy_string ; скопир. строку (с нулем), макс.15 симв.
; в буфер время файла/папки
MAKE_TIME: srl c
rr b
srl c
rr b
srl c
rr b
srl b
srl b
ld a,c
call toNumber
ld (hl),":" ; раздел. времени
inc hl
ld a,b
jr toNumber
; в буфер дату файла/папки
MAKE_DATE: ld a,c
and #1F
push bc
call toNumber
ld (hl),"." ; раздел. даты
inc hl
pop bc
ld a,c
srl b
rla
rla
rla
rla
and #0F
call toNumber
ld (hl),"." ; раздел. даты
inc hl
ld a,b
add a,80
cp 100
jr c,toNumber
.loop: sub 100
cp 100
jr nc,.loop
;
toNumber: ld c,#2F
.loop: inc c
sub 10
jr nc,.loop
add a,10
add a,"0"
ld (hl),c
inc hl
ld (hl),a
inc hl
ret
;
;!TODO перетащить в procedures/math.asm
; Десятичный 32-х разрядный вывод
; HL':HL - число для перевода
; !FIXIT можно объеденить с PDIGIT
MAKE_LN: ld ix,L32BIT_ ; "0000000000"
exx
ld de,#3B9A
exx
ld de,#CA00
; DE':DE = 1,000,000,000
call GET_DIG
.skip_1: exx
ld de,#05F5
exx
ld de,#E100
; DE':DE = 100,000,000
call GET_DIG ; 100,000,000...999,999,999
exx
ld de,#98
exx
ld de,#9680
; DE':DE = 10,000,000
call GET_DIG ; 10,000,000...99,999,999
exx
ld de,#0F
exx
ld de,#4240
; DE':DE = 1,000,000
call GET_DIG ; 1,000,000...9,999,999
exx
ld de,#01
exx
ld de,#86A0
; DE':DE = 100,000
call GET_DIG ; 100,000...999,999
exx
ld de,#00
exx
ld de,#2710
; DE':DE = 10,000
call GET_DIG ; 10,000...99,999
exx
ld de,#00
exx
ld de,#03E8
; DE':DE = 1,000
call GET_DIG ; 1,000...9,999
exx
ld de,#00
exx
ld de,#64
; DE':DE = 100
call GET_DIG ; 100..999
exx
ld de,#00
exx
ld de,#0A
; DE':DE = 10
call GET_DIG ; 10..99
ld a,l
add a,"0"
ld (ix+0),a
inc ix
ret
;
GET_DIG: ld a,"0"-1
AND A
.loop: inc a
sbc hl,de
exx
sbc hl,de
exx
jp nc,.loop
;
add hl,de
exx
adc hl,de
exx
;dec a
cp "0"
jr nz,.putChar
ld b,a
ld a,(ix-1)
cp " "
jr z,.putChar
ld a,b
;
.putChar: ld (ix+0),a
inc ix
ret
;
FILES: WORD 0
S_LOW: WORD 0
S_MED: WORD 0
S_HIGH: BYTE 0
dir_number: WORD 0
free_space_low: WORD 0
free_space_medium: WORD 0
free_space_high: BYTE 0
;
full_space_low: WORD 0
full_space_medium: WORD 0
full_space_high: BYTE 0
;
; !TODO может обойтись одним буфером 00 вместо двух?
L40BIT: db " " ; маркер для ix-1
.Str: db " " ; 00
L32BIT_: db " " ; 000000000
.end: db "0"
;
DIRIDD: db " ",0
;
SIZE_BUFFER: db " " ; маркер для ix-1
.high db " " ; "00"
.low: db " ",0,0 ; "0 000 000 000",0,0
.bytes equ SIZE_BUFFER - $
;
; [x] теперь не лезет напрямую, делает через новый параметр функции DskInfo
; иная логика получения метки тома - сначала ищется в корневой директории,
; если там нет, то берётся из BPB
read_disk_info: OR #80
LD HL,work_buffer
.full+1: LD B,0
LD C,Dss.DskInfo
RST ToDSS
; Файловая система
; Серийный номер диска
; Метка диска в BPB
;
; HL':HL - общее кол-во кластеров
; DE':DE - свободных кластеров
; A - размер кластера в секторах
; BC - размер сектора в байтах
; max sector (LBA28) #0FFF'FFFF
;
EX AF,AF'
LD A,D
AND E
EXX
AND D
AND E
EXX
INC A
LD (.full),A
EX AF,AF'
;
; --> (HL':HL)*BC*A, (DE':DE)*BC*A = B':HL'HL, C':DE':DE
EXX
LD BC,0
EXX
SRL B
RR C
RRCA
JR C,.loop2
;
.loop1: SLA L
RL H
EXX
RL L
RL H
RL B
EXX
;
SLA E
RL D
EXX
RL E
RL D
RL C
EXX
;
RRCA
JP NC,.loop1
;
.loop2: SLA L
RL H
EXX
RL L
RL H
RL B
EXX
;
SLA E
RL D
EXX
RL E
RL D
RL C
EXX
;
SRL B
RR C
JP NC,.loop2
; <-- B':HL'HL, C':DE':DE
EXX
LD A,C
LD (free_space_high),A
LD (free_space_medium),DE
;
LD A,B
LD (full_space_high),A
LD (full_space_medium),HL
EXX
LD (free_space_low),DE
LD (full_space_low),HL
;
.no_full_space_option:
; parse
LD D,0
LD HL,work_buffer
; тут в HL длина поля "Файловая система"
LD E,(HL)
ADD HL,DE
INC HL
; длина поля "Серийный номер диска"
LD A,(HL)
LD E,A
ADD HL,DE
INC HL
PUSH HL ; указатель на длину поля "Метка диска"
CP 4 ;!HARDCODE длина поля серийного номера
JR NZ,unknown_serial
DEC HL
; старшее слово серийника
LD D,(HL)
DEC HL
LD E,(HL)
DEC HL
PUSH HL
EX DE,HL
ld de,serial_string ; xxxx-xxxx
call hex16
POP HL
;
ld a,"-"
ld (de),a
INC DE
; младшее слово серийника
LD A,(HL)
DEC HL
LD L,(HL)
LD H,A
call hex16
.get_label: ; ищем метку в корне ФС раздела
; уст. корень диска
; ld hl,root_path ; "x:\",0
; ld c,Dss.ChDir
; RST ToDSS
; поиск метки
;ld hl,mask_fname ; "*.*" имя метки
ld hl,SlashMaskFname ; "\*.*" имя метки
ld de,work_buffer1 ; куда
ld a,FAT_ATTR.VOLUME_ID ; атрибут метки тома
ld bc,Dss.F_First.FATname ; f_first, формат 11
RST ToDSS
;push af
;call restore_path ; восст. тек. путь
;pop af
ld hl,work_buffer1 + BUFFER_FIND.REC_Name ; начало метки в буфере f_first
jr nc,volume_label ; метка в корневом каталоге
; берём метку из BPB
; тут в HL длина поля "Метка диска"
POP hl
LD A,(HL)
INC HL
AND A
jr z,.no_volume_label ; да
PUSH HL
LD B,A
LD A,' '
;
.loop: CP (HL)
JR NZ,.good_label
INC HL
DJNZ .loop
POP HL ; снимаем лишнее
; нет метки
.no_volume_label:; %4
ld hl,volume_string_no ; строка
ld de,PRM4 ; куда
call ncopy_string ; скопир. строку (с нулем)
XOR A
LD (PRM5),A
ret
.good_label: POP HL
PUSH HL ; толкаем лишнее
; есть метка
volume_label: POP DE ; снимаем лишнее
; %5
ld de,PRM5
ld bc,11 ;!HARDCODE длина метки
ldir
xor a
ld (de),a
; %4
ld hl,volume_string_yes ; строка
ld de,PRM4 ; куда
call ncopy_string ; скопир. строку (с нулем)
ret
;
; если не удалось прочитать серийный номер диска или формат неизвестен
unknown_serial: ; серийный номер диска - неизвестен ;!HARDCODE ниже
LD HL,serial_string
LD A,'?'
LD B,serial_string.Size
.loop: LD (HL),A
INC HL
DJNZ .loop
LD HL,serial_string+4
LD (HL),'-'
;POP HL ; лишнее
JP read_disk_info.get_label
;
;---------------;
SlashMaskFname: db '\' ;
; маска файлов
mask_fname: db "*.*",0
;---------------;
; корень диска
;root_path: db 'X:\',0
; Серийный номер диска
serial_string: db "xxxx-xxxx"
.Size equ $-serial_string
db 0 ; закрывашка
volume_string_no:
db "has no label",0
volume_string_yes:
db "has label",0
; has_not_full_info:
; db ' (?)',0
;
cmd_dir_options:; [x] параметр /F - вывод количества свободного места на диске (тормозит, поэтому параметром)
DB 'f' : DW cmd_dir_freeSpace
DB 'p' : DW cmd_dir_pause
.Size EQU ($-cmd_dir_options)/3
.paramLength EQU 3
;
;
cmd_dir_freeSpace:
; ставим опцию для API DSS DskInfo
ld a,1
ld (read_disk_info.full),a
jp cmd_dir.parse
;
cmd_dir_pause: ld a,#ff
ld (cmd_dir.key_p),a
jp cmd_dir.parse
///////////////////////////////////////////////////////////////////////////////////////
GET_BIG_DIG: ld b,"0"-1
and a
.loop: inc b
sbc hl,de
exx
sbc hl,de
exx
sbc a,c
jp nc,.loop
;
add hl,de
;
exx
adc hl,de
exx
adc a,c
;
ex af,af'
;dec b
ld a,b
cp "0"
jr nz,.putChar
ld a,(ix-1)
cp " "
jr z,.putChar
ld a,b
;
.putChar: ld (ix+0),a
ex af,af'
inc ix
ret
; stop
; A:HL':HL - число для перевода
PRINT_5BYTES: ld ix,L40BIT.Str ; "00"
ld c,#17
exx
ld de,#4876
exx
ld de,#E800
; C:DE':DE = 100,000,000,000
call GET_BIG_DIG
;
ld c,#02
exx
ld de,#540B
exx
ld de,#E400
; C:DE':DE = 10,000,000,000
CALL GET_BIG_DIG
;
ld c,#00
exx
ld de,#3B9A
exx
ld de,#CA00
; C:DE':DE = 1,000,000,000
CALL GET_BIG_DIG
;
; DE':DE = 100,000,000
CALL MAKE_LN.skip_1
ld de,SIZE_BUFFER.high ; "0 000 000 000"
ld hl,L40BIT.Str ; "0000000000"
ldi
ldi
ld a,(hl)
ldi
cp " "
jr z,1F
ld a,"," ; разд. разрядов
1: ld (de),a
inc de
ldi
ldi
ld a,(hl)
ldi
cp " "
jr z,1F
ld a,"," ; разд. разрядов
1: ld (de),a
inc de
ldi
ldi
ld a,(hl)
ldi
cp " "
jr z,1F
ld a,"," ; разд. разрядов
1: ld (de),a
inc de
ldi
ldi
ldi
scf
ret
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
;----------------------------------------------------------------------;
;Процедура умножения (16*8bit)
;На вход: DE * C
;На выход:A:HL = результат
IFUSED Mult32
Mult16X8: SUB A
LD L,A
LD H,A
CP C
RET Z
OR D
OR E
RET Z
LD A,C
LD C,#00
LD B,#08
.loop: ADD HL,HL
RLA
JR NC,.next
ADD HL,DE
ADC A,C
.next: DJNZ .loop
RET
ENDIF
;----------------------------------------------------------------------;
;----------------------------------------------------------------------;
;Процедура умножения (32bit)
;На вход: HL:DE * BC
;На выход:HL:DE = результат
IFUSED Mult32
Mult32: PUSH IX
LD IX,#0000
LD A,#20
EX DE,HL
.loop: ADD IX,IX
ADC HL,HL
RL E
RL D
JR NC,.no_add
ADD IX,BC
JR NC,no_add
INC HL
.no_add: DEC A
JR NZ,.loop
LD E,LX
LD D,HX
POP IX
RET
ENDIF
;----------------------------------------------------------------------;
;INPUT : DE * BC
;OUTPUT: HL:DE
IFUSED Mult32
Mult_16x16: LD IX,0
LD HL,0
;
LD A,B
OR C
JR Z,.exit
;
.loop: SRL B
RR C
JP NC,.no_add
ADD IX,DE
JR NC,.no_add
INC HL
;
.no_add: LD A,B
OR C
JR Z,.exit
;
SLA E
RL D
RL L
RL H
JP .loop
;
.exit: LD D,XH
LD E,XL
RET
ENDIF
///////////////////////////////////////////////////////////////////////////////////////