;/////////////////////////////////////////////////// ; ; DIR. Вывод списка файлов и папок ;/////////////////////////////////////////////////// cmd_dir: push de ;;;; [ ] поддержка параметров ; зануляем все параметры на старте xor a ld (Buffers.work.buffer2),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 ; 23/05/24 .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,Buffers.work.buffer1 ld c,Dss.GSwitch ; выделить параметр ком-строки RST ToDSS ; ld a,(Buffers.work.buffer1) or a ;jr nz,.SkipMask ; задана маска имён jr z,.NoSkipMask ; не задана маска имён ld hl,Buffers.work.buffer1 ld bc,Dss.EX_Path.GET_ALL rst ToDSS ; and %00001100 ; имя диска и путь jr z,.SkipMask ; ld hl,Buffers.work.buffer2+2 ld c,Dss.CurDir rst ToDSS ld c,Dss.CurDisk rst ToDSS add a,"A" ld (Buffers.work.buffer2),a ld a,":" ld (Buffers.work.buffer2+1),a ; xor a ld hl,Buffers.work.buffer1 ld bc,256 cpir ;!FIXIT проверка на ошибку по флагу P/V dec hl ex de,hl ld hl,256-1 and a sbc hl,bc ld b,h ld c,l ld a,'\' ; ex de,hl cpdr ;!FIXIT проверка на ошибку по флагу P/V inc hl ld (hl),0 inc hl ld de,PRM1 call ncopy_string ; сохраняем маску файла ; ld hl,Buffers.work.buffer1 ld c,Dss.ChDir rst ToDSS ; ld hl,PRM1 ld de,Buffers.work.free call ncopy_string ; восстанавливаем маску файла ; ld a,(PRM1) or a jr nz,.SkipMask ; ; добавление маски .NoSkipMask: ld hl,mask_fname ; "*.*" ld de,Buffers.work.free call copy_string ; 23/05/24 .SkipMask: LD C,Dss.CurDisk ; узнать тек. диск RST ToDSS CALL read_disk_info ; прочитать метку и серийный номер диска ; CALL Print_Header ; [ ] 01/10/23 ld hl,Buffers.work.free ; имя файла ld de,Buffers.work.buffer1 ; 80 буфер ld a,FAT_ATTR.NoVolID ; атрибут (все, кроме метки тома) ld bc,Dss.F_First.FATname ; f_first (формат 11) RST ToDSS JR C,.Dir_Empty ;R14 ; 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,Buffers.work.buffer1+33 ; 80 ;push af ;ld de,33 ;add hl,de call PRNNAME ; ld ix,Buffers.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,Buffers.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] вывод количества папок ; [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 симв. ; ; Десятичный вывод ld hl,(dir_number) ld ix,PRM4 ; кол-во каталогов в каталоге call PDIGIT ; 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 ; вывести строку ; ; [ ] 23/05/2024 ld hl,Buffers.work.buffer2 ld c,Dss.ChDir ld a,(hl) or a call nz,ToDSS ; 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 push hl ; ld c,Dss.CurDisk rst ToDSS add a,"A" ; pop hl 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..5 ;push hl ld hl,Buffers.work.free + 256 + 128 ; 128 - на всякий случай ld c,Dss.CurDir rst ToDSS ld hl,PRM3 ld a,(PRM1 + 1) ld (hl),a inc hl ld (hl),':' ; ld hl,PRM3+2 ld de,PRM3+2+1 ld (hl),0 ld bc,16+16+16-1-2 ldir ; ld hl,Buffers.work.free + 256 + 128 ; сист. путь ld de,PRM3 + 2 ;+PRM4..5 ; 2 + 48 байтов буфер call make_short_path ;pop hl ; ld hl,Buffers.screen_path ; !FIXIT если ввести "DIR gamez\*.*", то отображаемый путь в заголовке будет неверным ; ld de,PRM3 ;+PRM4 ; 32 байта буфер ; 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,Buffers.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 куда 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 буфер строки 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,Buffers.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,Buffers.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: ; тут в 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:; %6 ld hl,volume_string_no ; строка ld de,PRM6 ; куда call ncopy_string ; скопир. строку (с нулем) XOR A LD (PRM7),A ret .good_label: POP HL PUSH HL ; толкаем лишнее ; есть метка volume_label: POP DE ; снимаем лишнее ; %7 ld de,PRM7 ld bc,11 ;!HARDCODE длина метки ldir xor a ld (de),a ; %6 ld hl,volume_string_yes ; строка ld de,PRM6 ; куда 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 ///////////////////////////////////////////////////////////////////////////////////////