; ZDR2.ASM ;Small, horizontal directory. Sorts directory ;entries alphabetically, and presents them in ;horizontal order. The "Z" of zdr shows the path ;of the cursor. Will take disk specification on ;command line: ; A>zdr B: ;Understands user specifications in ZCPR style also: ; A>zdr D2: ;When other disks(D) or users(U) are selected, zdr ;returns to the original DU: on exit. If a user ;is specified, zdr shows the files in that user ;# only, though it continues to show total disk ;space, that is, space for the entire disk, all ;users. The object file is less than 1k in size, ;and zdr is particularly useful when disk space is ;limited, as in the Epson Geneva PX-8. ; ;Mike Yarus, 2231 16th Street, Boulder, CO 80302 ;Compuserve 73145,513 July, 1985 ; cnout equ 02h ;BDOS functions pstr equ 09h ; | seldsk equ 0Eh ; | schfrst equ 11h ; | schnext equ 12h ; | getdsk equ 19h ; | allocv equ 1Bh ; | dpbaddr equ 1Fh ; | usernr equ 20h ;_______v______ cr equ 0Dh lf equ 0Ah tab equ 09h tpastrt equ 0100h bdos equ 0005h fcb equ 05Ch dma equ 080h dummy equ 0000h ;marks run time addr ; org tpastrt ; ;current disk and user number data ; mvi c,usernr mvi e,0FFh ;get user # call bdos ;and store it sta initusr ;for possible change ; mvi c,getdsk;get current disk call bdos sta initdsk ;store current disk ; ;new disk and/or user number? ; lda fcb ;get disk, CPM-style cpi 0 ;default? jnz drv ;no, disk change needed ;also check ZCPR spec lda fcb+2 ;check user, ZCPR-style cpi ' ' ;blank? jz fillfcb ;yes, no change needed sui 30h ;no, convert user to hex mov e,a ;reset user mvi c,usernr call bdos ;switch! ; lda fcb+1 ;get disk, ZCPR-style sui 40h ;1=A:, 2=B:, etc. ; drv sui 1 ;calc disk # mov e,a ;0=A:, 1=B:, etc. mvi c,seldsk;select new disk call bdos ;switch! ; fillfcb lxi h,ambgfcb ;write the ambiguous lxi d,ambgfcb+10h ;fcb to search directory lxi b,fcb+1 ;CP/M did drive at fcb call movbyte ;move 'em! ; ;block size data for cases different from 1k ; mvi c,dpbaddr call bdos ;dpb addr in hl lxi d,02h ;offset to block shift dad d ;BSH addr in hl mov a,m ;BSH in a sui 3h ;0=1k, 1=2k, 2=4k,... xchg ;dpb+2 -> de cma adi 1 ;-block power in a lxi h,times1;addr for x 1 add l mov l,a ;addr for x block size shld mult+1 ;jmp addr at run time xchg ;dpb+2 back inx h ;dpb+3, addr BLM mov a,m ;get BLM inr a ;BLM+1 = sectors/block rrc!rrc!rrc ;(BLM+1)/8 = k/block sta blksiz ;store block size in k ; ;begin directory search ; getdir lda dirfn ;search first or next mov c,a lxi d,fcb call bdos ;fill dma w/ dir cpi 0FFh ;done? jz eotbl ;yes, terminate table ; ;calculate address of the directory entry ; add a!add a!add a!add a!add a ;code*32 adi dma ;addr dir entry in a ; ;read the directory entry ; mov c,a ;lo nibble, address mvi b,0 ;hi nibble zeroed ldax b ;file name or user byte cpi 0E5h ;erased? jz setdirf ;yes, ignore entry fname inx b ;no, get next addr ldax b ;get char ani 7Fh ;mask hi bit cpi 20h ;is this a char? jm extent ;not char, its the extent call mktable ;add to directory table jmp fname ;around again ; ;get extent and calculate size of the file ; extent add a!add a!add a!add a ;# extents*16 = k mov d,a ;k in extents -> d inx b!inx b!inx b ;addr of # records ldax b ;get # records, this extent ; ;a -> records/8, round up,= #k, add to extents ; rrc ! rrc ! rrc ;records div 8, sort of mov b,a ;save a ani 0E0h ;remainder? mask 11100000b mov a,b ;a back, flags same jz thru ;no remainder adi 1 ;remainder, round up thru ani 1Fh ;a has #k in records add d ;+k in extents ;file size in a call block ;correct to data block size call mktable ;add to directory table ;tally the entry lda count ;total dir entries so far inr a ;+ 1 sta count ;re-store ;reset dirfn setdirf mvi a,schnext sta dirfn ;search for next jmp getdir ;next entry! ; ;got all entries, write "end of table" into dirtbl ; eotbl mvi a,60h ;put in string of 60h mvi b,60h-0Ch ;counter set mo call mktable ;one 60h to dirtbl inr b ;counter incremented cmp b ;= a yet? jnz mo ;no, move another byte ; ;sort list of strings of length nrchar ;# strings is in location -> count ;de - address of string #2 ;hl - address of string #1 ; listhed call init ;counters = 0, get top addr strcomp lda entries ;# directory entries done inr a sta entries mov b,a ;test for end of table lda count ;tot entries in table cmp b ;done? jz endchk ;yes, check for sort end jm stats ;no entries, give disk size ; call stradd ;get string addresses call compar ;compare them, nrchar=12 jm next ;a=0, str =: a>0, str #1 bigger ; call stradd ;#1 bigger, interchange them call switch ;does it lda swnr inr a sta swnr ;count the switch ; next call nextstr ;incr string addresses jmp strcomp ;do next string ; endchk lda swnr ;# exchanges ora a ;is it 0? jnz listhed ;no, init another round ;yes, print the ordered list ; ;print a sorted list of directory entries ;have been sorted alfa, and also w/ increasing file size ;print when two successive file names DIFFER ;in order to handle multiple extents of the same file ; mvi a,0Bh ;11d sta nrchar ;compar 11 char strings ; call init ;entries=0, string1->dirtbl nxtntry lhld string1 ;load address mov a,m ;get first char, str #1 cpi 60h ;is it the end of table? jz stats ;yes, do space output ; call stradd ;str addresses call compar ;1st 11 char of str same? cnz writit ;no, differ, write them call nextstr ;incr addresses jmp nxtntry ;another entry ; ;disk size and usage section ; stats call eol ;after all files mvi c,getdsk;current disk call bdos ;get it adi 41h ;make ascii call print ;write disk lxi d,dskstr call prntstr ;disk title ; ;calc total disk space from the disk param block ; mvi c,dpbaddr ;get DPB address call bdos ;addr in hl lxi d,05h ;offset for DSM dad d ;hl -> addr DSM call getwd ;(hl) -> hl inx h ;# data blocks in hl shld tot ;store # blocks/disk ; call mult ;multiply by block size call decimal ;#k total output from hl lxi d,totstr call prntstr ;tot title ; ;find the address of the allocation vector, ;then read the bit map and mask out the space ;allocation for the disk. Uses word arithmetic ;for total space. ; ;a-the bit mask, tests ;hl-address of bytes to be masked, the bit map ; getvect mvi c,allocv call bdos ;have the alloc addr in hl lda mask ;get the byte mask, 1h abyte mov b,m ;get a byte inx h ;addr of next byte ; bitloop rrc ;shift mask right sta mask ;store mask ana b ;bit set? cnz nralloc ;yes, count this one push h ;save addr of bit map call totnr ;increment total, de<- totgrps ; lhld tot ;hl <- groups/disk call equal ;done? if a=0, were equal pop h ;get addr back ora a ;a=0? jz done ;yep, done ;o'wise, do another group lda mask ;get mask back cpi 1 ;masked the last bit? jz abyte ;yes,get another byte, mask=1 jmp bitloop ;another bit ; done lhld alcgrps ;get allocated groups call mult ;multiply by block size call decimal ;output! lxi d,usedstr call prntstr ;print used title ; lhld alcgrps ;get allocated call neghl ;negate it, 2's complement xchg ;-alcgrps to de lhld totgrps ;get tot grps/disk dad d ;space word in hl ; call mult ;multiply by block size call decimal ;output! lxi d,lftstr call prntstr ;print remains title ; ;reset to original disk and user, in case changed ; mvi c,usernr lda initusr ;load original user # mov e,a call bdos ;switch! ; mvi c,seldsk lda initdsk ;select init disk mov e,a call bdos ;switch! ;done back ret ;back to CP/M <<< END, MAIN ; ;format and write one dir entry to the screen ;gets address of string stored at string1 ;writes 11 char, then file size thru "decimal" ; writit lxi d,estr ;'> ' before entries call prntstr ;write it ; lhld string1 ;load the address mov b,h mov c,l ;set up for writit lxi d,0Bh ;set counter, d=0, e=11 ; nextchr ldax b ;get char inx b ;next get call print ;write it inr d ;increment char count mov a,e ;# char -> a cmp d ;whole name yet? jnz nextchr ;no, another char ldax b ;get size of file ; mvi h,0 ;set up mov l,a ;for output call decimal ;and do it ; lxi d,kstr call prntstr ;'k ' out ; lda entries ;total dir entries so far inr a ;+ 1 sta entries ;re-store ; ;format output into lines with four files/line ; ani 3 ;00000011b mask cz eol ;eol if a mod 4 = 0 ret ;end of entry ; ;string comparison routine, compares "nrchar" bytes ;h - address of string #1 < on exit = addr of difference ;d - address of string #2 < or addr after string, if =. ;b - counter < on exit, has # chars compared ;a=0, strings same: a>0, #1 bigger: a<0, #2 bigger ;flags also set to indicate result & can be used ; compar mvi b,0 ;set byte counter compar1 mov a,m ;str #1 char -> a xchg ;#2 addr -> hl mov c,m ;str #2 char -> c inr b ;incr counter sub c ;a=c?, strings same? rnz ;no xchg ;keep #1 in hl inx d inx h ;incr string addresses ; lda nrchar ;# char to check sub b ;done? jnz compar1 ;no ret ;yes ; ;exchange two strings of bytes of the coded length ;de - address of string #2 ;hl - address of string #1 ;b - counter ; switch mvi b,0 ;initialize counter switch1 mov c,m ;str #1 char -> c ldax d ;str #2 char -> a mov m,a ;str #2 char -> #1 mov a,c ;#1 char -> a stax d ;#1 char -> #2 ; inx d inx h ;incr addresses inr b ;incr byte counter mov a,b ;get counter cpi 12d ;12 char done? jnz switch1 ;no ret ;move done ; ;set up string #1 and string #2 addr for sort or compar ; stradd lhld string1 ;get current lxi d,0Ch ;str offset dad d ;get str #2 addr xchg lhld string1 ;get str #1 addr ret ;return ; ;initialize for sort or print of sorted list ; init xra a ;a=0 sta entries ;directory counter sta swnr ;# switches, for sort lxi h,dirtbl shld string1 ;address of current string ret ; ; ;increment string address ; nextstr lhld string1 ;get current lxi d,0Ch ;offset between str dad d shld string1 ;put back ret ;done ; ;print char in a to console, save b and d ; print push b ;save b push d ;save d mov e,a ;posn to go -> cons mvi c,cnout ;bdos #2 call bdos pop d ;d back pop b ;b back ret ;done ; ;bdos #9, print string at d, terminated by $ ; prntstr mvi c,pstr call bdos ret ;done ; eol lxi d,crlf call prntstr ret ;crlf at line end done ; ;relocate the bytes beginning at hl ; bytes end + 1 at de ; to addr at bc ; movbyte mov a,m ;get a byte stax b ;put byte to bc inx b ;increment put addr inx h ;increment get addr ; mov a,h ;hi nibble, get addr cmp d ; = hi nibble, end? jnz movbyte ;no, move another byte ; mov a,l ;lo nibble, get addr cmp e ; = lo nibble, end? jnz movbyte ;no, move another byte ; ret ;done w/ move ; ;gets file size in a in kbytes, calculates real size ;in a by adjusting to end on block borders ; block mov b,a ;size in k -> b lda blksiz ;get block size dcr a ;mod mask cma ;complement of mask mov c,a ;store cma ;mask back ana b ;siz mod block = 0? mov a,b ;get the number rz ;yes, return size unchanged lda blksiz ;get block size add b ;add one block to size ana c ;mask off remainder ret ;done ; ;output the hex number in hl as a decimal w/ lead blks ;puts the number in space 3 wide ; decimal mvi b,0FFh ;set counter to -1 ; cento lxi d,-100 ;100's dad d ;hl - 100d inr b ;count it mov a,h ani 80h ;result negative? if a=0, no. jz cento ;another 100? ; mov a,b ;get 100's sta cs ;store them mvi b,0FFh ;reset counter to -1 lxi d,100 dad d ;reset number ; deci lxi d,-10 ;10's dad d inr b mov a,h ;negative result? ani 80h jz deci ;no, another 10? ; mov a,b ;get 10's sta ts ;store lxi d,10 dad d ;1's in hl ; mov a,l ;get 1's sta os ;store them ; lda cs call prdeci ;100's lda ts call prdeci ;10's lda os call prdeci ;1's ; xra a ;zero to reset the sta zflag ;print zeros flag ret ; ;print decimal digit in a unless it is a leading zero ;when it will be a blank ; prdeci mov d,a ;save nr xri 0 ;is the number a zero? jz zero ;yes mvi a,1 ;set zflag after 1st non-0 sta zflag ;now printing zeros jmp pr ;get nr back, print ; zero lda zflag ;print a zero? ora a ;0 = no jnz pr ;yes, print ;no, not printing 0's mvi a,' ' ;use a blank jmp ready ;out the blank ; pr mov a,d ;get nr back adi 30h ;make into ascii ready call print ;out, note bc saved ret ; ;multiply the word in hl by 1,2,4,8,16 in order ;to calculate space for group size <> 1k ; mult jmp dummy ;replaced at run time dad h ;x 16k dad h ;x 8k dad h ;x 4k dad h ;x 2k times1 equ $ ;x 1k ret ; ;increment allocated groups, preserve hl ; nralloc push h ;save addr in hl lhld alcgrps inx h shld alcgrps pop h ret ;return ; ;increment total groups, return totgrps in de ; totnr lhld totgrps inx h shld totgrps xchg ;totgrps -> de ret ;return ; ;test equality of two words in de and hl ;return a = 0 for equality, no difference ;return a <> 0 for non-equality, is a difference ; equal mov a,d ;get hi nibble, de sub h ;a=h? rnz ;no, return mov a,e ;get lo nibble sub l ;lo nibbles =? ret ;0 if =, <>0 if not equal ; ;load hl with word at address in hl, addr+1 -> de ; getwd mov e,m ;lo nibble into e inx h ;next byte mov d,m ;hi nibble into d xchg ;de <--> hl ret ;addr+1 in de ; ;negate the word in hl, ie, take 2's complement ; neghl mov a,l ;get lo nibble cma ;complement it mov l,a ;back mov a,h ;get hi nibble cma ;complement mov h,a ;back inx h ;+1 ret ;-hl in hl ; ;write byte in a to the growing directory table ; mktable lhld tbladdr ;get current address mov m,a ;store the current entry inx h ;incr addr shld tbladdr ;restore addr ret ; ambgfcb db '????????????',0,0,0 ;ambiguous fcb ; dirfn db schfrst ;search for first, init tot dw 0000 ;allocation blocks per disk totgrps dw 0000 ;total groups counted alcgrps dw 0000 ;allocated groups counted ; mask db 1 ;the byte mask count db 00 ;# dir entries, # output entries db 00 ;dir entry counter nrchar db 0Ch ;# char to compar swnr db 00 ;# of switches during sort string1 dw dirtbl ;addr of current dir string ; initdsk ds 1 ;initial disk: 0=A:, 1=B:, etc initusr ds 1 ;initial user # blksiz ds 1 ;block size ; estr db '> $' ;pre-entry string kstr db 'k $' ;k title crlf db cr,lf,'$' dskstr db ': $' usedstr db 'k used >>$' totstr db 'k total/$' lftstr db 'k left$' zflag db 00 ;print zero? 0 = no, 1= yes cs db 00 ;100's ts db 00 ;10's os db 00 ;1's ; tbladdr dw dirtbl ;current value of table address dirtbl equ $ ;start here, grow up! ; end