; This program creates a directory structure suitable for ; time-stamping with DOS+. Any previous time-stamps are ; lost, and the directory is sorted. ; ; Usage: ; INITDIR d (to initialize drive d:) ; or ; INITDIR d X (to remove old time stamps) ; ; (If the disk is already time stamped INITDIR will abort unless ; the "x" parameter is supplied. Similarly, INITDIR will abort ; when too many directory entries are already used) ; ; It may be necessary to patch the "sec1st" value to 1 at location ; 0103h, if the bios system expects sectors from 1 up prior to ; sector translation. ; ; 1.0 86/10/28. Initial release. C.B. Falconer ; ver equ 10 ; boot equ 0 bdos equ 5 ; cr equ 0dh lf equ 0ah ; ; bdos calls coute equ 2 putmsg equ 9 dosver equ 12 seldsk equ 14 galloc equ 27 getdpbp equ 31 offset equ 13; of "off" in dpblk ; ; offsets for bios entries (from COLD boot entry) bdrvsel equ 001Bh bsetrk equ 001Eh bsetsec equ 0021h bsetdma equ 0024h bread equ 0027h bwrite equ 002Ah bsecxlt equ 0030h ; tbuf equ 0080h; default DMA buffer & cmd line ; vacant equ 00E5h; empty dir entries marked timark equ 021h; marker for time-stamp entry dentsiz equ 32; size of a directory entry (coded in) ; jmp begin ; sec1st: db 0; Patch if sectors do not ; start at zero (to secxlate) begin: lxi sp,stack lxi d,signon call tstr mvi c,dosver call bdos; to get hl value lxi d,badvermsg; DOS+ returns 23 up. inr h dcr h jnz exeunt; maybe MPM? cpi 20h jc exeunt; maybe 1.4 cpi 30h jnc exeunt; maybe 3.0 lxi h,tbuf mov a,m ora a lxi d,help jz exeunt; empty line bgn1: inx h mov a,m; skip blanks ora a jz exeunt; eol, empty line cpi ' ' jz bgn1 ani 05fh; upshift sui 'A' cpi 16 jnc exeunt sta drive mov e,a bgn2: inx h mov a,m ora a jz bgn4; eol cpi ' ' jnz bgn2; skip to next field dcx h bgn3: inx h mov a,m; now skip blanks ora a jz bgn4 cpi ' ' jz bgn3 ani 05fh; upshift sui 'X' mvi a,0 jnz bgn4 mvi a,0ffh bgn4: sta killmk; any non-zero does the kill mvi a,seldsk call dos; aborts on invalid drive ; lxi d,loading call tstr mvi c,getdpbp call bdos; Not dos, need HL mov a,m sta spt inx h inx h; +2 mov a,m sta bsh inx h inx h inx h; +5 mov e,m inx h mov d,m; get dsm push d inx h; +7 mov e,m inx h mov d,m; get drm inx h mov b,m; get al0 inx h; +10 mov c,m; get al1 inx h inx h inx h; +13, point to off mov a,m inx h mov h,m mov l,a shld firstk; 1st storage track xchg inx h shld dirmaxplus1 push h call shlrt call shlrt shld dirsectors; := (dirmax+1)/4 pop h pop d ;a=bsh, bc=diralloc bits, de=dsm, hl=dirmax+1 call setup; preserves af, hl:=dsm inx h shld dsmplus1 lda drive mov c,a mvi a,bdrvsel call callbios mov e,m inx h mov d,m xchg shld secxltptr lhld dirsectors mov b,h mov c,l lda sec1st mov e,a lhld firstk; 1st user track shld track lxi h,buffer mvi d,bread call rwdir; into buffer jnz rdwrterror lxi d,sortdirmsg call tstr ; call chkmk; look for old marks call sort call addstamps; add in time marker entries ; lxi d,wrtdirmsg call tstr lhld dirsectors mov b,h mov c,l lda sec1st mov e,a lhld firstk shld track lxi h,buffer mvi d,bwrite call rwdir; write dir. back jnz rdwrterror lxi d,statsmsg call tstr lhld dirmaxplus1 shld dircounter mov e,l mov d,h; * 3/4 for entries remaining dad d dad d; * 3 call shlrt call shlrt; /4 mov a,l ora a lxi d,toomanymsg jz exeunt call tdhlzs lxi d,entriesmsg call tstr lxi h,buffer lxi d,0; entries vacant mov b,d; entries used mov c,e ; L02BC: mov a,m; count entries used/vacant cpi timark jz L02C7 cpi vacant jz L02C6 inx b jmp L02C7 L02C6: inx d L02C7: push d lxi d,dentsiz dad d pop d push h lhld dircounter dcx h shld dircounter mov a,l ora h pop h jnz L02BC push d call tdbczs lxi d,delentriesmsg call tstr pop h call tdhlzs lxi d,usrsactivemsg call tstr mvi e,0ffh lhld dirmaxplus1 shld dircounter lxi h,buffer L02FA: mov a,m cpi timark jz L0314 push h cpi vacant jz L0312 cmp e jz L0312 mov l,a mvi h,0 call tdhlzs mvi a,' ' call couta L0312: pop h mov e,m L0314: push d lxi d,dentsiz dad d push h lhld dircounter dcx h shld dircounter mov a,l ora h pop h pop d jnz L02FA lhld dsmplus1 lda blksused cma mov e,a mvi d,0ffh inx d xchg dad d push h push d mvi c,galloc call bdos; get allocation map. Not DOS here pop d push h call L0456 pop h pop d lxi b,0 L0346: push psw push d push h inx b ana m jz L034F dcx b L034F: pop h pop d dcx d mov a,d ora e jz L035E pop psw call rsha_cnt_in_hl jmp L0346 L035E: pop psw lda bsh mov d,b mov e,c xchg sui 3 jz L0382 L036A: dad h push h lhld dsmplus1 dad h shld dsmplus1 pop h dcr a jnz L036A ; L0382: xchg lxi h,0 L0389: mov a,d ora e jz L0393 inx h dcx d jmp L0389 L0393: xchg lhld dsmplus1 xchg push h mov a,e sub l mov e,a mov a,d sbb h mov d,a lda kbused cma mov l,a mvi h,0ffh inx h dad d lxi d,spaceusedmsg call tstr push h; save used call tdhlzs mvi a,'K' call couta lxi d,spacefreemsg call tstr pop d; used pop h; free push d; save used call tdhlzs mvi a,'K' call couta pop h; bc := used; hl := used mov b,h mov c,l mvi e,0; extend used call lshftehl; multiply by 100 inx h call ehlplusbc call lshftehl call lshftehl call lshftehl call ehlplusbc call lshftehl call lshftehl push h lhld dsmplus1 mov b,h mov c,l pop h mov a,c; bc := -dsmplus1 cma mov c,a mov a,b cma mov b,a inx b mvi d,-1 L03FD: inr d; d := ehl/bc dad b mov a,e aci 0ffh mov e,a jc L03FD mov l,d mvi h,0 lxi d,pctfullmsg call tstr call tdhlzs lxi d,percent ; " " exeunt: call tstr jmp boot ; ; console output from a ; a,f couta: push d mov e,a mvi a,coute call dos pop d ret ; ; string from de^ to console tstr: mvi a,putmsg ; " " ; dos call (a), preserving regs ; a,f dos: push h push d push b mov c,a call bdos pop b pop d pop h ret ; lshftehl: dad h mov a,e ral mov e,a ret ; ehlplusbc: dad b rnc inr e ret ; setup: ;a=bsh, bc=dirallocbits, de=dsm, hl=dirmax+1 push psw mov h,b mov l,c mvi b,16 mvi c,0 setup1: dad h jnc setup2 inr c setup2: dcr b jnz setup1 mov a,c sta blksused xchg pop psw push psw push h sui 3 mov c,a lda blksused mov b,a jz setup4 setup3: add a mov b,a dcr c jnz setup3 mov a,b setup4: sta kbused pop h pop psw ret L0456: lda blksused mov c,a mvi b,080h L045C: mov a,b call rsha_cnt_in_hl mov b,a dcr c jnz L045C mov a,b ret rsha_cnt_in_hl: ora a rar rnc rar inx h ret ; ; read or write directory (complete). NZ for error. ; bc=sectors to rd/wrt, d=r/w opn, e=1st sector, hl=buff ptr ; a,f,b,c,d,e,h,l rwdir: push b push d mov b,h mov c,l push h; stk = buff, sect, ct lhld secxltptr; xchg; l=logical sector mvi h,0 mvi a,bsecxlt call callbioshl; hl=physical sector mvi a,bsetsec call callbioshl; set sector lhld track mvi a,bsetrk call callbioshl; set track pop b; buff address lxi h,080h; advance for next rd/wrt if any dad b push h mvi a,bsetdma; setdma to bc, not advanced call callbios pop h pop d inr e; advance sector for next time lda spt cmp e jnz rwdir1; more on this track push h lhld track; advance track for next time inx h shld track pop h lda sec1st; and reset sector mov e,a rwdir1: pop b push b dcx b mov a,b ora c; check for writing last sector push d; save advanced sect/opn push h; save advanced address mov a,d; read or write lxi b,0; for writes jnz rwdir2; not last write inx b; make it a directory write (flush) rwdir2: call callbios; DO IT pop h pop d pop b ora a rnz; i/o error occured dcx b mov a,b ora c jnz rwdir; more to read/write ret ; ; call bios with argument hl, operation (a) ; a,f,b,c,d,e,h,l callbioshl: mov b,h mov c,l " " ; 0th is cold boot entry. 0,3,.. in (a) ; a,f,b,c,d,e,h,l callbios: push h push d lhld boot+1 dcx h dcx h dcx h mov e,a mvi d,0 dad d pop d xthl ret ; rdwrterror: lxi d,rdwrterrmsg mvi c,putmsg call bdos jmp exeunt ; ; write bc in decimal, zero suppress ; a,f,h,l tdbczs: mov h,b mov l,c ; " " ; write hl in decimal, zero suppress ; a,f tdhlzs: push h call dten push psw mov a,h ora l cnz tdhlzs; recursive, next digit pop psw pop h adi '0' call couta ret ; ; divide hl by 10, remainder to a ; a,f,h,l dten: push b lxi b,0f00ah; c=divisor=10; b=iter.cnt=-16 xra a; clear dten1: dad h ral; shift off into a cmp c jc dten2; no bit sub c; bit=1 inx h dten2: inr b jm dten1; not done pop b ret ; sort: lhld dirmaxplus1 shld window sort1: lhld window call shlrt shld window; window := window DIV 2 ora h rz xchg lhld dirmaxplus1 dcx h mov a,l sub e mov l,a mov a,h sbb d mov h,a shld top; := n-1 - window lxi h,0 shld bottom sort2: shld current sort3: xchg lhld window dad d; window+current call compare; de=current, hl=window+current jnc sort4 call trade lhld window xchg lhld current mov a,l sub e mov l,a mov a,h sbb d mov h,a shld current; := current - window jm sort4 ora l jnz sort3 sort4: lhld bottom inx h shld bottom xchg lhld top call cmphlde xchg jnc sort2 jmp sort1 ; cmphlde: mov a,h cmp d rnz mov a,l cmp e ret ; ; de=current, hl=window+current ; a,f,b,c,d,e,h,l compare: dad h dad h dad h dad h dad h lxi b,buffer dad b xchg dad h dad h dad h dad h dad h dad b mvi b,15 push d push h cp1: ldax d cmp m jnz cp2 inx h inx d dcr b jnz cp1 cp2: pop h; rightentry pop d; leftentry ret; for possible trade trade: mvi c,dentsiz trade1: mov b,m ldax d mov m,a mov a,b stax d inx d inx h dcr c jnz trade1 ret ; ; right shift hl one place shlrt: xra a mov a,h rar mov h,a mov a,l rar mov l,a ret ; ; Add time-stamping entries to directory image. Every fourth entry ; becomes 021h, 0, .. 0 (32 total bytes). addstamps: lhld dirmaxplus1 mov c,l mov b,h lxi h,buffer ; Move entries up and inject time stamp operation. addst1: dcx b dcx b dcx b; 3 entries lxi d,3 * dentsiz dad d; point to entry to inject ; now move (bc) entries up by 32 bytes xchg lxi h,dentsiz dad d xchg; hl = source, de = destination dcx b; move 1 less entry mov a,b ora c mov a,m; in case last entry cnz moveup; leaves hl pointing to time entry cpi vacant jnz toomany; discarding real entry, abort call inject; a timestamp entry, blank mov a,b ora c jnz addst1; do next entry ret ; ; inject timestamp entry at hl^. Advance hl past entry inject: push b mvi b,31 mvi m,timark inj1: inx h mvi m,0 dcr b jnz inj1 inx h pop b ret ; ; moveup hl^ to de^ for bc 32 byte entries moveup: push h push d push b push h mov l,c mov h,b dad h dad h dad h dad h dad h; *32 = dentsiz mov c,l mov b,h; bc is bytes to move xchg dad b; top + 1 destination xchg pop h dad b; top + 1 source mov a,m; keep the discarded 1st byte push psw movup1: dcx h dcx d mov a,m stax d dcx b mov a,b ora c jnz movup1 pop psw; the discarded 1st byte pop b pop d pop h ret ; ; check bc entries from hl^ up for existing time marks chkmk: lhld dirmaxplus1 mov c,l mov b,h lxi h,buffer chkmk1: mov a,m cpi timark jnz chkmk4; not a mark lda killmk ora a lxi d,oldmkmsg jz exeunt mvi m,vacant; erase this entry inx h mvi m,vacant; so sorts to high end dcx h chkmk4: lxi d,dentsiz dad d dcx b mov a,b ora c jnz chkmk1; more ret ; ; abort, too many directory entries to add timestamps toomany: lxi d,toomanymsg jmp exeunt ; help: db 'usage: INITDIR d: [x:]' db cr,lf, db '(d is drive to sort/timestamp, ' db 'optional x: removes old timestamps)$' badvermsg: db cr,lf db 'Run under DOS+ or CPM2.2 only$' toomanymsg: db cr,lf db 'Too many files to add time-stamps, aborted$' oldmkmsg: db cr,lf db 'Time stamps already present, aborted$' rdwrterrmsg: db cr,lf db 'Read/Write Error!$' loading: db cr,lf db 'Loading directory.$' sortdirmsg: db cr,lf db 'Sorting directory.$' wrtdirmsg: db cr,lf db 'Writing directory.$' statsmsg: db cr,lf,cr,lf db ' Disk Statistics' db cr,lf db 'Possible entries : $' entriesmsg: db cr,lf db 'Active entries : $' delentriesmsg: db cr,lf db 'Deleted entries : $' usrsactivemsg: db cr,lf db 'User area active : $' spaceusedmsg: db cr,lf db 'Disk space used : $' spacefreemsg: db cr,lf db 'Disk space free : $' pctfullmsg: db cr,lf db 'Percent full : $' percent: db '%$' signon: db cr,lf db 'INITDIR (DOS+ time-stamps) Ver. ' db ver / 10 + '0', '.', ver mod 10 + '0' db ' (c) 1986 C.B. Falconer' db cr,lf db '$' ; killmk: ds 1; flag remove old stamps ; drive: ds 1 secxltptr: ds 2 firstk: ds 2; 1st storage track spt: ds 2; sectors per track dirmaxplus1: ds 2; dir entries available dirsectors: ds 2; sectors in whole directory ; ; sort vars top: ds 2 bottom: ds 2 window: ds 2 current: ds 2 ; track: ds 2 dircounter: ds 2 bsh: ds 1 blksused: ds 1 kbused: ds 1 dsmplus1: ds 2 ds 100 stack: buffer: ds 0; the rest end