; Alphawrite screen directory. Works on V1.2 ; This was originally adapted via FIX from FILES.LIT, distributed with ; the Omniledger accounting package, as an M68 training exercise. ; I've since noticed great similarities with the excellent EDIR from ; White House Software (available from AMUS network). ; all comments are IKLF interpretation and should not be relied on ; Author (with the above caveats) Iain Fraser, Mortimer Technology Ltd, 1987 ; ; See AWUTIL.DOC for more info OBJNAM .LIT SEARCH SYS SEARCH SYSSYM SEARCH TRM VMAJOR =1 VMINOR =0 VEDIT =100. L00000: PHDR -1,0 LEA A5,L00000 ; A5 indexes start of prog MOV A2,D2 ; store index to command line LEA A1,WRK0(A5) ; index work area MOV A1,D0 MOV D0,W0AD(A5) ; store address LEA A1,WRK1(A5) ; index second work area MOV A1,D0 MOV D0,W1AD(A5) ; store address MOV D2,A2 ; restore index to command line TRM ; test for terminator JNE 10$ ; no CLR D2 ; yes so indicate no command line 10$: CALL GETUFD JEQ NOPPN ; no ppn CALL CURCLR ; clear cursor position MOVB #52,FNMASC(A5) ; * as default filename CLRB 1+FNMASC(A5) CALL GETSRC ; get search parameters FILOOP: CALL GETFIL ; get file from directory JEQ ENDDIR ; no more files CALL MATFIL ; does file match? JNE FILOOP ; no - next one CALL FLREAD ; read first block of file CALL FIRST1 ; first time code if necc LEA A1,HOMCUR(A5) ; load table of cursor homes MOV A1,D2 ; into register CALL NEXCUR ; put cursor to next posn JNE PRFILE ; jump if successful ; ; else prompt for next screen MOV #14001,D1 ; 24,1 TCRT PUSH D1 MOV #177413,D1 ; -1,11 (background display) TCRT POP D1 TYPESP PUSH D1 MOV #177414,D1 ; -1,12 (foreground display) TCRT POP D1 CALL GETKBD CMPB D1,#3 ; control-C JEQ ENDDIR ; causes exit LEA A1,HOMCUR(A5) ; load table of cursor homes MOV A1,D2 CALL NEXCUR ; next cursor position PUSH D1 MOV #177412,D1 ; -1,10 (erase eos) TCRT POP D1 PRFILE: LEA A6,FNMASC(A5) ; filename to print TTYL ; print it MOV #7,D1 ; 7 cols CALL CURTAB ; reposition cursor ; LEA A6,EXTASC(A5) ; extension to print ; TTYL ; print it LEA A6,16.+WRK1(A5) ; AW description TTYL JMP FILOOP ; next file ENDDIR: TST WRK2(A5) ; 1st time flag JNE 20$ ; set, so there has been something TYPECR <%No such files> ; not set so no matches EXIT 20$: MOV #14001,D1 ; 24,1 TCRT PUSH D1 MOV #177411,D1 ; -1,9 erase eol TCRT POP D1 EXIT NOPPN: TYPECR EXIT WRK0: BLKB 1000 WRK1: BLKB 1000 WRK2: LWORD 0 FIRST1: TST WRK2(A5) ; 1st time flag BEQ FIRSTY ; 1st time RTN ; not first time FIRSTY: MOV #-1,WRK2(A5) ; no longer first time CALL IMAGEM ; image mode PUSH D1 ; save D1 MOV #177400,D1 ; -1,0 (clear screen) TCRT POP D1 ; restore D1 PUSH D1 ; save it again MOV #177413,D1 ; -1,11 (background display) TCRT POP D1 ; restore D1 TYPE < AlphaWRITE Screen Catalogue...................................> LEA A1,DEVICE(A5) ; addr to pack device into MOV A1,D2 LEA A1,D.DEV+DDB1(A5) ; addr with rad50 device MOV A1,D1 MOV D1,A1 MOV D2,A2 UNPACK ; unpack device MOV A2,D2 MOV A1,D1 LEA A6,DEVICE(A5) ; index device name TTYL ; type it out CLR D1 ; clear drive no MOVW D.DRV+DDB1(A5),D1 ; load drive no from ddb MOV D2,A2 ; update pointer DCVT 0,OT$TRM ; print drive no in decimal TYPE <:[> JOBIDX A6 ; who am I? MOV A6,D0 ; in register MOV D0,A0 ADD #24,A0 ; JOBUSR MOVW @A0,D4 ; in D4 MOV D0,A0 ; JOBIDX CLRW 24(A0) ; clear JOBUSR (bad idea!) PRPPN D.PPN+DDB1(A5) ; print ppn MOV D0,A1 ; stored JOBIDX ADD #24,A1 ; JOBUSR MOVW D4,@A1 ; restore JOBUSR TYPE <]> PUSH D1 ; save D1 MOV #177414,D1 ; -1,12 (foreground display) TCRT POP D1 ; restore D1 RTN ; return HOMCUR: WORD 0 ; top word of cursor LW BYTE 1 ; home col=1 BYTE 2 ; home row=2 BYTE 70. ; cols per file=70 BYTE 69. ; max col no=69 BYTE 22. ; max row no=22 BYTE 0 DEVICE: ASCII /DEV/ BYTE 0 FNMASC: LWORD 0 LWORD 0 EXTASC: ASCII /WRT/ BYTE 0 WSIZE: WORD 0 WSIZW: WORD 0 WACTI: WORD 0 WACTW: WORD 0 WLINK: WORD 0 WLINW: WORD 0 DDB1: BLKB D.DDB DDB2: BLKB D.DDB W0AD: LWORD 0 W1AD: LWORD 0 WW1: LWORD 0 WW2: LWORD 0 WDEV: WORD 0 WDRV: WORD 0 WPPN: WORD 0 GETUFD: MOV W0AD(A5),D.BUF+DDB1(A5) ; DDB buffer addresses MOV W1AD(A5),D.BUF+DDB2(A5) MOV #1000,D.SIZ+DDB1(A5) ; 1 block size MOV #1000,D.SIZ+DDB2(A5) MOVB #100,D.FLG+DDB1(A5) ; flag as INITed MOVB #100,D.FLG+DDB2(A5) CLR D.DVR+DDB1(A5) ; no device driver CLR D.DVR+DDB2(A5) JOBIDX A6 MOV A6,D0 MOV D0,A0 MOVW JOBDEV(A0),D.DEV+DDB1(A5) ; default log-in device MOVW JOBDRV(A0),D.DRV+DDB1(A5) ; default log-in drive MOVW JOBUSR(A0),D.PPN+DDB1(A5) ; default log-in ppn TST D2 ; any args to command? JEQ SETDD2 ; no, so use defaults MOV D2,WW1(A5) ; area to unpack args from LEA A1,WDEV(A5) ; area to pack device into MOV A1,D1 MOV D1,A1 MOV D2,A2 PACK ; pack arg into rad50 MOV A2,D2 ; update pointers MOV A1,D1 MOV D2,A2 GTDEC ; get number from args MOV A2,D2 ; update pointer MOVW D1,WDRV(A5) ; store as drive no MOV D2,A1 ADD #1,D2 MOVB #72,D7 ; : CMPB D7,@A1 JEQ INCDEV ; yup, a colon MOV WW1(A5),D2 CLR WDEV(A5) ; no device specified INCDEV: MOV D2,WW1(A5) CLRW WPPN(A5) ; no ppn specified PPNSRC: MOV D2,A2 TRM ; terminator? JEQ SETDD1 ; yup so we're done with args MOV D2,A0 ADD #1,D2 MOVB @A0,D7 CMPB D7,#133 ; [ JNE PPNSRC ; nope so try next char MOV D2,A2 GTPPN ; unpack ppn MOV A2,D2 MOVW D1,WPPN(A5) ; and store ADD #1,D2 MOV WW1(A5),D0 MOV D0,A0 MOVB @A0,D7 CMPB D7,#133 ; [ JNE SETDD1 ; nope MOV D2,WW1(A5) SETDD1: TST WDEV(A5) ; device specified? JEQ TESPPN ; nope MOVW WDEV(A5),D.DEV+DDB1(A5) ; yup, so store dev in ddb MOVW WDRV(A5),D.DRV+DDB1(A5) ; and drv TESPPN: TSTW WPPN(A5) ; ppn specified? JEQ SETDD2 ; nope MOVW WPPN(A5),D.PPN+DDB1(A5) ; yup so store it SETDD2: MOVW D.DEV+DDB1(A5),D.DEV+DDB2(A5) ; copy account into ddb2 MOVW D.DRV+DDB1(A5),D.DRV+DDB2(A5) MOVW D.PPN+DDB1(A5),D.PPN+DDB2(A5) MOV #1,D.REC+DDB1(A5) ; want record one GETMFD: LEA A6,DDB1(A5) ; in ddb1 READ ; so read it CLR WW2(A5) ; zeroise index NEXMFR: MOV W0AD(A5),D0 ; address of record buffer ADD WW2(A5),D0 ; add record index MOV D0,A0 TSTW @A0 ; is this zero JEQ NEXMFD ; yup so end of mfd record MOV D0,A0 MOVW @A0,D7 CMPW D7,D.PPN+DDB1(A5) ; ppn we want JEQ GOTPPN ; yup ADD #10,WW2(A5) ; no so look at next one JMP NEXMFR ; loop back GOTPPN: MOV D0,A0 ADD #2,A0 MOVW @A0,2+D.REC+DDB1(A5) ; put ufd address in ddb1 LEA A6,DDB1(A5) READ ; read it MOV WW1(A5),D2 ; leave D2 pointing to next bit of command line MOV #2,WW2(A5) ; leave WW2 pointing to 1st ufd entry LCC #0 ; indicate OK RETUFD: RTN ; back to main bit NEXMFD: MOV D0,A0 TSTW 2(A0) ; link to next mfd block BEQ RETUFD ; none so return with error MOV D0,A0 ADD #2,A0 MOVW @A0,D0 AND #177777,D0 MOV D0,D.REC+DDB1(A5) ; next mfd rec in ddb JMP GETMFD ; search this one GETFIL: MOV W0AD(A5),D0 ; ufd buffer ptr ADD WW2(A5),D0 ; position in buffer MOV D0,A1 ; indexed by A1 MOVW #-1,D7 CMPW D7,@A1 ; erased file? JNE 10$ ; no ADD #14,D0 ; yes so point to next one ADD #14,WW2(A5) 10$: MOV WW2(A5),D7 ; position in buffer CMP D7,#770 ; past last valid entry JLO 20$ ; no MOV W0AD(A5),D0 ; yes so index buffer MOV D0,A0 TSTW @A0 ; link entry present BEQ RETUFD ; no so end of search MOV D0,A0 ; yes MOVW @A0,2+D.REC+DDB1(A5) ; so point to next block LEA A6,DDB1(A5) ; and READ ; read it in MOV #2,WW2(A5) ; point to first entry 20$: MOV W0AD(A5),D0 ; ufd buffer pointer ADD WW2(A5),D0 ; position in buffer MOV D0,A1 ; index it MOVW #-1,D7 CMPW D7,@A1 ; erased file? JEQ GETFIL ; yes so point to next one MOV D0,A0 ; no so index it again TSTW @A0 ; end of directory? BNE 30$ ; no RTN ; yes so return 30$: MOV D0,D1 LEA A1,FNMASC(A5) MOV A1,D2 MOV D1,A1 ; rad50 filename from ufd MOV D2,A2 ; area to unpack into UNPACK ; unpack 1st byte MOV A2,D2 ; update pointers MOV A1,D1 MOV D1,A1 MOV D2,A2 UNPACK ; unpack second byte MOV A2,D2 ; update pointers MOV A1,D1 MOV D2,A0 CLRB @A0 ; terminate with null STRFIL: SUB #1,D2 ; last char of upacked name MOV D2,A0 MOVB @A0,D7 CMPB D7,#40 ; space ? JNE 40$ ; no MOV D2,A0 ; yes CLRB @A0 ; replace with null JMP STRFIL ; and look at previous char 40$: LEA A1,EXTASC(A5) ; area for unpacked extension MOV A1,D2 MOV D1,A1 ; packed extension from ufd MOV D2,A2 UNPACK ; and unpack it MOV A2,D2 ; update pointers MOV A1,D1 MOV D2,A0 CLRB @A0 ; terminate with null STREXT: SUB #1,D2 ; look at last char MOV D2,A0 MOVB @A0,D7 CMPB D7,#40 ; space? JNE 50$ ; no MOV D2,A0 ; yes CLRB @A0 ; replace with null JMP STREXT ; and look at previous char 50$: MOV D0,A0 ; pointer to buffer ADD #6,A0 ; plus six chars - size MOVW @A0,WSIZW(A5) ; store it MOV D0,A0 ; pointer to buffer ADD #10,A0 ; plus 8 - active MOVW @A0,WACTW(A5) ; store it MOV D0,A0 ; pointer to buffer ADD #12,A0 ; plus 10 - link MOVW @A0,WLINW(A5) ; store it ADD #14,WW2(A5) ; point to next entry RTN ; and return ; this bit of code doesn't seem to get used ; does now FLREAD: MOV WLINK(A5),D.REC+DDB2(A5) ; set up record no of file LEA A6,DDB2(A5) ; file #2 READ ; read record MOV WACTI(A5),D.WRK+DDB2(A5) ; active bytes MOV WSIZE(A5),D7 ; size CMP D7,#1 ; is it 1? MOV #1000,D.SIZ+DDB2(A5) ; size = 1 block JNE 60$ ; always jump?? MOV WACTI(A5),D.SIZ+DDB2(A5) ; size = active bytes 60$: MOV #2,D.IDX+DDB2(A5) ; point to byte 2 of file MOVB #1,D.OPN+DDB2(A5) ; indicate file open RTN ; return FNMSRC: LWORD 0 LWORD 0 EXTSRC: LWORD 0 VALCHR: WORD ^H7A61 ; za WORD ^H5A41 ; ZA WORD ^H3930 ; 90 WORD ^H3F3F ; ?? WORD ^H2A2A ; ** WORD 0 VALCHA: MOV D0,A0 TSTB @A0 ; end of validation table? JEQ VALBAD ; yes , failed validation MOV D0,A1 CMPB D1,@A1 ; compare char with low range JLO VALNXT ; fail - next test MOV D0,A1 ADD #1,A1 CMPB D1,@A1 ; compare char with high range JHI VALNXT ; fail - next test LCC #4 ; char in valid range RTN VALNXT: ADD #2,D0 ; point to next range JMP VALCHA VALBAD: LCC #0 ; indicate failure RTN UPCASE: CMPB D1,#141 ; a JLO UPCASR ; less than a CMPB D1,#172 ; z JHI UPCASR ; more than z SUB #40,D1 ; a-z so convert to upper case UPCASR: RTN GETSRC: CLR D3 ; clear counter NXTFNC: CLR D1 ; clear arg char MOV D2,A0 ; index arg line MOVB @A0,D1 LEA A1,VALCHR(A5) ; table of valid chars MOV A1,D0 CALL VALCHA JNE GETEXT ; char is invalid - done here CMP D3,#7 ; counter over 6? JNE STOFNM ; no JNKFNC: CLR D1 ; clear arg char MOV D2,A0 ; index arg line ADD #1,D2 ; point to next char MOVB @A0,D1 ; load arg char LEA A1,VALCHR(A5) ; validate it MOV A1,D0 CALL VALCHA JEQ JNKFNC ; if valid get next one JMP GETEXT ; if invalid we're done STOFNM: CLR D1 ; clear arg char MOV D2,A0 ; index arg char ADD #1,D2 ; point to next one MOVB @A0,D1 ; load char CALL UPCASE ; upper case it LEA A1,FNMSRC(A5) ; index filename to search MOV A1,D0 ADD D3,D0 ; add char count MOV D0,A1 MOVB D1,@A1 ; store char ADD #1,D3 ; increment count JMP NXTFNC ; go back for next one GETEXT: LEA A1,FNMSRC(A5) ; index filename to search MOV A1,D0 ADD D3,D0 ; add char count MOV D0,A0 CLRB @A0 ; null at end CLR D3 ; clear counter CLRB EXTSRC(A5) ; clear extension to search MOV D2,A0 MOVB @A0,D7 ; next char CMPB D7,#56 ; . JNE TSTSRC ; not a . so no extension ADD #1,D2 ; increment pointer NXTEXT: CLR D1 ; clear arg char MOV D2,A0 MOVB @A0,D1 LEA A1,VALCHR(A5) ; validate it MOV A1,D0 CALL VALCHA JNE TEREXT ; if invalid CMP D3,#4 ; over 3 chars? JNE STOEXT ; not yet JNKEXT: CLR D1 ; clear arg char MOV D2,A0 ; index arg ADD #1,D2 ; point to next one MOVB @A0,D1 ; load char LEA A1,VALCHR(A5) MOV A1,D0 CALL VALCHA ; validate it JEQ JNKEXT ; next one if valid JMP TEREXT ; else we're done STOEXT: CLR D1 ; clear arg char MOV D2,A0 ; index arg line ADD #1,D2 ; point to next one MOVB @A0,D1 ; load char CALL UPCASE ; upper case it LEA A1,EXTSRC(A5) ; where to load it to MOV A1,D0 ADD D3,D0 ; add in counter MOV D0,A1 MOVB D1,@A1 ; store char ADD #1,D3 ; increment counter JMP NXTEXT ; go back for next one TEREXT: LEA A1,EXTSRC(A5) ; extension to search for MOV A1,D0 ADD D3,D0 ; add in char count MOV D0,A0 CLRB @A0 ; terminate with null TSTSRC: TSTB FNMSRC(A5) ; any filename offered? JNE TSTEXT ; no LEA A1,FNMASC(A5) ; index what we will test against MOV A1,D2 LEA A1,FNMSRC(A5) ; index what we've just stored MOV A1,D0 NXTSCH: MOV D2,A0 ADD #1,D2 ; increment index MOV D0,A1 ADD #1,D0 ; increment index MOVB @A0,@A1 ; move char across JNE NXTSCH ; next one if last wasn't null TSTEXT: TSTB EXTSRC(A5) ; do as above for extension JNE SRCRET ; if there is one LEA A1,EXTASC(A5) MOV A1,D2 LEA A1,EXTSRC(A5) MOV A1,D0 NXTECH: MOV D2,A0 ADD #1,D2 MOV D0,A1 ADD #1,D0 MOVB @A0,@A1 JNE NXTECH SRCRET: RTN MATTES: MOV D2,A0 ; D2 points to dir entry TSTB @A0 ; if char null string matches JEQ MATYES MOV D0,A0 ; D0 points to search entry MOVB @A0,D7 CMPB D7,#52 ; if * string matches JEQ MATYES MOV D0,A0 ; search entry MOVB @A0,D7 CMPB D7,#77 ; if ? char matches JNE MATCHA ; no MATNEX: ADD #1,D0 ; next search char ADD #1,D2 ; next dir char JMP MATTES ; test MATCHA: MOV D0,A0 ; search char MOV D2,A1 ; dir char MOVB @A0,D7 CMPB D7,@A1 ; test for equality JEQ MATNEX ; yup so try next LCC #0 ; nope so indicate not equal RTN ; and return MATYES: LCC #4 ; indicate equal MATRET: RTN ; common return point MATFIL: LEA A1,FNMASC(A5) ; filename from dir MOV A1,D2 LEA A1,FNMSRC(A5) ; filename to search MOV A1,D0 CALL MATTES ; test for match BNE MATRET ; branch if no match LEA A1,EXTASC(A5) ; extension from dir MOV A1,D2 LEA A1,EXTSRC(A5) ; extension to search MOV A1,D0 JMP MATTES ; test for match CURPOS: WORD 0 CURCOL: BYTE 0 CURROW: BYTE 0 NEXCUR: TST CURPOS(A5) ; cursor set up? JNE INCROW ; yes MOV D2,A0 ; D2 is pointing to start cursor pos ADD #0,A0 ; don't know why MOV @A0,CURPOS(A5) ; store as cursor position POSCUR: MOV CURPOS(A5),D1 ; position cursor TCRT LCC #0 ; indicate NE RTN ; and return INCROW: MOV D2,A1 ; start cursor storage ADD #6,A1 ; +6 = highest line no MOVB CURROW(A5),D7 ; current cursor row CMPB D7,@A1 ; compare with highest JHI INCCOL ; jump if too big CLR D1 ; clear register MOVB CURROW(A5),D1 ; load row ADD #1,D1 ; increment row MOVB D1,CURROW(A5) ; store it JMP POSCUR ; position cursor & return INCCOL: MOV D2,A0 ; start cursor position ADD #3,A0 ; +3 = start row MOVB @A0,CURROW(A5) ; store as row for position CLR D1 ; clear register MOV D2,A0 ; start cursor pos ADD #4,A0 ; +4 = cols per file MOVB @A0,D1 ; load it ADDB CURCOL(A5),D1 ; add current col pos MOVB D1,CURCOL(A5) ; store result MOV D2,A1 ; start cursor position ADD #5,A1 ; +5 = max column no MOVB CURCOL(A5),D7 ; current cursor pos CMPB D7,@A1 ; compare JLO POSCUR ; position cursor if OK CLR CURPOS(A5) ; indicate no position RTN ; return indicating EQ CURTAB: ADD CURPOS(A5),D1 ; new cursor position TCRT ; print it RTN CURCLR: CLR CURPOS(A5) ; no cursor position yet RTN IMAGEM: JOBIDX A6 ; who am I MOV JOBTRM(A6),A0 ORW #23,@A0 ; lower case, no echo, image modes RTN ; this code doesn't seem to be used. Would cancel above settings JOBIDX A6 MOV JOBTRM(A6),A0 ANDW #-24,@A0 RTN GETKBD: KBD ; get char input JOBIDX A6 ; who am I? MOVW (A6),D7 ; status word ANDW #200,D7 ; isolate ^C pending BEQ NOTCC ; branch if not ANDW #-201,(A6) ; say no ^C pending MOV #3,D1 ; indicate user pressed ^C NOTCC: RTN ; this code doesn't seem to be used CLR D1 JOBIDX A6 MOVW (A6),D7 ANDW #200,D7 BEQ 10$ MOV #3,D1 BR 20$ 10$: MOV JOBTRM(A6),A6 TST 22(A6) BEQ 20$ MOV 36(A6),A6 MOVB @A6,D1 AND #177,D1 20$: RTN END .