.TITLE UPDATE - DISK UPDATE PROGRAM .IDENT /X01.02/ ; ; VERSION X01.02 ; AUTHOR: KENNETH BELL / APPLIED RESEARCH LABS / SUNLAND,CA. ; CREATION DATE: 4-SEP-81 ; ; MODIFIED TO ADD WILD CARD SUPPORT 10-SEP-81 KRB ; ; MODIFIED TO ADD PROTECTED FILE SUPPORT 4-DEC-81 KRB ; ; UPDATE IS INTENDED AS A DISK UPDATE PROGRAM. IT COPIES NEWER ; VERSIONS OF FILES FROM THE INPUT DEVICE TO THE OUTPUT DEVICE ; ONLY IF THE FILES ALREADY EXIST ON THE OUTPUT DEVICE. ; ERRBYT = 52 ; ERROR BYTE ; NEXT$ = 2 ; OFFSET OF NEXT SEGMENT # EXTRA$ = 6 ; OFFSET OF # EXTRA WORDS / ENTRY LEN$ = 14. ; LENGTH OF DIRECTORY ENTRY ; PROT$ = 100000 ; PROTECTED FILE PERM$ = 2000 ; PERMANENT FILE ENDS$ = 4000 ; END OF DIRECTORY SEGMENT NAM1$ = 2 ; OFFSET TO 1ST WORD OF FILE NAME NAM2$ = 4 ; OFFSET TO 2ND WORD OF FILE NAME TYPE$ = 6 ; OFFSET TO FILE TYPE DATE$ = 12. ; OFFSET OF CREATION DATE SIZE$ = -4 ; OFFSET OF SIZE FROM DATE IN ENTRY STAT$ = -12. ; OFFSET OF STATUS FROM DATE IN ENTRY ; FILST$ = 100000 ; FILE STRUCTURED DEVICE HSIZ$ = 2 ; OFFSET TO HANDELR SIZE ADDR$ = 4 ; OFFSET TO HANDLER LOAD ADDRESS ; .MCALL .CSISPC,.DSTAT,.FETCH,.RELEAS .MCALL .LOOKUP,.ENTER,.DELETE,.CLOSE,.RENAME .MCALL .READW,.WRITW,.PRINT,.GTLIN .MCALL .SERR,.EXIT,.SETTOP,.TTYIN .MCALL .LOCK,.UNLOCK ; .MACRO $ERROR STR,TST=CC,?LOC B'TST LOC JSR R5,ERROR .WORD STR LOC: .ENDM $ERROR ; ; SCRATCH AREAS AND CONSTANTS ; .PSECT DATA AREA: .BLKW 5 ; EMT PARAMETER BLOCK STATUS: .BLKW 4 ; DEVICE STATUS BLOCK DEFEXT: .WORD 0,132500,0,0 ; DEFAULT EXTENTIONS = NULL,*,NULL,NULL OUTSPC: .BLKW 3*5 ; OUTPUT FILE SPECIFICATIONS INSPC: .BLKW 6*4 ; INPUT FILE SPECIFICATIONS FILSPC: .BLKW 8. ; FILE SPEC FOR LOOKUP, ENTER, DELETE, RENAME OUTFIL: .BLKB 14 ; OUTPUT FILE SPEC (ASCII) INFIL: .BLKB 20 ; INPUT FILE SPEC (ASCII) BUFFER: .BLKW 256. ; INPUT/OUTPUT BUFFER DIRBUF: .BLKW 512. ; DIRECTORY BUFFER BLOCK: .WORD 0 ; I/O BLOCK # INDATE: .WORD 0 ; INPUT FILE CREATION DATE INSIZE: .WORD 0 ; INPUT FILE SIZE INSTAT: .WORD 0 ; INPUT FILE STATUS PRTFLG: .WORD 0 ; PROT/UNPROT FLAG DIRSEG: .WORD 0 ; # OF CURRENT DIRECTORY SEGMENT TOP: .WORD 0 ; POINTER TO END OF PROGRAM WLDCRD: .BYTE 0,0 ; WILD CARD FLAGS (NAME , EXT) CHARS: .WORD 0 ; STRING POINTER ; ; SWITCH TABLE ; SWITCH: .WORD QUERY,'Q .WORD PREDEL,'P .WORD LOG,'L .WORD OVRPRT,'X .WORD 0 QUERY: .WORD 0 PREDEL: .WORD 0 LOG: .WORD 0 OVRPRT: .WORD 0 ; ; MESSAGE TEXT ; .PSECT STRING .NLIST BEX .ENABL LC HELLO: .ASCIZ /UPDATE X01.02 04-Dec-81/ TO: .ASCII / to /<200> CRLF: .BYTE 15,12,200 QUEST: .ASCII / ? /<200> UPDERR: .ASCII /UPDATE-F-/<200> ILSERR: .ASCIZ /Illegal switch/ INFERR: .ASCIZ /Input device not file structured/ IFFERR: .ASCIZ /Input handler fetch fail/ ONFERR: .ASCIZ /Output device not file structured/ OFFERR: .ASCIZ /Output handler fetch fail/ LFOERR: .ASCIZ /Lookup fail on output device/ DRFERR: .ASCIZ /Directory read fail/ LFIERR: .ASCIZ /Lookup fail on input device/ DFOERR: .ASCIZ /Delete fail on output device/ EFOERR: .ASCIZ /Enter fail on output device/ REDERR: .ASCIZ /Read error on input file/ WRTERR: .ASCIZ /Write error on output file/ NRMERR: .ASCIZ /No room to fetch handler/ RPUERR: .ASCIZ 'Protect/unprotect error on output file' .LIST BEX .PSECT CODE ; ; ONCE ONLY INITIALIZATION ; START: .SERR .SETTOP #-2 ; GRAB FOR ALL THE GUSTO .PRINT #HELLO ; ; ONCE PER CSI STRING INITIALIZATION ; RESTRT: MOV #END,TOP ; SET TOP OF PROGRAM POINTER CLR QUERY ; CLEAR SWITCH FLAGS CLR PREDEL CLR LOG CLR OVRPRT CLR OUTFIL ; CLEAR OUTPUT FILESPEC STRING ; ; GET CSI STRING FROM USER AND CHECK FOR SWITCHES ; .LOCK ; GRAB THE USR .CSISPC #OUTSPC,#DEFEXT,#0 ; GET DEVICE NAMES FROM USER MOV (SP)+,R0 ; GET # OF SWITCHES BEQ 40$ ; NO SWITCHES - SKIP PROCESSING 10$: MOV (SP)+,R1 ; GET SWITCH , CHECK FOR VALUE BPL 20$ ; NO VALUE - SKIP TST (SP)+ ; IGNORE VALUE 20$: BIC #^C177,R1 ; STRIP TO ASCII CHARACTER MOV #SWITCH,R2 ; POINT TO SWITCH TABLE 30$: MOV (R2)+,R3 ; GET ADDRESS OF FLAG TO SET $ERROR ILSERR,NE ; END OF TABLE IF ZERO CMP (R2)+,R1 ; CHECK FOR SWITCH BNE 30$ ; NOT FOUND - CHECK FURTHER MOV #1,(R3) ; FOUND - SET FLAG DEC R0 ; CHECK IF MORE SWITCHES BNE 10$ ; TST QUERY ; QUERY ASSUMES LOG BEQ 40$ MOV #1,LOG 40$: ; ; CHECK INPUT DEVICE FOR FILE-STRUCTURED AND FETCH HANDLER ; .DSTAT #STATUS,#INSPC ; GET INPUT DEVICE STATUS BIT #FILST$,STATUS ; FILE STRUCTURED? $ERROR INFERR,NE TST STATUS+ADDR$ ; HANDLER LOADED? BNE 50$ ; YES - SKIP FETCH MOV TOP,R0 ; GET TOP ADDRESS ADD STATUS+HSIZ$,R0 ; ADD SPACE FOR HANDLER CMP R0,@#50 ; DID WE USE IT ALL? $ERROR NRMERR,LO .FETCH TOP,#INSPC ; NO - GET HANDLER $ERROR IFFERR MOV R0,TOP ; REMEMBER NEW TOP 50$: ; ; CHECK OUTPUT DEVICE FOR FILE-STRUCTURED AND FETCH HANDLER ; .DSTAT #STATUS,#OUTSPC ; GET OUTPUT DEVICE STATUS BIT #FILST$,STATUS ; FILE STRUCTURED? $ERROR ONFERR,NE TST STATUS+ADDR$ ; HANDLER LOADED? BNE 60$ ; YES - SKIP FETCH MOV TOP,R0 ; GET TOP ADDRESS ADD STATUS+HSIZ$,R0 ; ADD SPACE FOR HANDLER CMP R0,@#50 ; DID WE USE IT ALL? $ERROR NRMERR,LO .FETCH TOP,#OUTSPC ; NO - GET HANDLER $ERROR OFFERR MOV R0,TOP ; REMEMBER NEW TOP 60$: ; ; DO NON-FILE-STRUCTURED LOOKUP ON OUTPUT DEVICE TO READ DIRECTORY ; MOV OUTSPC,FILSPC ; COPY OUTPUT DEVICE SPEC CLR FILSPC+2 ; MAKE SURE FILE NAME AND EXT ARE NULL CLR FILSPC+4 CLR FILSPC+6 .LOOKUP #AREA,#0,#FILSPC ; DO NON-FILE-STRUCTURED LOOKUP ; ON OUTPUT DEVICE $ERROR LFOERR MOV #1,DIRSEG ; SET TO GET 1ST DIRECTORY SEGMENT ; ; PRIMARY LOOP - READ DIRECTORY SEGMENT ; LOOP1: MOV DIRSEG,R1 ; GET DIRECTORY SEGMENT # *2 ASL R1 ADD #4,R1 ; COMPUTE DISK BLOCK # .READW #AREA,#0,#DIRBUF,#512.,R1 ; READ DIRECTORY SEGMENT $ERROR DRFERR MOV #DIRBUF+10.,R5 ; ; SECONDARY LOOP - PROCESS DIRECTORY ENTRY ; ; CHECK IF FILE ON OUTPUT DEVICE HAS UPDATED FILE ON INPUT DEVICE ; LOOP2: BIT #PERM$,(R5) ; PERMANENT FILE? BEQ 10$ ; NO - SKIP MOV NAM1$(R5),FILSPC+2 ; SET FILE NAME INTO INPUT SPEC MOV NAM2$(R5),FILSPC+4 MOV TYPE$(R5),FILSPC+6 ; CALL CHECK ; CHECK IF WE COPY THIS FILE TST R0 ; R0 = 0 IF NOT BEQ 10$ ; BIT #PROT$,(R5) ; PROTECTED FILE? BEQ 5$ ; NO - PROCEED TST OVRPRT ; OVERRIDE PROTECTION? BNE 10$ ; NO - SKIP THIS FILE CALL UNPROT ; UNPROTECT FILE TO AVOID PROBLEMS 5$: ; MOV INSPC,FILSPC ; COPY INPUT DEVICE SPEC MOV #GETDAT,AREA+8. ; SET UP COLLECT CALL FROM USR .LOOKUP #AREA,#1,#FILSPC!1 ; SEE IF WE HAVE THIS FILE BCC 15$ ; FILE FOUND - CHECK IT OUT TSTB @#ERRBYT ; CHECK EROR CODE $ERROR LFIERR,NE 10$: JMP NEXT 15$: ; ; FILE OF SAME NAME ON INPUT DEVICE - UPDATED? ; CMP INDATE,DATE$(R5) ; SEE IF INPUT FILE IS NEWER BLOS 10$ ; ; CHECK FOR LOG OR QUERY ; TST LOG ; LOG (OR QUERY)? BEQ 30$ CALL LOGIT ; TST QUERY ; QUERY? BNE 20$ .PRINT #CRLF ; NO - PRINT CRLF AND COPY FILE BR 30$ ; ; UPDATED FILE ON INPUT DEVICE - OK TO COPY? ; 20$: .PRINT #QUEST ; YES - ASK FOR PERMISSION .TTYIN ; GET ANSWER MOV R0,-(SP) ; AND SAVE IT 25$: .TTYIN ; SEARCH FOR EOL CMP R0,#012 BNE 25$ CMP (SP)+,#'Y ; "Y" IS ONLY ANSWER THAT MATTERS BNE NEXT ; ; OK TO COPY - SET UP FILE SPEC ; 30$: MOV OUTSPC,FILSPC ; SET OUTPUT DEVICE SPEC TO FILENAME ; ; CHECK FOR PREDELETE ; TST PREDEL ; PREDELETE? BEQ 35$ ; NO - TRY TO COPY WITHOUT PREDELETE .DELETE #AREA,#2,#FILSPC ; DELETE FILE FROM OUTPUT DEVICE $ERROR DFOERR ; ; TRY TO ALLOCATE SPACE FOR NEW FILE ON OUTPUT DEVICE ; 35$: MOV #SETDAT,AREA+8. ; SET UP CLOOECT CALL FROM USR .ENTER #AREA,#2,#FILSPC!1,INSIZE $ERROR EFOERR ; ; TERTIARY LOOP - COPY FILE ONE BLOCK AT A TIME (SLOW - BUT WHO CARES) ; CLR BLOCK ; CLEAR BLOCK NUMBER 40$: .READW #AREA,#1,#BUFFER,#256.,BLOCK $ERROR REDERR .WRITW #AREA,#2,#BUFFER,#256.,BLOCK $ERROR WRTERR INC BLOCK ; NEXT BLOCK DEC INSIZE ; DECREMENT COUNT BNE 40$ ; UNTIL ZERO BIT #PROT$,INSTAT ; WAS INPUT FILE PROTECTED? BEQ 45$ ; NO CALL PROT ; YES - PROPAGATE FILE PROTECTION 45$: .CLOSE #2 ; CLOSE OUTPUT FILE ; ; END OF PROCESSING FOR THIS ENTRY - GET READY FOR MORE ; NEXT: .CLOSE #1 ; CLOSE INPUT FILE ADD #LEN$,R5 ; POINT TO NEXT DIRECTORY ENTRY ADD DIRBUF+EXTRA$,R5 ; SKIP EXTRA WORDS BIT #ENDS$,(R5) ; CHECK FOR END OF DIRECTORY SEGMENT BNE 10$ JMP LOOP2 ; NO - GET NEXT ENTRY ; 10$: MOV DIRBUF+NEXT$,DIRSEG ; POINT TO NEXT DIRECTORY SEGMENT BEQ 20$ JMP LOOP1 ; NOT ZERO - MORE TO CHECK ; 20$: .CLOSE #0 ; CLOSE DIRECTORY CHANNEL .RELEAS #INSPC ; RELEASE THE HANDLERS .RELEAS #OUTSPC .UNLOCK ; RELEASE THE USR JMP RESTRT ; GO GET NEXT COMMAND STRING ; ; LOG INPUT AND OUTPUT FILE SPECS ; LOGIT: MOVB #'.,INFIL+12 ; SET . BETWEEN NAME AND TYPE MOVB #200,INFIL+16 ; SET TO ASCIZ / NO CRLF .PRINT #INFIL ; PRINT INPUT FILE SPEC .PRINT #TO MOV OUTSPC,R0 ; SET OUTPUT DEVECE NAME IN FILE SPEC MOV #INFIL,R1 CALL RAD50 .PRINT #INFIL ; PRINT OUTPUT FILE SPEC RETURN ; ; GETDATE ROUTINE - CALLED FROM USR ; GETDAT: MOV (R1),INDATE ; GET CREATION DATE MOV SIZE$(R1),INSIZE ; GET FILE SIZE MOV STAT$(R1),INSTAT ; AND FILE STATUS WORD RETURN ; ; SETDATE ROUTINE - CALLED FROM USR ; SETDAT: MOV INDATE,(R1) ; SET CREATION DATE RETURN ; ; PROT/UNPROT OUTPUT FILE ; .ENABL LSB PROT: INC PRTFLG ; SET FLAG TO PROTECT FILE BR 10$ UNPROT: CLR PRTFLG ; CLEAR FLAG TO UNPROTECT FILE 10$: MOV OUTSPC,FILSPC ; SET UP FILE SPEC FOR OUTPUT DEVICE MOV FILSPC,FILSPC+8. ; COPY FILESPEC FOR RENAME MOV FILSPC+2,FILSPC+10. MOV FILSPC+4,FILSPC+12. MOV FILSPC+6,FILSPC+14. MOV #PRTFIL,AREA+8. ; SET ROUTINE FOR USR COLLECT CALL .RENAME #AREA,#3,#FILSPC!1 $ERROR RPUERR RETURN .DSABL LSB ; PRTFIL: TST PRTFLG ; PROTECT OR UNPROTECT? BNE 10$ BIC #PROT$,STAT$(R1) ; UNPROTECT BR 20$ 10$: BIS #PROT$,STAT$(R1) ; PROTECT 20$: RETURN ; ; ERROR ROUTINE ; ERROR: .PRINT #UPDERR .PRINT @R5 .EXIT ; ; RAD50 TO ASCII CONVERSION ROUTINE ; R0 = RAD50 CHARACTERS ; R1 > OUTPUT BUFFER ; R2 IS USED AS A SCRATCH REGISTER ; ; RAD50W - R3 > RAD50 WORD ; RAD50W: MOV (R3)+,R0 RAD50: CALL DIV50 ; DIVIDE BY 50(8) MOV R2,-(SP) ; SAVE THIRD CHARACTER CALL DIV50 ; AGAIN MOV R2,-(SP) ; AND SAVE SECOND CHARACTER CALL DIV50 ; ONCE MORE CALL 10$ ; CONVERT TO ALPHA AND OUTPUT MOV (SP)+,R2 ; REMEMBER SECOND CALL 10$ ; AND OUTPUT MOV (SP)+,R2 ; REMEMBER THIRD ; AND FALL THROUGH 10$: TST R2 ; SPACE ? BEQ 20$ ADD #40,R2 ; NO - ADD OFFSET FOR A-Z CMP R2,#72 ; ALPHA ? BLE 20$ SUB #56,R2 ; NO - OFFSET TO NUMERIC CMP R2,#16 ; NUMERIC, *, OR % ? BGE 20$ CLR R2 ; NO - FORCE TO BLANK 20$: ADD #40,R2 ; FINISH TRANSLATION MOVB R2,(R1)+ ; AND OUTPUT RETURN ; ; DIV50 ROUTINE - DUMB SUBTRACT-AND-INCREMENT, BUT WHO CARES ; DIV50: MOV R0,R2 CLR R0 1$: SUB #50,R2 BCS 2$ INC R0 BR 1$ 2$: ADD #50,R2 RETURN ; ; CHECK FILSPC(RAD50) FOR MATCH WITH OUTSPC(RAD50) ; RETURNS R0 = 0 IF NO MATCH ; CHECK: TST OUTFIL ; HAVE WE SET UP THE MATCH STRING ? BNE 10$ ; YES - SKIP ; MOV #OUTSPC+2,R3 ; POINT TO RAD50 OUTPUT FILE SPEC MOV #OUTFIL,R1 ; POINT TO ASCII STRING STORAGE CALL CONVRT ; CONVERT RAD50 TO ASCII MOV #OUTFIL,CHARS ; CHECK FOR WILDCARDS IN OUTPUT FILE SPEC CALL WLDCHK ; 10$: MOV #FILSPC,R3 ; CONVERT INPUT FILESPEC TO ASCII MOV #INFIL,R1 CALL CNVRT2 ; CLR R0 ; ASSUME FAILURE TSTB WLDCRD ; FILENAME WILDCARD FLAG BMI 20$ ; EMBEDDED WILCARDS ? BNE 30$ ; ARBITRARY NAME ? CMP OUTSPC+2,FILSPC+2 BNE 60$ CMP OUTSPC+4,FILSPC+4 BNE 60$ BR 30$ 20$: MOV #OUTFIL,R1 ; POINT TO TEST STRING MOV #INFIL+4,R2 ; POINT TO MATCH STRING CALL MATCH ; LOOK FOR WILDCARD MATCH TST R0 BEQ 60$ ; 30$: CLR R0 ; REASSUME FAILURE TSTB WLDCRD+1 ; EXTENTION WILDCARD FLAG BMI 40$ ; EMBEDDED WILDCARDS ? BNE 50$ ; ARBITRARY TYPE ? CMP OUTSPC+6,FILSPC+6 ; FIXED - COMPARE BNE 60$ ; FAILURE BR 50$ ; SUCCESS 40$: MOV #OUTFIL+7,R1 ; POINT TO TEST STRING MOV #INFIL+13,R2 ; POINT TO MATCH STRING CALL MATCH ; LOOK FOR WILDCARD MATCH BR 60$ ; 50$: INC R0 ; SUCCESS EXIT 60$: RETURN ; ; CONVERT A RAD50 FILE SPEC TO ASCII FOR USE BY WLDCHK AND MATCH ; ; CNVRT2 - DEVICE, FILE NAME, AND TYPE ; CONVRT - FILE NAME AND TYPE ; ; R3 > RAD50 STRING ; R1 > ASCII STRING ; R0,R2 ARE SCRATCH REGISTERS ; CNVRT2: CALL RAD50W MOVB #':,(R1)+ CONVRT: CALL RAD50W CALL RAD50W MOVB #40,(R1)+ CALL RAD50W MOVB #40,(R1)+ RETURN ; ; THIS PROCEDURE CHECKS AN ASCII FILENAME FOR WILDCARDS ; THE FILE NAME MUST LOOK LIKE "FFFFFFBXXXB", WHERE F IS ; THE FILE NAME, X IS THE EXTENTION, AND B IS A BLANK. ; THE FILENAME IS POINTED TO BY CHARS ; WLDCRD = 1 IF * , -1 IF % OR EMBEDDED * IN FILE NAME ; WLDCRD+1 = 1 IF * , -1 IF % OR EMBEDDED * IN EXTENTION ; WLDCHK: MOV R3,-(SP) ; PRESERVE R3 MOV R1,-(SP) ; AND R1 CLR R1 ; CLEAR THE COUNTER CLR WLDCRD ; CLEAR THE FLAG MOV #6,R0 ; CHECK THE FIRST 6 CHARACTERS MOV CHARS,R3 ; POINT TO IT 1$: CMPB @R3,#'. ; IS IT A % ? BEQ 3$ CMPB (R3)+,#'/ ; IS IT A * ? BEQ 2$ DEC R0 ; DECREMENT COUNTER BNE 1$ SUB CHARS,R3 ; WHERE ARE WE ? CMP R3,#12 ; FINISHED CHECKING EXTENTION ? BLT 6$ BR 8$ 2$: CMPB @R3,#40 ; BLANK FOLLOWING * ? BNE 3$ TSTB -(R3) ; MOVE POINTER BACK CMPB R3,CHARS ; ARE WE AT THE BEGINNING ? BEQ 4$ CMPB -1(R3),#40 ; IS THERE A PRECEDING BLANK BEQ 4$ 3$: DECB WLDCRD(R1) ; SET EMBEDDED FLAG BR 5$ 4$: INCB WLDCRD(R1) ; INCREMENT COUNTER 5$: SUB CHARS,R3 ; FIND OUT WHERE WE ARE 6$: CMP R3,#6 ; IN THE FILENAME ? BGT 7$ MOV CHARS,R3 ; POINT TO EXTENTION ADD #7,R3 MOV #3,R0 ; 3 CHARACTERS INC R1 ; POINT TO EXTENTION PART OF WLDCRD BR 1$ 7$: INC @SP ; INCREMENT COUNTER 8$: MOV (SP)+,R1 ; RESTORE R1 MOV (SP)+,R3 ; AND R3 TST R0 ; SET CONDITION CODES RETURN ; ; MATCH CHECKS FOR A MATCH BETWEEN A TEST STRING, POINTED TO BY R1, ; AND A MATCH STRING, POINTED TO BY R2, AND RETURNS R0 NON-ZERO ON ; A MATCH. BOTH STRING MUST BE DELIMITTED BY A BLANK. THE TEST STRING ; MAY CONTAIN EMBEDDED * OR % ; MATCH: MOV R4,-(SP) ; SAVE REGISTERS 4 - 1 MOV R3,-(SP) MOV R2,-(SP) MOV R1,-(SP) CALL MATCH1 ; AND DO MATCH MOV (SP)+,R1 ; RESTORE REGISTERS 1 - 4 MOV (SP)+,R2 MOV (SP)+,R3 MOV (SP)+,R4 RETURN ; MATCH1: CLR R0 ; ASSUME FAILURE MOV #40,R4 ; USED OFTEN - WASTE A REGISTER 1$: MOVB (R1)+,R3 ; GET A CHARACTER CMPB R3,#'/ ; ARBITRARY MATCH ? BNE 2$ CMPB @R1,R4 ; END OF TEST STRING ? BEQ 5$ 2$: CMPB R4,@R2 ; END OF MATCH STRING ? BEQ 3$ CMPB R4,R3 ; END OF TEST STRING ? BEQ 6$ CMPB R3,#'/ ; ARBITRARY MATCH ? BEQ 5$ CMPB (R2)+,R3 ; CHARACTER MATCH ? BEQ 1$ CMPB R3,#'. ; WILD CHARACTER ? BEQ 1$ BR 6$ ; NONE OF THE ABOVE - EXIT ; 3$: CMPB R4,R3 ; END OF TEST STRING ? BNE 6$ 4$: INC R0 ; SUCCESS BR 6$ ; 5$: MOV R2,-(SP) ; RECURSE - SAVE STATE MOV R1,-(SP) CALL 1$ ; CALL OURSELVES MOV (SP)+,R1 ; RESTORE STATE MOV (SP)+,R2 TST R0 ; SUCCESS ? BNE 6$ CMPB R4,(R2)+ ; END OF MATCH STRING ? - MAKE * COVER 1 MORE BNE 5$ 6$: RETURN END: .END START