; ; SYSLIB Module Name: SZFNAM ; Author: Richard Conn ; SYSLIB Version Number: 2.1 ; Module Version Number: 1.1 ; Module Entry Points: ; ZFNINIT ZFNAME ZDNAME ZDNFIND ; Module External References: ; CAPS FI3$CLOSE FI3$OPEN F3$GET ; INITFCB MOVEB ZPFIND BDOS ; ;* ;* ZFNAME is a file name scanner. Pointing to the first character ;* of a file name specification of the form 'dir:filename.typ', where ;* any part of this specification is optional, this routine fills in ;* an FCB with zeros, properly initializes the FN and FT (File Name and ;* File Type) fields if 'filename.typ' or any part thereof is present, ;* and returns the value of disk and user if they are specified ;* (or FFH if they are not). ;* The directory indicator 'dir:', if specified, may be of one of two forms: ;* DIRECT -- A named directory, of up to 8 chars in length ;* d -- A disk drive letter ;* u -- A user number ;* du -- A disk drive letter and a user number ;* The named directory form is checked first, so if a directory named ;* A or A10 exists, it matches, as opposed to Drive A or ;* drive/user A/10. ;* Examples: ;* HELP:*.HLP ;* A5:TEST.TXT ;* C?:ABC.* ;* PASCAL:*.COM ;* NOTE: It is the programmer's responsibility to have called and ;* properly initialized the buffers in the ZCPRINIT routine ;* in the SZCPR module ;* ;* ;* EXTERNALS ;* EXT BDOS ; BDOS UTILITY EXT MOVEB ; COPY UTILITY EXT INITFCB ; INIT FCB UTILITY EXT CAPS ; CAPITALIZE ROUTINE EXT ZPFIND ; FIND FILE ALONG PATH EXT FI3$OPEN ; BYTE-ORIENTED FILE I/O EXT FI3$CLOSE EXT F3$GET ;* ;* BASIC EQUATES ;* MAXDISK EQU 16 ; MAX NUMBER OF DISKS MAXUSER EQU 31 ; MAX USER NUMBER MAXNAME EQU 64 ; MAX NUMBER OF NAMES IN DIR FILE CPM EQU 0 ; CP/M ENTRY BENTRY EQU CPM+5 ; BDOS ENTRY CR EQU 0DH LF EQU 0AH ;* ;* INIT MODULE ;* IF THE USER WISHES TO CHANGE THE NAME OF THE DIRECTORY FILE TO LOOK ;* FOR, HE CALLS THIS ROUTINE, WITH THE FCB PTR IN DE ;* ;* IF THE USER WISHES TO CHANGE THE NUMBER OF DIRECTORY NAMES PERMITTED ;* IN THE DIRECTORY FILE, HE CALLS THIS ROUTINE, WITH THE NEW NAME ;* COUNT IN C ;* ;* THE SPECIFIC BUFFERED VALUES TO CHANGE ARE INDICATED BY THE A ;* REGISTER AS FOLLOWS: ;* BIT 7 -- SET NAME OF DIR FILE TO FCB PTED TO BY DE ;* BIT 6 -- SET MAX NUMBER OF DIRECTORY NAMES PERMITTED ;* ;* IF THIS MODULE IS NOT CALLED, THE FOLLOWING DEFAULT VALUES ARE ;* ASSUMED: ;* NAME OF DIRECTORY NAMES FILE -- NAMES.DIR ;* MAX NUMBER OF DIRECTORY NAMES -- 64 ;* ;* NO REGS ARE AFFECTED ;* ON INPUT, DE PTS TO NEW FCB ;* C IS THE MAX NUMBER OF DIRECTORY NAMES ;* A IS FLAG -- ;* BIT 7 SET (1) - LOAD DEFAULT FCB FROM DE ;* BIT 6 SET (1) - LOAD NAME COUNT FROM C ;* ZFNINIT:: PUSH H ; SAVE REGS PUSH D PUSH B PUSH PSW MOV B,A ; SAVE FLAG IN B ANI 80H ; LOOK AT BIT 7 JZ ZFNIN1 ; SKIP FCB LOAD IF BIT 7 = 0 PUSH B ; SAVE FLAG IN B XCHG ; HL PTS TO FCB LXI D,FNFCB ; PT TO MY FCB MVI B,12 ; COPY 12 BYTES CALL MOVEB ; COPY POP B ; GET FLAG IN B ZFNIN1: MOV A,B ; GET FLAG ANI 40H ; LOOK AT BIT 6 JZ ZFNIN2 ; SKIP NAMES LOAD IF BIT 6 = 0 MOV A,C ; GET COUNT STA MAXN ; STORE IN BUFFER ZFNIN2: POP PSW ; RESTORE REGS POP B POP D POP H RET ; ; FCB USED BY ZFNAME ; MAXN: DB MAXNAME ; INIT TO MAXNAME FNFCB: DB 0,'NAMES DIR',0,0,0,0 ; INIT TO NAMES.DIR DS 16 DS 4 ;* ;* MAIN MODULE ;* ON ENTRY, DE PTS TO FCB TO BE FILLED AND HL PTS TO FIRST BYTE OF ;* TARGET STRING; FCB IS 36 BYTES LONG ;* ON EXIT, B=DISK NUMBER (1 FOR A, ETC) AND C=USER NUMBER ;* HL PTS TO TERMINATING CHAR ;* A=0 AND Z SET IF ERROR IN DISK OR USER NUMBERS, A=0FFH AND NZ ;* IF OK ;* ZFNAME:: PUSH D ; SAVE DE PUSH H ; SAVE HL XCHG ; SAVE PTR TO FCB SHLD FCBPTR XCHG ; DE PTS TO FCB POP H ; GET HL MVI A,0FFH ; SET DEFAULT DISK AND USER STA DISK STA USER ; FILL TARGET FCB WITH ZEROES MVI B,36 ; INIT FCB XRA A ; A=0 FNINI: STAX D ; STORE ZERO INX D ; PT TO NEXT DCR B ; COUNT DOWN JNZ FNINI ; SCAN FOR COLON IN STRING PUSH H ; SAVE PTR TO TARGET STRING COLON: MOV A,M ; SCAN FOR COLON OR SPACE CPI ':' ; COLON FOUND? JZ COLON1 CALL DELCK ; DELIMITER FOUND? JZ GETF1 INX H ; PT TO NEXT JMP COLON ; CONTINUE IF NOT END OF LINE ; WE HAVE FOUND A COLON, SO THERE IS A DIR: PREFIX COLON1: POP H ; GET PTR TO FIRST CHAR MVI A,0FFH ; ALLOW DU: FORM CALL ZDNFIND ; SCAN FOR DIRECTORY NAME; RETURN DISK IN DISK, JNZ GETFILE ; USER IN USER, NZ IF OK, HL PTS TO COLON XRA A ; ERROR INDICATOR POP D ; RESTORE DE RET ; EXTRACT FILE NAME GETF1: POP H ; GET PTR TO BYTE GETFILE: XCHG ; GET PTR TO FCB LHLD FCBPTR XCHG ; HL PTS TO TARGET STRING, DE PTS TO FCB MOV A,M ; PTING TO COLON? CPI ':' JNZ GFILE1 INX H ; SKIP OVER COLON GFILE1: CALL DELCK ; GET NEXT CHAR AND CHECK FOR A DELIMITER JNZ GFILE2 ; PROCESS SINCE NOT A DELIMITER CPI '.' ; WAS DELIMITER A '.'? JZ GFILE2 ; PROCESS SINCE FN MISSING ; NO NAME SPECIFIED, SO MAKE IT WILD GFQUES: INX D ; FILL WITH '?' MVI B,11 ; 11 BYTES MVI A,'?' GFFILL: STAX D ; PUT ? INX D ; PT TO NEXT DCR B ; COUNT DOWN JNZ GFFILL ; EXIT ZFNAME FNDONE: LDA DISK ; GET DISK NUMBER CPI 0FFH ; CURRENT DISK? JZ FNDN1 INR A ; ADD 1 SO IN THE RANGE FROM 1 TO 16 FNDN1: MOV B,A ; ... IN B LDA USER ; GET USER NUMBER MOV C,A ; ... IN C POP D ; RESTORE REGS MVI A,0FFH ; NO ERROR ORA A ; SET FLAGS RET ; GET FILE NAME FIELDS GFILE2: MVI B,8 ; AT MOST 8 BYTES FOR FN CALL SCANF ; SCAN AND FILL MVI B,3 ; AT MOST 3 BYTES FOR FT MOV A,M ; GET DELIMITER CPI '.' ; FN ENDING IN '.'? JNZ GFILE3 INX H ; PT TO CHAR AFTER '.' CALL SCANF ; SCAN AND FILL JMP FNDONE ; DONE ... RETURN ARGS ; FT FIELD NOT GIVEN, SO FILL FT FIELD IN FCB GFILE3: CALL SCANF4 ; FILL WITH JMP FNDONE ; ; SCANNER ROUTINE ; SCANF: CALL DELCK ; CHECK FOR DELIMITER JZ SCANF4 ; FILL IF FOUND INX D ; PT TO NEXT BYTE IN FN CPI '*' ; ? FILL? JNZ SCANF1 MVI A,'?' ; PLACE '?' STAX D JMP SCANF2 SCANF1: STAX D ; PLACE CHAR INX H ; PT TO NEXT POSITION SCANF2: DCR B ; COUNT DOWN JNZ SCANF ; CONTINUE LOOP SCANF3: CALL DELCK ; "B" CHARS OR MORE - SKIP TO DELIMITER RZ INX H ; PT TO NEXT JMP SCANF3 SCANF4: INX D ; PT TO NEXT FN OR FT MVI A,' ' ; FILL STAX D DCR B ; COUNT DOWN JNZ SCANF4 RET ;* ;* ZDNAME -- LOAD THE CONTENTS OF THE NAMES.DIR FILE INTO THE MEMORY ;* BUFFER PTED TO BY HL ;* ON ENTRY, HL PTS TO THE MEMORY BUFFER EXTENDING TO THE BASE OF ;* THE BDOS ;* ON EXIT, HL PTS TO THE FIRST ENTRY IN THE NAMES.DIR FILE, BC IS ;* THE NUMBER OF VALID ENTRIES, A IS THE ERROR FLAG (A=0FFH ;* AND NZ IF NO ERROR, A=0 AND Z IF ERROR) ;* ERRORS MAY BE EITHER MEMORY OVERFLOW OR NAMES.DIR ;* NOT FOUND ;* EACH NAMES.DIR ENTRY IS 10 BYTES LONG, STRUCTURED AS FOLLOWS: ;* BYTE 0: DISK NUMBER (A=0) ;* BYTE 1: USER NUMBER ;* BYTES 2-9: DIRECTORY NAME, 8 CHARS MAX, FILL AT END ;* ZDNAME:: PUSH D ; SAVE UNCHANGED REG SHLD DIRNAME ; SAVE PTR TO BUFFER SHLD CURNAME ; SAVE PTR TO FIRST ENTRY LXI D,FNFCB ; PT TO FCB WHICH CONTAINS DIR FILE NAME CALL INITFCB ; INIT FCB MVI B,0FFH ; SEARCH CURRENT USER CALL ZPFIND ; LOOK FOR NAMES.DIR FILE JZ DIRNERR ; FILE NOT FOUND ERROR ; ; FOUND NAMES.DIR, SO LOAD IT ; CALL PUTUD ; SAVE CURRENT USER/DISK CALL LOGUD ; LOG IN NEW USER/DISK LXI D,FNFCB ; PT TO FCB CALL FI3$OPEN ; OPEN FOR INPUT ; ; LOAD NAMES.DIR FILE ; MVI C,0 ; SET ENTRY COUNT LDA MAXN ; GET MAX NUMBER OF NAMES MOV B,A ; ... IN B ZDNA1: LXI H,ENTRY ; PT TO ENTRY BUFFER CALL GETNAME ; GET NAME FROM DISK JNZ ZDNA3 ; DONE? LDA ENTRY+2 ; LOOK AT FIRST LETTER OF DIR NAME ORA A ; NO ENTRY? JZ ZDNA2 LHLD DIRNAME ; PT TO BUFFER ENTRY LXI D,ENTRY ; PT TO NEW ENTRY INR C ; INCREMENT ENTRY COUNTER PUSH B ; SAVE COUNTERS XCHG ; HL PTS TO NEW ENTRY, DE PTS TO DEST MOV A,M ; GET DISK NUMBER STAX D ; STORE DISK NUMBER INX H ; PT TO USER NUMBER INX D MOV A,M ; GET USER STAX D ; PUT USER MVI B,8 ; AT MOST 8 MORE BYTES ZDNA1A: INX H ; PT TO NEXT BYTE INX D MOV A,M ; GET NEXT BYTE ORA A ; END OF NAME? JZ ZDNA1B ; FILL STAX D ; PUT BYTE DCR B ; COUNT DOWN JNZ ZDNA1A INX D ; PT TO FIRST BYTE OF NEXT ENTRY JMP ZDNA1C ZDNA1B: MVI A,' ' ; FILL STAX D ; PLACE INX D ; PT TO NEXT DCR B ; COUNT DOWN JNZ ZDNA1B ZDNA1C: POP B ; RESTORE COUNTERS LHLD BENTRY+1 ; PT TO BDOS ADDRESS MOV A,H ; CHECK FOR PAGE BEFORE BDOS DCR A ; PAGE BEFORE CMP D ; ARE WE THERE? JZ DNSC2 ; ERROR IF SO, BUT RESTORE UD JC DNSC2 XCHG ; HL PTS TO NEXT BUFFER POSITION SHLD DIRNAME ; SAVE PTR ; ; CONTINUE LOOPING ; ZDNA2: DCR B ; COUNT DOWN JNZ ZDNA1 ; ; COMPLETION EXIT ; ZDNA3: CALL GETUD ; RESTORE USER/DISK MVI B,0 ; SET HIGH-ORDER BYTE LHLD CURNAME ; GET PTR TO FIRST ENTRY MVI A,0FFH ; SET NO ERROR ORA A ; SET FLAGS POP D ; RESTORE DE RET ;* ;* ZDNFIND -- SCAN FOR POSSIBLE DISK DIRECTORY NAME ;* THIS ROUTINE EXAMINES THE DIR: PREFIX FOR EITHER A DIRECTORY NAME ;* OR THE DU FORM ;* ON ENTRY, HL PTS TO DIRECTORY NAME ENDING IN ANY VALID DELIMITER ;* AND A=0 IF DU: FORM NOT ALLOWED (JUST DIR: FORM ALLOWED) ;* RETURN DISK IN B, USER IN C, NZ IF OK, HL PTS TO COLON ;* DE IS NOT AFFECTED ;* ZDNFIND:: PUSH D ; SAVE DE SHLD DIRNAME ; SAVE DIRECTORY NAME AWAY ORA A ; DU: FORM ALLOWED? JNZ SVDISK ; SCAN FOR DU: FORM FIRST ; ; LOOK FOR DIR: FORM ; NAME: LXI D,FNFCB ; PT TO FCB WHICH CONTAINS DIR FILE NAME CALL INITFCB ; INIT FCB ; ; LOOK FOR DIR NAME FILE ; LHLD DIRNAME ; PT TO DIRECTORY NAME MVI B,0FFH ; SEARCH CURRENT USER CALL ZPFIND ; LOOK FOR NAME FILE JZ DIRNERR ; ERROR IF NOT FOUND ; ; FOUND DIR NAME FILE, SO LOAD IT AND SCAN IT FOR TARGET NAME ; CALL PUTUD ; SAVE CURRENT USER/DISK CALL LOGUD ; LOG IN NEW USER/DISK LXI D,FNFCB ; PT TO FCB CALL FI3$OPEN ; OPEN FOR INPUT ; ; LOAD DIR NAME FILE ENTRIES ; LDA MAXN ; GET MAXIMUM NUMBER OF NAMES MOV B,A ; ... IN B DNSC1: LXI H,ENTRY ; PT TO ENTRY BUFFER CALL GETNAME ; GET NAME FROM DISK JNZ DNSC2 ; ERROR EXIT? CALL SCANAME ; SCAN FOR DIR NAME JZ DNSC3 ; FOUND ENTRY, SO GET VALUES DCR B ; COUNT DOWN JNZ DNSC1 DNSC2: CALL GETUD ; RESTORE CURRENT USER/DISK JMP DIRNERR ; ERROR SINCE NO ENTRY FOUND ; ; DIR NAME FOUND, SO GET DISK AND USER INFORMATION ; DNSC3: CALL GETUD ; RESTORE CURRENT USER/DISK MOV A,M ; GET DISK (HL PTS TO CURRENT ENTRY) STA DISK ; SAVE DISK INX H ; PT TO USER MOV A,M ; GET USER STA USER ; SAVE USER ; ; SKIP TO COLON AFTER DIR NAME ; LHLD DIRNAME ; PT TO DIR NAME DNSC4: CALL DELCK ; SKIP TO DELIMITER JZ DIRNX ; EXIT IF SO INX H ; PT TO NEXT JMP DNSC4 ; ; LOOK AT START OF DU: FORM ; ON ENTRY, HL PTS TO FIRST CHAR OF DIRECTORY NAME ; SVDISK: MOV A,M ; GET DISK LETTER CALL CAPS ; CAPITALIZE LETTER CPI 'A' ; DIGIT? JC USERCK ; IF NO DIGIT, MUST BE USER OR COLON SUI 'A' ; CONVERT TO NUMBER CPI MAXDISK ; LIMIT? JNC NAME ; NAME IF OUT OF LIMIT STA DISK ; SAVE FLAG INX H ; PT TO NEXT CHAR ; ; CHECK FOR USER ; USERCK: MOV A,M ; GET POSSIBLE USER NUMBER CPI ':' ; NO USER NUMBER JZ DIRNX ; EXIT IF SO CPI '?' ; ALL USER NUMBERS? JNZ USERC1 STA USER ; SET VALUE INX H ; PT TO AFTER MOV A,M ; MUST BE COLON CPI ':' JZ DIRNX ; EXIT JMP DIRNERR ; FATAL ERROR IF NOT COLON AFTER ? USERC1: XRA A ; ZERO USER NUMBER MOV B,A ; B=ACCUMULATOR FOR USER NUMBER USRLOOP: MOV A,M ; GET DIGIT INX H ; PT TO NEXT CPI ':' ; DONE? JZ USRDN SUI '0' ; CONVERT TO BINARY JC NAME ; NAME IF USER NUMBER ERROR CPI 10 JNC NAME MOV C,A ; NEXT DIGIT IN C MOV A,B ; OLD NUMBER IN A ADD A ; *2 ADD A ; *4 ADD B ; *5 ADD A ; *10 ADD C ; *10+NEW DIGIT MOV B,A ; RESULT IN B JMP USRLOOP USRDN: MOV A,B ; GET NEW USER NUMBER CPI MAXUSER ; WITHIN RANGE? JNC NAME ; NAME IF OUT OF RANGE STA USER ; SAVE IN FLAG ; ; VALID EXIT -- FOUND IT, SO LOAD BC AND EXIT FLAG; ON ENTRY, HL PTS TO : ; DIRNX: LDA USER ; RETURN USER IN C, DISK IN B MOV C,A LDA DISK MOV B,A INR B ; DISK A = 1 MVI A,0FFH ; SET NO ERROR ORA A ; SET FLAGS POP D ; RESTORE DE RET ; ; INVALID EXIT -- NOT FOUND OR ERROR ; NO VALID RETURN PARAMETERS (BC, HL) ; DIRNERR: XRA A ; ERROR CODE POP D ; RESTORE DE RET ;* ;* BUFFERS ;* FCBPTR: DS 2 ; PTR TO FCB DISK: DS 1 ; DISK NUMBER USER: DS 1 ; USER NUMBER ENTRY: DS 11 ; ENTRY FROM DISK FILE (DISK, USER, DIR NAME) DIRNAME: DS 2 ; PTR TO DIRECTORY NAME CURNAME: DS 2 ; PTR TO CURRENT LOCATED NAME ; ; SCAN DIRECTORY ENTRY PTED TO BY HL FOR DIRECTORY NAME STARTING AT DIRNAME ; RETURN WITH Z IF FOUND; DO NOT AFFECT BC ; SCANAME: PUSH B ; SAVE BC SHLD CURNAME ; SET CURRENT NAME PTR INX H ; SKIP DISK INX H ; SKIP USER MVI B,9 ; UP TO 9 CHARS XCHG ; CURRENT PTR IN DE LHLD DIRNAME ; PT TO TARGET NAME SCANL: LDAX D ; GET CHAR ORA A ; END OF STRING? JZ SCANL2 MOV C,A ; SAVE IN C MOV A,M ; GET TARGET NAME CHAR CALL CAPS ; CAPITALIZE IT CMP C ; COMPARE JNZ SCANL1 ; ABORT IF NO MATCH CALL DELCK ; END OF TARGET NAME? JZ SCANL1 ; ABORT IF SO INX H ; PT TO NEXT INX D DCR B ; COUNT DOWN JNZ SCANL ; NOT FOUND RETURN SCANL1: LHLD CURNAME ; PT TO CURRENT ENTRY LXI B,11 ; SKIP 11 BYTES DAD B ; PT TO NEXT ENTRY POP B ; RESTORE BC MVI A,0FFH ; NOT FOUND FLAG ORA A ; SET FLAGS RET ; FOUND RETURN SCANL2: CALL DELCK ; MUST PT TO DELIMITER IF MATCH JNZ SCANL1 ; ABORT IF NOT LHLD CURNAME ; PT TO FOUND ENTRY POP B ; RESTORE BC XRA A ; FOUND RET ; ; GET NAME FROM FILE 3 INTO BUFFER PTED TO BY HL ; DO NOT AFFECT BC OR HL; RET W/NZ IF ERROR ; GETNAME: PUSH B ; SAVE BC PUSH H ; SAVE HL CALL F3$GET ; GET DISK LETTER JNZ GNERR ; ERROR? SUI 'A' ; CONVERT TO NUMBER MOV M,A ; STORE IT INX H ; PT TO NEXT MVI B,10 ; GET USER AND DIRECTORY NAME GETN1: CALL F3$GET ; GET BYTE JNZ GNERR ; ERROR? MOV M,A ; STORE IT INX H ; PT TO NEXT DCR B ; COUNT DOWN JNZ GETN1 XRA A ; OK GNERR: POP H ; RESTORE HL POP B ; RESTORE BC RET ; ; CHECK CHAR PTED TO BY HL FOR A DELIMITER ; RET WITH Z FLAG SET IF DELIMITER ; DELCK: MOV A,M ; GET CHAR CALL CAPS ; CAPITALIZE ORA A ; 0=DELIM RZ CPI ' '+1 ; +1 JC DELCK1 ; OR LESS CPI '=' RZ CPI 5FH ; UNDERSCORE RZ CPI '.' RZ CPI ':' RZ CPI ';' RZ CPI ',' RZ CPI '<' RZ CPI '>' RET DELCK1: CMP M ; COMPARE WITH SELF FOR OK RET ; ; PUTUD -- SAVE CURRENT USER/DISK FOR LATER RESTORE ; NO REGS AFFECTED ; PUTUD: PUSH B ; SAVE REGS PUSH PSW PUSH D PUSH H MVI C,25 ; GET CURRENT DISK CALL BDOS STA CDISK ; SET CURRENT DISK MVI E,0FFH ; GET USER MVI C,32 ; GET CURRENT USER CALL BDOS STA CUSER ; SET CURRENT USER POP H ; RESTORE REGS POP D POP PSW POP B RET ; ; BUFFERS ; CDISK: DS 1 ; CURRENT DISK CUSER: DS 1 ; CURRENT USER ; ; GETUD -- RESTORE USER/DISK FROM PREVIOUS PUTUD ; GETUD: PUSH H ; SAVE REGS PUSH D PUSH B PUSH PSW LDA CDISK ; SELECT DISK MOV E,A MVI C,14 ; SELECT CALL BDOS LDA CUSER ; SELECT USER MOV E,A MVI C,32 ; SELECT CALL BDOS DONE: POP PSW ; GET REGS POP B POP D POP H RET ; ; LOGUD -- LOG IN USER/DISK, WHICH C=USER AND B=DISK ; LOGUD: PUSH H ; SAVE REGS PUSH D PUSH B PUSH PSW MOV E,C ; SELECT USER MVI C,32 CALL BDOS MOV E,B ; SELECT DISK MVI C,14 CALL BDOS JMP DONE END