; ; PROGRAM: MKDIR ; VERSION: 1.2 ; AUTHOR: RICHARD CONN ; DATE: 17 Jan 83 ; PREVIOUS VERSIONS: 1.1 (15 Jan 83), 1.0 (14 Jan 83) ; VERS EQU 12 ; ; MKDIR is used to create named directory files. It allows the user ; to read and edit them. It is fully integrated into the ZCPR2 system. ; ; Forms of the MKDIR command are: ; MKDIR <-- Enter System ; MKDIR // <-- Get Help ; MKDIR filename.typ <-- Enter System with selected file ; ; ; CP/M Constants ; cpm equ 0 ; base bdose equ cpm+5 fcb equ cpm+5ch tbuff equ cpm+80h cr equ 0dh lf equ 0ah ; ; SYSLIB Routines ; ext print,zgpins,putud,getud,logud,retud,zfname,moveb ext cin,cout,crlf,caps,compb ext fi0$open,f0$get,fi0$close ext fo0$open,f0$put,fo0$close ext bbline,padc,initfcb,cline,zpfind,codend ext sort ; ; This program is Copyright (c) 1982, 1983 by Richard Conn ; All Rights Reserved ; ; ZCPR2 and its utilities, including this one, are released ; to the public domain. Anyone who wishes to USE them may do so with ; no strings attached. The author assumes no responsibility or ; liability for the use of ZCPR2 and its utilities. ; ; The author, Richard Conn, has sole rights to this program. ; ZCPR2 and its utilities may not be sold without the express, ; written permission of the author. ; ; ; Branch to Start of Program ; jmp start ; ;****************************************************************** ; ; SINSFORM -- ZCPR2 Utility Standard General Purpose Initialization Format ; ; This data block precisely defines the data format for ; initial features of a ZCPR2 system which are required for proper ; initialization of the ZCPR2-Specific Routines in SYSLIB. ; ; ; EXTERNAL PATH DATA ; EPAVAIL: DB 0FFH ; IS EXTERNAL PATH AVAILABLE? (0=NO, 0FFH=YES) EPADR: DW 40H ; ADDRESS OF EXTERNAL PATH IF AVAILABLE ; ; INTERNAL PATH DATA ; INTPATH: DB 0,0 ; DISK, USER FOR FIRST PATH ELEMENT ; DISK = 1 FOR A, '$' FOR CURRENT ; USER = NUMBER, '$' FOR CURRENT DB 0,0 DB 0,0 DB 0,0 DB 0,0 DB 0,0 DB 0,0 DB 0,0 ; DISK, USER FOR 8TH PATH ELEMENT DB 0 ; END OF PATH ; ; MULTIPLE COMMAND LINE BUFFER DATA ; MCAVAIL: DB 0FFH ; IS MULTIPLE COMMAND LINE BUFFER AVAILABLE? MCADR: DW 0FF00H ; ADDRESS OF MULTIPLE COMMAND LINE BUFFER IF AVAILABLE ; ; DISK/USER LIMITS ; MDISK: DB 4 ; MAXIMUM NUMBER OF DISKS MUSER: DB 31 ; MAXIMUM USER NUMBER ; ; FLAGS TO PERMIT LOG IN FOR DIFFERENT USER AREA OR DISK ; DOK: DB 0FFH ; ALLOW DISK CHANGE? (0=NO, 0FFH=YES) UOK: DB 0FFH ; ALLOW USER CHANGE? (0=NO, 0FFH=YES) ; ; PRIVILEGED USER DATA ; PUSER: DB 10 ; BEGINNING OF PRIVILEGED USER AREAS PPASS: DB 'chdir',0 ; PASSWORD FOR MOVING INTO PRIV USER AREAS DS 41-($-PPASS) ; 40 CHARS MAX IN BUFFER + 1 for ending NULL ; ; CURRENT USER/DISK INDICATOR ; CINDIC: DB '$' ; USUAL VALUE (FOR PATH EXPRESSIONS) ; ; DMA ADDRESS FOR DISK TRANSFERS ; DMADR: DW 80H ; TBUFF AREA ; ; NAMED DIRECTORY INFORMATION ; NDRADR: DW 00000H ; ADDRESS OF MEMORY-RESIDENT NAMED DIRECTORY NDNAMES: DB 64 ; MAX NUMBER OF DIRECTORY NAMES DNFILE: DB 'NAMES ' ; NAME OF DISK NAME FILE DB 'DIR' ; TYPE OF DISK NAME FILE ; ; REQUIREMENTS FLAGS ; EPREQD: DB 0FFH ; EXTERNAL PATH? MCREQD: DB 000H ; MULTIPLE COMMAND LINE? MXREQD: DB 0FFH ; MAX USER/DISK? UDREQD: DB 000H ; ALLOW USER/DISK CHANGE? PUREQD: DB 000H ; PRIVILEGED USER? CDREQD: DB 0FFH ; CURRENT INDIC AND DMA? NDREQD: DB 0FFH ; NAMED DIRECTORIES? Z2CLASS: DB 0 ; CLASS 0 DB 'ZCPR2' DS 10 ; RESERVED ; ; END OF SINSFORM -- STANDARD DEFAULT PARAMETER DATA ; ;****************************************************************** ; ; ; Start of Program ; start: lxi h,0 ; save stack dad sp shld stack xra a ; A=0 sta chflag ; set no changes sta flflag ; set no file loaded sta ecount ; set no entries call zgpins ; set up environ call print db 'MKDIR Version ' db vers/10+'0','.',(vers mod 10)+'0',0 lda fcb+1 ; check for help cpi '/' jnz start1 call print ; print help message db cr,lf,' MKDIR is used to read and edit named directory files.' db cr,lf,'It is invoked by the following forms --' db cr,lf db cr,lf,' MKDIR <-- Enter System' db cr,lf,' MKDIR dir:filename.typ <-- Define File First' db cr,lf,' MKDIR // <-- Print this Help' db cr,lf,0 ret start1: call putud ; save current dir for quick return call retud ; get current user and disk mov a,b ; save disk sta cdisk mov a,c sta cuser lxi h,dnfile ; set default file name lxi d,dfcb+1 ; copy into fcb mvi b,11 ; 11 chars call moveb lxi h,tbuff ; save command line as string call cline call sblank ; skip to non-blank ora a ; no entry? jz mkdir ; enter system ; ; Main Entry Point for Loading a File ; loadfile: lxi sp,stack ; set stack lxi d,dfcb ; set up default file name call zfname ; extract info jnz start2 call print db cr,lf,'Error in Disk or User -- Ignoring',0 lda cdisk ; set current values mov b,a lda cuser mov c,a jmp start3 start2: mov a,b ; check for current disk cpi 0ffh ; current? jnz cutst lda cdisk ; get current disk mov b,a inr b ; add 1 for following decrement cutst: dcr b ; adjust disk to 0 to n-1 mov a,c ; check for current user cpi 0ffh ; current? jnz start3 lda cuser ; get current user mov c,a start3: call logud ; log into UD to begin search ; ; Entry Point for Loading File in DFCB ; ffile: lxi sp,stack ; reset stack mvi b,0ffh ; search current first lxi d,dfcb ; pt to FCB call initfcb ; init it call zpfind ; look for file jnz start4 call print db cr,lf,'File ',0 lxi h,dfcb+1 ; print name call prfn call print db ' Not Found',0 jmp mkdir start4: call logud ; log into dir of file lxi d,dfcb call initfcb call fi0$open ; open file for input call codend ; pt to scratch buffer lda ndnames ; get max entry count mov b,a ; ... in B readf: call getch ; get disk letter from file sui 'A' ; convert to number from 0 to n-1 mov m,a ; store disk number inx h ; pt to user number call getch ; get user number mov m,a ; store user number inx h ; pt to next mvi c,8 ; store dir name readn: call getch ; get char ora a ; done? jz readn1 mov m,a ; store char if not done inx h ; pt to next dcr c ; count down jnz readn jmp readn2 readn0: call getch ; flush char readn1: mvi m,' ' ; store spaces now inx h ; pt to next dcr c ; count down jnz readn0 readn2: call getch ; flush 9th char dcr b ; count down jnz readf ; continue reading file entries call fi0$close ; close input file call getud ; return to current dir call dirpack ; pack dir mvi a,0ffh ; set file loaded flag sta flflag jmp mkdir1 ; ; Enter MKDIR System and Init Environ ; Enter at MKDIR if no file loaded, enter at MKDIR1 if file loaded ; mkdir: call dinit0 ; init directory xra a ; A=0 sta ecount ; set no entries present sta flflag ; set no file loaded sta chflag ; set no changes mkdir1: lxi sp,stack ; set stack call print db cr,lf,'MKDIR Command (? for Help)? ',0 call cin ; get command call caps ; capitalize call cout ; echo lxi d,mkdir1 ; set ret address push d lxi h,ctable ; scan command table for it mov c,a ; command in C mkdir2: mov a,m ; get command letter ora a ; end of table? jz mkdirh cmp c ; match? jz mkdir3 inx h ; skip over address inx h inx h jmp mkdir2 mkdir3: inx h ; get address in HL mov a,m ; low inx h mov h,m mov l,a ; HL is address of routine pchl ; "call" routine ; ; Print MKDIR Command Help ; mkdirh: call print db cr,lf,'MKDIR Commands are --' db cr,lf,' C -- Change Directory (Add/Rename/Delete Entries)' db cr,lf,' I -- Initialize Directory' db cr,lf,' P -- Print Directory' db cr,lf,' R -- Read Directory File' db cr,lf,' S -- Status of MKDIR Environment' db cr,lf,' W -- Write Directory File' db cr,lf,' X -- Exit Program' db cr,lf,0 ret ; ; Command Table ; ctable: db 'C' ; change directory dw change db 'I' ; init directory dw dinit db 'P' ; print directory dw dprint db 'R' ; read file dw read db 'S' ; status dw status db 'W' ; write file dw write db 'X' ; exit dw exit db 0 ; end of table ; ; Status ; status: call print db cr,lf,'** MKDIR Status **',cr,lf,cr,lf,0 lda ecount ; print entry count mov b,a ; ... count in B for later call padc call print db ' Entries in Directory',cr,lf,0 lda ndnames ; get limit sub b ; subtract amount taken so far call padc call print db ' Empty Entries Remaining' db cr,lf db cr,lf,'Working File Name: ',0 lxi h,dfcb+1 call prfn call crlf ; new line call crlf lda chflag ; changes made? ora a jnz stat1 call print db 'No ',0 stat1: call print db 'Changes made to Directory since Startup' db cr,lf,0 lda flflag ; file loaded? ora a ; 0=no jnz stat2 call print db 'No ',0 stat2: call print db 'File has been loaded',cr,lf,0 ret ; ; Init Directory ; dinit: call print db cr,lf,' Are you sure you want to Initialize the Directory ' db '(Y/N/=N)? ',0 call cin ; get response call caps call cout call crlf cpi 'Y' ; Yes is only valid reply rnz dinit0: xra a ; A=0 sta ecount mvi a,0ffh sta chflag ; set change flag call codend ; pt to directory lda ndnames ; get entry count mov b,a ; ... in B dinit1: mvi m,0 ; set double zero inx h mvi m,0 inx h ; pt to name mvi c,8 ; 8 chars dinit2: mvi m,' ' ; store space inx h ; pt to next dcr c ; count down jnz dinit2 dcr b ; count down jnz dinit1 ret ; ; Read File ; read: call getfname ; get file name ora a ; none? jz ffile ; just find default file and load it jmp loadfile ; parse entry and load file ; ; Get File Name from User ; getfname: call print db cr,lf,'Name of File ( = ',0 lxi h,dfcb+1 ; print default name call prfn call print db ')? ',0 mvi a,0ffh ; capitalize call bbline ; get user input call sblank ; skip to non-blank ora a ; default? ret ; ; Write File ; write: call getfname jz write1 lxi d,dfcb ; parse into DFCB call zfname ; parse file name jnz write0 call print db cr,lf,'Invalid Disk or User -- Using Current Directory',0 jmp write1 write0: mov a,b ; current disk? cpi 0ffh jnz wutst lda cdisk ; select current disk mov b,a inr b ; add 1 for following decrement wutst: dcr b ; adjust disk to 0 to n-1 mov a,c ; current user? cpi 0ffh jnz wlog lda cuser ; select current user mov c,a wlog: call logud ; log into new dir write1: lxi d,dfcb ; open file for output call initfcb call fo0$open ; open file ora a ; OK? jnz werr ; write error and abort call print db cr,lf,'Writing Directory to Disk ... ',0 lda ndnames ; save dir as loaded mov b,a ; count in B call codend ; pt to start of buffer writef: mov a,m ; get disk adi 'A' ; convert to letter call putch ; write char inx h ; pt to user mov a,m ; get user call putch ; write char inx h ; pt to next mvi c,8 ; write dir name to disk wf1: mov a,m ; get char cpi ' ' ; done? jz wf2 inx h ; pt to next call putch ; write char to disk dcr c ; count down jnz wf1 jmp wf3 wf2: xra a ; write zeroes inx h ; skip next char call putch dcr c ; count down jnz wf2 wf3: xra a ; write 9th zero call putch dcr b ; count down jnz writef call fo0$close ; close file call getud ; go home xra a ; A=0 sta chflag ; set no changes flag call print db 'Done',0 ret ; ; Exit from MKDIR ; exit: lda chflag ; check for any changes ora a ; 0=No jz exit1 call print db cr,lf db cr,lf,'Directory has changed since last Write' db cr,lf,'Do you want to write Directory to Disk first ' db '(Y/N/=Y)?',0 call cin ; get response call caps call cout call crlf ; new line cpi 'N' ; no? cnz write ; write if not No exit1: lhld stack ; return to OS sphl ret ; ; Print Directory to User ; dprint: lda ecount ; any entries? ora a ; 0=none jnz dpr1 call print db cr,lf,'Empty Directory',0 ret dpr1: call codend ; pt to first element lda ecount ; get entry count mov b,a ; ... in B mvi c,'A'-1 ; set disk type prloop: inr c ; next disk call print db cr,lf,'Disk ',0 mov a,c ; print disk letter call cout call print db ' --',0 mvi a,0ffh ; set line count sta crcnt prl1: mov a,m ; get next disk adi 'A' ; convert to alpha cmp c ; same as current? jnz prloop ; loop to next if not lda crcnt ; increment entry count inr a sta crcnt ani 3 ; new line? cz crlf call print db ' ',0 ; space over inx h ; pt to user mov a,m ; get user number call padc ; print user number call print db ': ',0 inx h ; pt to name mvi d,8 ; 8 chars prl2: mov a,m ; get char inx h ; pt to next call cout ; print char dcr d ; count down jnz prl2 prl3: dcr b ; count down jnz prl1 call crlf ; new line lda ecount call padc call print db ' Entries in Directory',0 ret ; ; Change Directory Contents ; change: call print db cr,lf,'** MKDIR Change Mode **',0 ch0: call print db cr,lf,'Directory Entry (? for Help)? ',0 mvi a,0ffh ; caps call bbline ; get user input call sblank ; skip to non-blank ora a ; no input? jz chprint ; done, so print directory mov a,m ; get first char cpi 'X' ; Exit? jz dsort ; if so, sort and then exit cpi '?' ; help? jnz ch1 call print db cr,lf db cr,lf,'MKDIR Change Mode --' db cr,lf,' You may issue the following commands at this point:' db cr,lf db cr,lf,' DU:dirname <-- Create/Rename Dir Entry' db cr,lf,' DU: <-- Delete Dir Entry' db cr,lf,' <-- Print Directory' db cr,lf,' X <-- Exit' db cr,lf,' ? <-- Print this Help' db cr,lf,0 jmp ch0 chprint: call dsort ; use dsort routine call dprint ; use dprint routine jmp ch0 ; continue ch1: lxi d,tfcb ; extract user and disk info as well as name call zfname ; get info jnz ch2 call print db cr,lf,'Error in Disk or User',0 jmp ch0 ch2: mov a,b ; current disk? cpi 0ffh jnz ch3 lda cdisk ; set disk mov b,a inr b ; add 1 for following decrement ch3: dcr b ; adjust disk to 0 to n-1 mov a,c ; current user? cpi 0ffh jnz ch4 lda cuser ; set user mov c,a ch4: mov a,b ; save as temp disk and user sta tdisk mov a,c sta tuser ; ; Scan Directory for Temp Disk and User ; lda ndnames ; get entry count mov b,a ; ... in B call codend ; pt to first entry scanud: inx h ; pt to name inx h mov a,m ; get first char of name dcx h dcx h ; pt to disk cpi ' ' ; deleted entry? jz scanud1 mov d,m ; get disk lda tdisk ; compare it cmp d jnz scanud1 inx h ; pt to user mov a,m ; get user dcx h ; pt back cmp c ; compare it jz udfound scanud1: lxi d,10 ; pt to next dad d dcr b ; count down jnz scanud lda tfcb+1 ; delete? cpi '?' ; ? if so jnz addname call print db cr,lf,' -- DU not found for Delete -- No Change Made',0 jmp ch0 ; ; Found Possible Directory Entry ; udfound: inx h ; found existing entry inx h ; pt to name lda tfcb+1 ; delete? cpi '?' ; ? if so jz delname ; ; Rename Function ; xra a ; clear add flag sta addflg call print db cr,lf,' Renaming ',0 mvi b,8 ; 8 chars push h ; save ptr call prfn1 ; print name pop h ; get ptr mvi m,' ' ; space fill jmp putname ; ; Add Function ; addname: mvi a,0ffh ; set add flag sta addflg call print db cr,lf,' Adding ',0 lxi h,tfcb+1 mvi b,8 call prfn1 lda ecount ; increment entry count inr a sta ecount putname: lda ndnames ; get entry count mov c,a ; ... in C call codend ; pt to first entry inx h ; pt to name inx h etest: lxi d,tfcb+1 ; pt to new name mvi b,8 ; 8 chars call compb ; compare jnz etest1 call print db cr,lf,' -- Error -- Duplicate Name Exists -- No Change Made',0 lda addflg ; add? ora a ; 0=no jz ch0 lda ecount ; count down dcr a sta ecount jmp ch0 etest1: lxi d,10 ; pt to next entry dad d dcr c ; count down jnz etest mvi a,0ffh ; change made sta chflag lda ndnames ; get entry count mov b,a ; ... in B call codend ; pt to first inx h ; pt to name inx h putn1: mov a,m ; valid entry? cpi ' ' ; empty? jnz putn2 dcx h ; pt to disk dcx h lda tdisk mov m,a inx h lda tuser mov m,a inx h lxi d,tfcb+1 ; pt to new name xchg mvi b,8 ; 8 chars call moveb call print db ' -- ',0 lda ecount ; print count mov b,a ; ... in B call padc call print db ' Entries in Directory, Room for ',0 lda ndnames sub b call padc call print db ' More',0 jmp ch0 ; continue putn2: lxi d,10 ; skip to next entry dad d dcr b ; count down jnz putn1 call print db cr,lf,'** Directory Full **',0 lda addflg ; adding? ora a ; 0=no jz ch0 lda ecount ; count down dcr a sta ecount jmp ch0 ; ; Delete Function ; delname: mvi a,0ffh ; change made sta chflag call print db cr,lf,' Deleting ',0 mvi b,8 ; 8 chars push h ; save ptr call prfn1 pop h ; get ptr mvi m,' ' ; space fill call dirpack ; pack directory call print db ' -- ',0 lda ecount ; print remaining count call padc call print db ' Entries Remaining',0 jmp ch0 ; continue ; ; Sort Directory ; dsort: call dirpack ; pack directory lda ecount ; number of elements ora a ; any? rz ; done if none sta ssbcnt ; set count call codend ; pt to first element shld ssbstrt ; set starting address lxi d,ssb ; pt to sort specifiction block call sort ; sort ret ; ; Sort Compare Routine ; compare: push h ; don't change regs push d ldax d ; compare disk cmp m jnz comp1 inx h ; pt to user inx d ldax d ; compare user cmp m comp1: pop d ; restore regs pop h ret ; ; Utilities ; ; ; Read and Write Chars to Disk ; getch: call f0$get ; get char rz ; OK since no error call print db cr,lf,'File Read Error -- Aborting',0 jmp mkdir1 ; goto command level putch: call f0$put ; put char rz ; OK since no error werr: call print db cr,lf,'Disk Write Error -- Aborting',0 call getud ; return home jmp mkdir1 ; ; Pack Memory-Based Directory ; dirpack: call codend ; get address of first entry mov d,h ; DE pts to it also mov e,l lda ndnames ; get max count mov b,a ; ... in B mvi c,0 ; set entry count dirp0: push b ; save counts inx h ; pt to name inx h mov a,m ; get char dcx h ; pt back to disk dcx h cpi ' ' ; no entry if space jz dirp1 mvi b,10 ; copy 10 bytes dirpm: mov a,m ; copy HL to DE for B bytes stax d inx h ; pt to next inx d dcr b ; count down jnz dirpm pop b ; get counts inr c ; 1 more entry jmp dirp2 dirp1: push d ; save new entry ptr lxi d,10 ; pt to next entry dad d pop d pop b ; get counts dirp2: dcr b ; count down jnz dirp0 mov a,c ; save count sta ecount lda ndnames ; make rest empty sub c ; number of entries remaining mov b,a ; ... in B ora a ; none? rz xchg ; HL pts to next entry inx h ; pt to name inx h lxi d,10 ; prep to add 10 dirp3: mvi m,' ' ; set space as first char dad d ; pt to next dcr b ; count down jnz dirp3 ret ; ; Skip until non-blank encountered ; sblank: mov a,m ; get char inx h ; pt to next cpi ' ' ; skip space jz sblank dcx h ; pt to char ret ; ; Print file name pted to by HL ; prfn: push b ; save regs push h mvi b,8 ; 8 chars call prfn1 mvi a,'.' call cout mvi b,3 ; 3 chars call prfn1 pop h ; get regs pop b ret prfn1: mov a,m ; print chars inx h ; pt to next call cout dcr b ; count down jnz prfn1 ret ; ; Sort Specification Block ; ssb: ssbstrt: ds 2 ; start address of dir ssbcnt: dw 0 ; number of records to sort dw 10 ; 10 bytes/record dw compare ; compare routine dw 0 ; no ptr table db 0,0 ; don't use ptrs ; ; Buffers ; cdisk: ds 1 ; current disk cuser: ds 1 ; current user tdisk: ds 1 ; temp disk tuser: ds 1 ; temp user flflag: ds 1 ; file loaded flag chflag: ds 1 ; dir changed flag ecount: ds 1 ; entry count addflg: ds 1 ; add/rename flag crcnt: ds 1 ; new line count tfcb: ds 36 ; temp FCB dfcb: ds 36 ; Default FCB ds 50 ; 25-elt stack stack: ds 2 ; original stack ptr end