.TITLE TIOENC EN COMMAND .SBTTL EN COMMAND ; LAST EDIT ON 13-MAR-80 BY MARK BRAMHALL .IDENT /V36/ .MCALL .DSTAT, .LOOKUP,.PURGE, .READW, .REOPEN,.SAVESTATUS .SBTTL DIRECTORY ENTRY LAYOUT .DSECT ;DIRECTORY ENTRY LAYOUT EN.STS: .BLKW ;STATUS WORD EN.NAM: .BLKW 2 ;FILENAME (RAD50) EN.TYP: .BLKW ;FILE TYPE (RAD50) EN.LEN: .BLKW ;FILE LENGTH .BLKW ;CREATING JOB/CHANNEL EN.DAT: .BLKW ;FILE CREATION DATE EN$SIZ: ;BASE SIZE OF DIRECTORY ENTRY IN BYTES .BSECT HIGH ;STATUS BITS IN "EN.STS" S.TENT: .BLKB . ;TENTATIVE FILE S.EMPT: .BLKB . ;EMPTY ENTRY S.PERM: .BLKB . ;PERMANENT FILE S.END: .BLKB . ;DUMMY END ENTRY .BLKB . ;RESERVED .BLKB . ;RESERVED .BLKB . ;RESERVED .BLKB . ;RESERVED .SBTTL SAVED DATA LAYOUT .EQUATE NAMSIZ, 14. ;SIZE OF FILENAME PATTERN INCLUDING ENDING NULL .EQUATE TYPSIZ, 8. ;SIZE OF FILE TYPE PATTERN INCLUDING ENDING NULL .EQUATE ENSIZE, <2+<5*2>+2+2+2+NAMSIZ+TYPSIZ> ;SIZE OF "EN" SAVED DATA .GLOBL ENSIZE ; GLOBALIZED FOR INITIALIZATION .DSECT -ENSIZE ;SAVED DATA LAYOUT FROM "HANDLR" BLOCK: .BLKW ;CURRENT DIRECTORY BLOCK NUMBER SAVERG: .BLKW 5 ;SAVESTATUS REGION HIGH: .BLKW ;HIGHEST ACTIVE DIRECTORY SEGMENT NUMBER ENTRY: .BLKW ;CURRENT DIRECTORY ENTRY NUMBER DEVICE: .BLKW ;DEVICE NAME (RAD50) NAME: .BLKB NAMSIZ ;WILD CARDED FILENAME STRING TO MATCH TYPE: .BLKB TYPSIZ ;WILD CARDED FILE TYPE STRING TO MATCH ;START OF OUR PRIVATE READ/WRITE AREA ("HANDLR") .ASSUME . EQ 0 .SBTTL PROCESS A "EN" REQUEST ;+ ; WILD - DO "EN". ; ; CALL WILD ;- ORG TECOIO WILD:: SAVREG ;SAVE ALL REGISTERS .PURGE #14. ;ENSURE OUR CHANNEL IS FREE MOV R5,R1 ;COPY THE READ/WRITE AREA POINTER ADD #HANDLR-ENSIZE,R1 ; AND FIND OUR PRIVATE SAVE AREA MOV FILBUF(R5),R3 ;GET FILENAME BUFFER POINTER TSTB (R3) ;GET NEXT OCCURANCE (NULL STRING)? BNE SETUP ;NOPE, SET UP A NEW WILD CARDED SPECIFICATION .BR GETNXT ;YEP, GET NEXT OCCURANCE OF WILD CARDED SPEC .SBTTL GET NEXT OCCURANCE OF WILD CARDED SPECIFICATION .ENABL LSB GETNXT: TST (R1)+ ;IS THERE REALLY ANYTHING SET UP? BEQ 70$ ;NOPE, SAY "NOT FOUND"... .ASSUME BLOCK EQ -ENSIZE .REOPEN #AREA,#14.,R1 ;RE-OPEN THE DIRECTORY CHANNEL .ASSUME SAVERG EQ BLOCK+2 BCS 80$ ;WHOOPS, SOME ERROR... TST DIRBUF ;IS THERE SOMETHING ALREADY IN THE BUFFER? BNE 20$ ;YES, WE DON'T NEED TO (RE-)READ THE SEGMENT 10$: .READW #AREA,#14.,#DIRBUF,#2000/2,BLOCK-SAVERG(R1) ;DO THE READ BCS 80$ ;WHOOPS, SOME ERROR TST HIGH-SAVERG(R1) ;DO WE KNOW THE HIGHEST ACTIVE SEGMENT? BNE 20$ ;YES, WE'VE BEEN THROUGH HERE BEFORE MOV HD$HGH,HIGH-SAVERG(R1) ;NO, SET HIGHEST ACTIVE SEGMENT 20$: MOV #EN$SRT,R2 ;POINT TO START OF DIRECTORY ENTRIES MOV ENTRY-SAVERG(R1),R4 ;GET NUMBER OF ENTRIES TO SKIP BR 50$ ; AND ENTER THE ENTRY SKIPPING LOOP 30$: CLR R4 ;PRE-SET WANTING NEXT ENTRY SINCE NO MATCH 40$: ADD #EN$SIZ,R2 ;SKIP THE STANDARD PART OF THE ENTRY ADD HD$EXT,R2 ; AND ANY EXTRA INFORMATION 50$: BIT (R2),#S.PERM ;PERMANENT ENTRY? BNE 60$ ;YES BIT (R2),#S.END ;NO, IS IT THE END? BEQ 40$ ;NOPE, IT'S EITHER TENTATIVE OR EMPTY, SKIP IT MOV HD$NXT,R0 ;YEP, GET LINK TO NEXT DIRECTORY SEGMENT BEQ 70$ ;NO MORE... CMP R0,HIGH-SAVERG(R1) ;MORE, BUT IS IT ACTIVE? BHI 70$ ;NOPE, SO REALLY NO MORE... ASL R0 ;CONVERT A SEGMENT NUMBER CMP (R0)+,(R0)+ ; INTO A BLOCK NUMBER (#0=>6, #1=>10, ETC.) MOV R0,BLOCK-SAVERG(R1) ; AND SET THE BLOCK NUMBER MOV R4,ENTRY-SAVERG(R1) ;(RE-)SAVE NUMBER OF ENTRIES TO SKIP BR 10$ ;GO READ NEXT DIRECTORY SEGMENT 60$: DEC R4 ;HAVE WE SKIPPED ENOUGH YET? BPL 40$ ;NOPE, CONTINUE SKIPPING... CALL CHKENT ;YEP, GO TRY FOR A MATCH INC ENTRY-SAVERG(R1) ;BUMP NUMBER OF ENTRIES TO SKIP THE NEXT TIME BCS 30$ ;NOT A MATCH, CONTINUE WITH NEXT ENTRY .SAVESTATUS #AREA,#14.,R1 ;SAVE THE CHANNEL'S STATUS AGAIN RETURN ; AND EXIT 70$: CALL 90$ ;DO SOME CLEAR UP ERR FNF,<"File not found"> 80$: CALL 90$ ;DO SOME CLEAR UP ERR DIO,<"Directory I/O error"> 90$: .PURGE #14. ;ENSURE THE CHANNEL GETS FREED UP CLR -(R1) ; AND THAT WE ALWAYS SAY NOT FOUND FROM NOW ON .ASSUME BLOCK EQ SAVERG-2 CLRB (R3) ; AND THAT WE RETURN A NULL SPECIFICATION RETURN ;EXIT .DSABL LSB .SBTTL SET UP A NEW WILD CARDED SPECIFICATION .ENABL LSB SETUP: MOV #ENSIZE/2,R0 ;SET COUNT FOR CLEARING WHOLE AREA 10$: CLR (R1)+ ;CLEAR DEC R0 ; THE BNE 10$ ; WHOLE AREA CLR DIRBUF ;ENSURE NOTHING'S IN THE DIRECTORY BUFFER MOV #100000,R2 ;SAY NO ":" OR "." FOUND YET 20$: MOV (PC)+,R0 ;DEFAULT DEVICE NAME TO "DK:" .RAD50 /DK/ 30$: MOV R5,R1 ;COPY THE READ/WRITE AREA POINTER ADD #HANDLR+DEVICE,R1 ; AND POINT AT WORD FOR DEVICE NAME MOV R0,(R1)+ ;LOAD THE DEVICE NAME & POINT AT WILD FILENAME .ASSUME NAME EQ DEVICE+2 MOV #NAMSIZ-1,R0 ;SET MAXIMUM SIZE OF WILD FILENAME 40$: MOV #LEGALS,R4 ;GET LIST OF SPECIAL/LEGAL STUFF MOVB (R3)+,(R1) ;GET NEXT CHARACTER FROM SPECIFICATION BICB (R4)+,(R1) ; TRIMMED TO 7-BIT ASCII BEQ 150$ ;END OF SPECIFICATION CMPB (R1),(R4)+ ;HAVE WE JUST LOADED A DEVICE NAME(":")? BNE 80$ ;NOPE ADD #100000,R2 ;YEP, SECOND ":" OR "." ALREADY SEEN? BNE 130$ ;ONE OR THE OTHER, THAT IS AN ERROR CALL 200$ ;GET FILENAME POINTER, CHECK FOR NULL BCC 20$ ;DEVICE NAME (FILENAME) IS NULL, GO DEFAULT IT CLR R0 ;CLEAR A RAD50 BUCKET 50$: MOVB (R4)+,R1 ;GET NEXT CHARACTER BNE 60$ ;ONE EXISTS CMP R0,#50*50 ;NO MORE, HAVE WE FORMED A VALID RAD50 WORD? BHIS 30$ ;YEP, ALL SET, GO SET DEVICE AND (RE-)LOOP... DEC R4 ;NOPE, ENSURE WE SEE THE ENDING NULL NEXT TIME BR 70$ ;GO MULTIPLY OLD BY 50 AND ADD IN A ZERO 60$: SUB #'A-1,R1 ;MAKE ALPHABETIC INTO RAD50 (1-32) CMP R1,#'Z-<'A-1> ; AND CHECK FOR ALPHABETIC BLOS 70$ ;IT'S AN ALPHABETIC SUB #'0-<'A-1>,R1 ;MAKE A DIGIT INTO BINARY CMP R1,#9. ; AND CHECK FOR DIGIT RANGE BHI 180$ ;NOT A DIGIT, IT'S AN ILLEGAL DEVICE NAME ADD #36,R1 ;IT'S A DIGIT, MAKE RAD50 (36-47) 70$: ASL R0 ;MULTIPLE ASL R0 ; OLD ASL R0 ; BY 10 ADD R0,R1 ;ADD OLD *10 TO NEW CODE ASL R0 ;NOW OLD ASL R0 ; *40 ADD R1,R0 ;ADD BACK OLD *10 AND NEW CODE BR 50$ ; AND LOOP... 80$: CMPB (R1),(R4)+ ;IS THIS A JUNKY CHARACTER? BLOS 40$ ;YEP, JUST IGNORE IT... CMPB (R1),(R4)+ ;LOWER CASE? BLO 90$ ;NOPE BICB #40,(R1) ;YEP, MAKE IT INTO UPPER CASE (DIRTY...) 90$: CMPB (R1),(R4)+ ;IS IT A SPECIAL CHARACTER? BEQ 110$ ;YES TSTB (R4) ;NO, MORE IN THE SPECIAL CHARACTER LIST? BNE 90$ ;THERE'S MORE, CONTINUE CHECKING... INC R4 ;NO MORE, SKIP THE TERMINATING NULL 100$: CMPB (R1),(R4)+ ;IS IT TOO LOW FOR THIS RANGE? BLO 130$ ;YES, THAT'S AN ERROR CMPB (R1),(R4)+ ;MIGHT BE O.K. BHI 100$ ;OUT-OF-RANGE, CONTINUE CHECKING... 110$: TSTB (R4) ;IS IT REALLY "."? BEQ 140$ ;YEP 120$: INC R1 ;KEEP THE CHARACTER DEC R0 ;INDICATE ANOTHER CHARACTER STORED BPL 40$ ;STILL ENOUGH ROOM, CONTINUE 130$: ERR IFN,<"Illegal file name"> 140$: COMB R2 ;INDICATE "." FOUND BEQ 130$ ;WHOOPS, TWO "."'S, AN ERROR CALL 200$ ;CHECK FOR NULL FILENAME, DEFAULT IT IF NULL ADD #HANDLR+TYPE,R1 ;FORM POINTER TO THE FILE TYPE STRING MOV #TYPSIZ-1,R0 ;SET MAXIMUM SIZE OF WILD FILE TYPE BR 40$ ;NOW LOOP FOR THE FILE TYPE... 150$: COMB R2 ;DID WE FIND A "."? BEQ 160$ ;YES MOV #'*,HANDLR+TYPE(R5) ;NO, DO FILE TYPE DEFAULTING 160$: CALL 200$ ;CHECK FOR NULL FILENAME, DEFAULT IT IF NULL ADD #HANDLR+SAVERG,R1 ;FORM POINTER TO SAVESTATUS REGION MOV DEVICE-SAVERG(R1),(R1) ;MOVE DEVICE NAME UP TO IT MOV #AREA,R4 ;GET POINTER TO DEVICE INFORMATION BUCKET .DSTAT R4,R1 ;GET INFORMATION ABOUT THE DEVICE BCS 180$ ;IT IS AN ILLEGAL DEVICE NAME TST (R4) ;IS IT A RANDOM-ACCESS DEVICE? BPL 180$ ;NOPE, WE CAN'T HANDLE IT TST 4(R4) ;IS THE DEVICE HANDLER ALREADY RESIDENT? BNE 170$ ;YEP CALLX FETCH ;NOPE, GO FETCH A DEVICE HANDLER BCS 190$ ;WHOOPS, SOME ERROR FETCHING THE HANDLER 170$: .LOOKUP #AREA,#14.,R1 ;OPEN THE DEVICE NON-FILE STRUCTURED BCS 180$ ;ERROR??? .SAVESTATUS #AREA,#14.,R1 ;SAVE THE CHANNEL'S STATUS MOV #6,-(R1) ;START @ DIRECTORY BLOCK NUMBER 6 (SEG #1) .ASSUME BLOCK EQ SAVERG-2 RETURN ; AND EXIT 180$: .PURGE #14. ;ENSURE THE CHANNEL GETS FREED UP ERR DEV,<"Invalid device"> 190$: .PURGE #14. ;ENSURE THE CHANNEL GETS FREED UP ERR FET,<"Handler fetch error"> 200$: CLRB (R1) ;TERMINATE THE FILENAME STRING WITH A NULL MOV R5,R4 ;COPY THE READ/WRITE AREA POINTER ADD #HANDLR+NAME,R4 ; AND POINT TO THE FILENAME STRING CMP R4,R1 ;DO WE HAVE A NON-NULL FILENAME STRING? BLO 210$ ;YES, GO EXIT C=1 ('BLO' = 'BCS') MOV #'*,(R4) ;NO, DEFAULT THE FILENAME 210$: MOV R5,R1 ;LOAD POINTER TO READ/WRITE AREA AS A SERVICE RETURN ;EXIT W/ C=0 IF NULL (& DEFAULTED) FILENAME .DSABL LSB TMPORG TIOTXT LEGALS: .BYTE ^C<177> ;TRIM FOR 7-BIT ASCII .ASCII ":" ;":" => END OF A DEVICE NAME .BYTE SPACE ;CHECK FOR JUNKY CHARACTERS .BYTE 140 ;CHECK FOR LOWER CASE (DIRTY...) .ASCIZ "%*." ;LEGAL SPECIAL CHARACTERS .ASCII "09" ;DIGITS ARE O.K. .ASCII "AZ" ;ALPHABETICS ARE O.K. .BYTE -1 ;END'S THE RANGE LIST UNORG .SBTTL CHECK A DIRECTORY ENTRY ;+ ; R1 -> "EN" SAVED DATA @ SAVERG ; R2 -> DIRECTORY ENTRY ; R3 -> FILENAME BUFFER W/ GARBAGE ; ; CALL CHKENT ; ; R0 = UNDEFINED ; R3 -> FILENAME BUFFER W/ FILE'S DEV:FILNAM.TYP ; R4 = UNDEFINED ; ; IF C=1 ('BCS') THEN NO MATCH ; IF C=0 ('BCC') THEN A MATCH ;- CHKENT: MOV R2,-(SP) ;SAVE POINTER TO DIRECTORY ENTRY MOV DEVICE-SAVERG(R1),R0 ;GET THE DEVICE NAME (RAD50) CALL 50$ ; AND CONVERT IT INTO ASCII MOVB #':,(R3)+ ; THEN TERMINATE IT WITH A ":" MOV R3,-(SP) ;SAVE POINTER TO FILE NAMING STRING TST (R2)+ ;INDEX TO FILENAME .ASSUME EN.NAM EQ 2 CALL 30$ ; AND CONVERT IT INTO ASCII MOV R3,-(SP) ;SAVE POINTER TO FILE TYPE NAMING STRING -1 CLRB (R3)+ ;TERMINATE FILENAME WITH A NULL FOR NOW CALL 40$ ;CONVERT FILE TYPE INTO ASCII .ASSUME EN.TYP EQ EN.NAM+4 CLRB (R3) ;TERMINATE FILE TYPE WITH A NULL MOV 2(SP),R3 ;GET BACK POINTER TO FILE NAMING STRING MOV R1,R4 ;COPY POINTER @ SAVESTATUS REGION ADD #NAME-SAVERG,R4 ; AND FORM POINTER TO FILENAME PATTERN STRING CALL MATCH ;NOW PATTERN MATCH THE FILENAME MOV (SP)+,R3 ;GET BACK POINTER TO FILE TYPE STRING -1 MOVB #'.,(R3)+ ; AND REPLACE THE FILENAME'S NULL WITH "." TST (SP)+ ;JUNK THE SAVED FILENAME POINTER TST R0 ;DID WE GET A MATCH ON FILENAME? BEQ 10$ ;NOPE, NO POINT IN TRYING THE FILE TYPE MOV R1,R4 ;ELSE COPY POINTER @ SAVESTATUS REGION ADD #TYPE-SAVERG,R4 ; AND FORM POINTER TO FILE TYPE PATTERN STRING CALL MATCH ;NOW PATTERN MATCH THE FILE TYPE TST R0 ;DID WE GET A MATCH (R0 <> 0)? BNE 20$ ;YES, EXIT C=0 (FROM THE 'TST') 10$: SEC ;NO, SET C=1 FOR EXIT 20$: MOV (SP)+,R2 ;RESTORE DIRECTORY ENTRY POINTER MOV FILBUF(R5),R3 ; AND RESTORE FILENAME BUFFER POINTER RETURN ; THEN EXIT W/ C-BIT INDICATION 30$: MOV PC,-(SP) ;DO THE BELOW TWICE 40$: MOV (R2)+,R0 ;GET A RAD50 WORD 50$: CALL 60$,R1,50*50 ;DO THE FIRST CHARACTER CALL 60$,R1,50 ;DO THE SECOND CHARACTER CALL 60$,R1,1 ;DO THE THIRD CHARACTER RETURN ;EXIT 60$: CLR R4 ;CLEAR A RESULT BUCKET 70$: INC R4 ;INCREMENT THE RESULT SUB (R1),R0 ; AND DO A TRIAL SUBTRACTION BHIS 70$ ;KEEP GOING... ADD (R1)+,R0 ;ELSE CORRECT FOR THE UNDERFLOW DEC R4 ; AND CORRECT THE RESULT BEQ 90$ ;ZERO, DO NOTHING ADD #'A-1,R4 ;GUESS AT ALPHABETIC (1-32) CMP R4,#'Z ;GOOD GUESS? BLOS 80$ ;YES ADD #'0-36-<'A-1>,R4 ;NO, NUMERIC (36-47) (33, 34, 35 ARE UNUSED) 80$: MOVB R4,(R3)+ ;OUTPUT THE CHARACTER 90$: RETURN R1 ;EXIT .SBTTL CHECK FOR A PATTERN STRING MATCH ;+ ; R3 -> TEST STRING (.ASCIZ) ; R4 -> PATTERN STRING (.ASCIZ) ; ; CALL MATCH ; ; R0 <> 0 => TEST STRING MATCHED ; = 0 => TEST STRING DIDN'T MATCH ; R2 = UNDEFINED ; R3 = UNDEFINED ; R4 = UNDEFINED ; ; This routine does a wildcard pattern match against an ASCII pattern string ; pointed to by R4 and a test string pointed to by R3. The matchable ; wildcards are: ; "%" => match any non-null, non-blank character ; "*" => match any string ; Both strings must end in a null byte (i.e., be .ASCIZ). ;- MATCH: CLR R0 ;Assume failure 10$: MOVB (R4)+,R2 ;Get the next pattern character CMPB #'*,R2 ;Is it a "*"? BNE 20$ ;Branch if not TSTB (R4) ;Are we at the end of the string? BEQ 30$ ;Branch if so. We have a match 20$: TSTB (R3) ;Is this the end of the test string? BNE 40$ ;Branch if not TSTB R2 ;At the end of the pattern string? BNE 60$ ;Branch if not. Return a level 30$: INC R0 ;Else it matched!!! BR 60$ ;Return a level 40$: TSTB R2 ;Is this the end of the pattern string? BEQ 60$ ;Branch if so CMPB #'*,R2 ;Is the pattern character a "*"? BEQ 50$ ;Branch if so CMPB (R3)+,R2 ;Does test char match pattern char? BEQ 10$ ;Branch if yes CMPB #'%,R2 ;Is the pattern char a "%"? BEQ 10$ ;Branch if so. It matches. BR 60$ ;Else return to caller 50$: MOV R4,-(SP) ;Save R4 MOV R3,-(SP) ; and R3 CALL 10$ ;Then call self!!!! MOV (SP)+,R3 ;Restore R3 MOV (SP)+,R4 ; and R4 TST R0 ;Did the strings match? BNE 60$ ;Branch if so TSTB (R3)+ ;At the end of the test string yet? BNE 50$ ;Branch if not 60$: RETURN ;Return a level .SBTTL READ/WRITE DATA AREA .PSECT ENCMRW,RW,D,LCL,REL,CON ORG ENCMRW DIRBUF: ;DIRECTORY BUFFER HD$SGS: .BLKW ;NUMBER OF ACTIVE DIRECTORY SEGMENTS HD$NXT: .BLKW ;NEXT DIRECTORY SEGMENT NUMBER (0=>NONE) HD$HGH: .BLKW ;HIGHEST DIRECTORY SEGMENT NUMBER IN USE (FIRST ONLY) HD$EXT: .BLKW ;NUMBER OF EXTRA BYTES PER ENTRY HD$BLK: .BLKW ;STARTING BLOCK NUMBER FOR FILE DATA FOR THIS SEGMENT EN$SRT: ;START OF DIRECTORY ENTRIES .BLKB 2000- ;ALLOCATE THE REST OF DIRECTORY BUFFER AREA: .BLKW 5 ;MONITOR CALL WORK AREA .END