;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ ;$ Program name: FASTGO vers. 1.1 $ ;$ Program author: James Whorton $ ;$ Originally written: 04/25/84 $ ;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ ; ;FASTGO 1.1 : A PROGRAM DESIGNED TO MAKE IT EASIER ;TO MOVE TO A SPECIFIC, LABELED DRIVE/USER AREA. ;INTENDED MAINLY FOR HARD DISK SYSTEMS, BUT SHOULD ;WORK EQUALLY WELL ON ANY 2.2 SYSTEM. ALLOWS PASSWORD ;PROTECTING AND CHAINING TO ANOTHER PROGRAM AFTER ;ENTERING NEW USER-AREA. FOR USAGE, TYPE GOTO. ; ;*************************************************** ;REVISIONS: ; ;05/06/84 VERS. 1.1: ; ADDED RELOCATION OF CODE TO HIGHMEM SO ; THAT A .COM FILE MAY BE LOADED AND RAN FROM ; 100H. ADDED DRIVE AND USER # DISPLAY TO ; USAGE ROUTINE. (JHW) ;*************************************************** ; ;WHEN EXECUTED, THIS PROGRAM DOES THE FOLLOWING: ; ;1. RELOCATES ITSELF TO HIGH MEM (SET BY USER). ;2. CHECKS FOR INPUT, PRINTS OPTIONS AND QUITS IF NONE. ;3. EVALUATES INPUT, SEEKING A MATCH FROM THE TABLE. ;4. IF NO MATCH FOUND, TELL USER, DISPLAY OPTIONS AND QUIT. ;5. ON MATCH, CHECK FOR PASSWORD STATUS AND GET IT IF NEEDED. ;6. IF PASSWORD DOESN'T MATCH, ABORT. ;7. SELECT SPECIFIED USER-AREA. ;8. IF RUNCOM = TRUE, LOAD AND RUN A .COM FILE. ;9. EXIT TO SYSTEM. ; ;NOTE: I'VE SEEN A UTILITY OF THIS TYPE ON OTHER ;SYSTEMS, BUT HAVE NEVER BEEN ABLE TO LOCATE THE ;SOURCE CODE. SO I WROTE THIS ONE. THIS CODE IS CRUDE, ;BUT IT DOES THE JOB. I'M PLANNING ON MOVING UP TO A ;HARD DISK SYSTEM IN THE FAIRLY NEAR FUTURE SO I'M ;GATHERING UTILITIES FOR IT. ; ;RENAME THIS FILE TO GOTO.COM. ; GOTO DISPLAYS USAGE AND VALID USER-AREAS ; GOTO USER-AREA MOVES TO USER-AREA. IF PASSWORDED, ; GETS SAME FROM USER BEFORE MOVING. ; ;JAMES H. WHORTON ;402-346-4206 DATA ;402-341-0770 VOICE ; ;--------------------------------------------------- ;THIS IS THE RUNNING LOCATION OF THE MAIN CODE. PUT IT ;HIGH ENOUGH SO THAT THE .COM FILE YOU LOAD, IF ANY, ;WILL NOT OVERLAY IT. ; DEST EQU 0A000H ;RUNNING LOCATION ;..... ;EQUATES SECTION ; WARM EQU 0 ;WARM START BDOS EQU 5 ;BDOS CALL VECTOR CIN EQU 1 ;CONSOLE IN COUT EQU 2 ;CONSOLE CHAR. OUT DIO EQU 6 ;DIRECT I/O CALL CSTAT EQU 12 ;CONSOLE STATUS RSTDSK EQU 13 ;RESET DISK SUBSYSTEM STDSK EQU 14 ;SET DEFAULT DISK OPEN EQU 15 ;OPEN FILE READ EQU 20 ;READ SEQUENTIAL RECORD STDMA EQU 26 ;SET DMA ADDRESS STUSR EQU 32 ;GET/SET USER # FCB EQU 05CH ;FIRST FCB CR EQU 13 ;CARRAIGE RETURN LF EQU 10 ;LINE FEED BELL EQU 7 ;CONSOLE BELL TRUE EQU 0FFH FALSE EQU 0 DEFBYT EQU 4 ;CURRENT DRIVE/USER BYTE ; ;................................................... ; USER SETTABLE OPTIONS ; WIDTH EQU 3 ;# OF COLUMNS TO PRINT ACROSS RUNCOM EQU TRUE ;SET TO TRUE IF CHAIN DESIRED COMDRV EQU 'A'-40H ;DRIVE COM FILE IS ON COMUSR EQU 0 ;USER # COM FILE IS IN DIVID EQU '|' ;DIVIDER CHARACTER FOR DISPLAY ; ;................................................... ;PROGRAM STARTS HERE ; ORG 0100H ; ;THE FOLLOWING ROUTINE MOVES THE BODY OF THE ;PROGRAM UP TO SAFE MEMORY. THE TECHNIQUE OF THE ;$+OFFSET LABELS AND THE LOAD .COM FILE CODE ARE ;ASLO FROM BYE. ; MOVEUP: LXI B,PEND-START+1 ;NUMBER OF BYTES TO MOVE LXI H,DEST+PEND-START+1 ;END OF MOVED CODE LXI D,SOURCE+PEND-START ;END OF SOURCE CODE ; MOVLOP: LDAX D ;GET BYTE DCX H ;BUMP POINTERS MOV M,A ;NEW HOME DCX D DCX B ;BUMP BYTE COUNT MOV A,B ;CHECK IF ZERO ORA C JNZ MOVLOP ;IF NOT, DO SOME MORE ; PUSH H ;SAVE RETURN ADDRESS RET ;RETURN TO NEW ADDRESS ; SOURCE EQU $ ;BOUNDARY MEMORY MARKER ; OFFSET EQU DEST-SOURCE ;RELOCATION AMOUNT ; ;THE FOLLOWING CODE IS THE MAIN BODY OF THE PROGRAM. ;IT IS FIRST MOVED TO DEST, THEN EXECUTED. FROM THIS ;POINT ON, ALL LABELS MUST BE IN THIS FORMAT: ; LABEL EQU $+OFFSET ;SO THAT THE RELOCATION WILL WORK PROPERLY. ; START EQU $+OFFSET ; ;=================================================== ; ;CHECK IF USER-AREA SPECIFIED. ; LDA FCB+1 ;GET FIRST BYTE OF FCB CPI 32 ;BLANK? JZ USAGE ;YES, PRINT USAGE AND QUIT ; ;OK, A USER-AREA WAS SPECIFIED. LET'S SEE HOW LONG ;IT IS MVI B,0 ;SET UP COUNTER LXI H,FCB+1 ;SET UP POINTER LENCHK EQU $+OFFSET MOV A,M ;GET A BYTE INX H ;INCREMENT POINTER INR B ;INCREMENT COUNTER CPI 32 ;IS IT A BLANK? JNZ LENCHK ;NO, GO AGAIN MOV A,B STA USRLEN ;STORE COUNT FOR LATER USE ; ;NOW LET'S START CHECKING THE NAME SPECIFIED AGAINST ;THE TABLE LXI H,TABLE+2;SET UP POINTER SHLD CHARP ;SAVE POINTER NAMCHK EQU $+OFFSET LHLD CHARP ;GET TABLE POINTER MOV A,M ;CHECK FOR END OF TABLE CPI 0 ;ARE WE THERE? JZ NOMATCH ;YES, ERROR MESSAGE AND USAGE LXI D,FCB+1 ;POINT TO INPUT LDA USRLEN ;GET LENGTH OF INPUT MOV B,A ;MOVE IT TO B CALL COMPAR ;DO THE COMPARISON JZ MATCH ;IT'S A MATCH, SO DO IT LXI D,25 ;INCREMENT THE POINTER LHLD CHARP ;GET THE POINTER BACK DAD D ;ADD IT SHLD CHARP ;SAVE IT JMP NAMCHK ;TRY NEXT ENTRY ; ;A MATCH WAS FOUND, SEE IF PWD PROTECTED ; MATCH EQU $+OFFSET LHLD CHARP ;GET ENTRY POINTER DCX H ;BACK UP 1 BYTES MOV A,M ;GET ACCESS CODE CPI '*' ;NEED A PASSWORD? JNZ SELECT ;NOPE, GO AHEAD AND DO IT ;GET A PASSWORD FROM USER CALL ILPRT ;PROMPT USER DB 'Password ? ',0 LXI H,USRPWD;POINT TO STORAGE AREA MVI B,0 ;MAX CHARS ALLOWED = 080H PWD1 EQU $+OFFSET PUSH H PUSH B MVI E,0FFH ;SEE IF CHAR THERE MVI C,DIO CALL BDOS POP B POP H CPI 0 ;CHAR READY? JZ PWD1 ;NOT YET CPI CR ;END OF INPUT? JZ PWD2 ;YES MOV M,A INX H ;INCREMENT POINTER INR B ;INCREMENT CHAR COUNTER MOV A,B ;GET COUNTER IN A TO CHECK CPI 080H ;BUFFER FULL? JZ PWD2 ;NOPE, GET ANOTHER CHAR MOV B,A JMP PWD1 ;PAD INPUT BUFFER WITH SPACES PWD2 EQU $+OFFSET MOV B,A ;GET COUNTER BACK MVI A,32 ;FILL INPUT WITH NULLS MOV M,A ;PUT IT IN STORAGE INX H INR B MOV A,B ;CHECK COUNTER CPI 080H ;FULL YET? JNZ PWD2 ;NOPE, TRY IT AGAIN ; ;NOW DO THE CHECK PWD3 EQU $+OFFSET LHLD CHARP;POINT TO TABLE ENTRY LXI D,13 DAD D LXI D,USRPWD MVI B,10 ;CHECK 10 CHARS (PWD LENGTH) CALL COMPAR ;DO A COMPARISON JZ SELECT ;CORRECT PASSWORD SUPPLIED CALL ILPRT ;NOPE, SAY FORGET IT DB BELL,'++ Invalid password.',CR,LF,0 JMP DONE ;DISPLAY CORRECT AREAS ; ;WE GOT THIS FAR, LET'S CHANGE THE USER # AND DRIVE SELECT EQU $+OFFSET LHLD CHARP ;POINT TO TABLE DCX H ;BACK UP 2 BYTES DCX H MOV A,M ;GET VALUE FROM TABLE PUSH H STA DEFBYT ;PUT IT IN MEMORY BYTE STA DRVUSR ANI 0FH ;MASK OUT USER # STA NEWDRV ;SAVE FOR LATER MOV E,A MVI C,STDSK ;SELECT THE DRIVE CALL BDOS POP H ;NOW SET THE USER # MOV A,M ;GET THE BYTE ANI 0F0H ;MASK OUT DRIVE RAR ;ROTATE 4 TIMES TO GET USER # RAR ;IN PROPER POSITION RAR RAR STA NEWUSR ;SAVE IT FOR LATER MOV E,A ;DO IT MVI C,STUSR CALL BDOS MVI C,RSTDSK CALL BDOS ; ;ROUTINE TO LOAD THE COM FILE ; IF RUNCOM LODCOM EQU $+OFFSET ;SELECT USER # TO LOAD FROM MVI E,COMUSR MVI C,STUSR CALL BDOS ; MVI A,COMDRV;INITIALIZE FCB STA COMFIL LXI H,COMFIL+12 MVI B,21 ; ZLOOP EQU $+OFFSET MVI M,0 INX H DCR B JNZ ZLOOP ; MVI C,OPEN ;NOW OPEN THE FILE LXI D,COMFIL CALL BDOS INR A ;SHOULD BE NON-ZERO JZ NOFILE ;NO FILE, ABORT ; ;NOW LOAD THE FILE LHLD 6 ;GET TOP OF MEMORY LXI D,-80H ;RECORD LOADS CAN'T START.. DAD D ;..ABOVE (BDOS) - 80H PUSH H ;SAVE ON STACK ; LXI D,80H ;TPA-80H LXI B,0 ;KEEP A RECORD COUNTER PUSH B ;SAVE COUNTER PUSH D ;AND LOAD ADDRESS ; GLOOP EQU $+OFFSET POP D ;GET TPA ADRS LXI H,80H ;POINT TO NXT ADRS TO READ TO DAD D ;HL HAS THE ADDRESS POP B ;INCREMENT THE COUNTER ;CHECK FOR LOAD PAST TOP-OF-MEMORY POP D ;GET (TOP-OF-MEMORY) PUSH D ;RE-SAVE FOR NEXT TIME MOV A,E ;SUBTRACT: (TOP) - (ADRS) SUB L MOV A,D ;ONLY THE CARRY NEEDED SBB H JNC SIZEOK ;CY= BETTER MOVCPM CALL ILPRT ;SO TELL THE STORY DB BELL,'++ Program area too small ++ Aborting...',0 JMP DONE ;EXIT ; SIZEOK EQU $+OFFSET INX B PUSH B PUSH H ;SAVE TPA ADRS XCHG ;ALIGN REGISTERS MVI C,STDMA ;TELL BDOS WHERE TO PUT RECORD CALL BDOS LXI D,COMFIL ;NOW READ THE RECORD MVI C,READ CALL BDOS ORA A JZ GLOOP ;A=0 IF MORE TO READ POP B ;UNJUNK STACK POP B ;THIS IS OUR COUNTER POP H ;MORE JUNK ON STACK MOV A,B ;CHECK FOR ZERO ORA C JZ NOFILE ;WE SHOULD HAVE READ SOMETHING LXI D,80H ;WE DID, RESET DMA TO 80H MVI C,STDMA CALL BDOS ; LOADOK EQU $+OFFSET MVI A,' ' ;MAKE THE LOADED PROGRAM THINK STA FCB+1 ;THAT NOTHING WAS PASSED IN THE ;COMMAND LINE LDA NEWDRV ADI 1 ;MAKE IT RIGHT FOR FCB STA FCB ;PUT THE PROPER DRIVE INTO THE FCB ;BEFORE JUMPING TO THE .COM FILE, RESET USER # AND DRIVE LDA NEWUSR ;USER # MOV E,A MVI C,STUSR CALL BDOS LDA NEWDRV ;DRIVE MOV E,A MVI C,STDSK CALL BDOS MVI C,RSTDSK;RESET DISK SYSTEM CALL BDOS ; ;BLANK THE FCB MVI B,11 LXI H,FCB+1 QLOOP EQU $+OFFSET MVI M,' ' INX H DCR B JNZ QLOOP LXI H,FCB+1 ; ;NOW JUMP TO THE CHAIN FILE JMP 0100H ;NOW RUN IT. ; NOFILE EQU $+OFFSET CALL ILPRT DB CR,LF DB BELL,'++ Cannot find COM file ++',0 ; ENDIF JMP DONE ;QUIT ; NOMATCH EQU $+OFFSET CALL ILPRT DB CR,LF,BELL,'++ Invalid user-area specified ++',0 ; ; ;NO OPTION SPECIFIED, OR BAD ONE, SO LIST USAGE AND ;TABLE OF DEFINITIONS. ; USAGE EQU $+OFFSET CALL ILPRT DB CR,LF,'FASTGO 1.1 05/06/84 James Whorton' DB CR,LF,LF,'GOTO Displays user-area info.' DB CR,LF,'GOTO USER-AREA Moves to the specified user-area.' DB CR,LF,LF,'Defined user-areas are --' DB CR,LF,0 ; ;THIS ROUTINE PRINTS THE DEFINITION TABLE. IT PRINTS ; COLUMNS ACROSS AND DOES NOT DISPLAY ANY PASSWORDS. LXI H,TABLE+2;POINT TO NAMES MVI D,13 ;# OF BYTES PER ENTRY TO PRINT MVI B,WIDTH ;# OF COLUMNS TO PRINT CALL HEADER ;PRINT FIRST ENTRY HEADER ;NOW SEND CHAR AND CHECK FOR END OF ENTRY INFO1 EQU $+OFFSET CALL ENDCHK MOV A,M ;BE SURE IT'S THERE CALL CTYPE ;SEND IT INX H ;INCREMENT POINTER DCR D ;DECREMENT CHAR COUNTER MOV A,D ;GET CHAR COUNT TO CHECK CPI 0 ;END OF ENTRY? JNZ INFO1 ;NO, DO ANOTHER BYTE ; ;DONE WITH ONE ENTRY, SO EVALUATE ;FIRST, SKIP PAST PASSWORD SECTION, PRINT DIVIDER ;AND NEW LINE MVI D,13 ;RESET CHAR COUNTER MVI A,12 ;# OF CHARS TO SKIP SKIP EQU $+OFFSET INX H ;INCREMENT POINTER DCR A ;DECREMENT CHAR COUNTER CPI 0 ;PAST IT YET? JNZ SKIP ;NOPE, NOT YET ; CALL ENDCHK ;SEE OF END OF TABLE REACHED DCR B ;DECREMENT COLUMN COUNT MOV A,B ;GET COUNT CPI 0 ;NEED A NEW LINE? JZ SKIP1 ;YES ;PRINT A DIVIDER SECTION PUSH H PUSH D PUSH B MVI E,DIVID MVI C,COUT CALL BDOS POP B POP D POP H CALL HEADER ;PRINT HEADER JMP INFO1 ;NOW BACK TO THE GRIND SKIP1 EQU $+OFFSET MVI A,CR ;START A NEW LINE CALL CTYPE MVI A,LF CALL CTYPE MVI B,3 ;RESET COLUMN COUNTER CALL ENDCHK CALL HEADER JMP INFO1 ; ;CHECK FOR END OF ENTRY TABLE ; ENDCHK EQU $+OFFSET PUSH D PUSH B MOV A,M ;GET BYTE CPI 0 ;END OF TABLE? JZ DONE ;YES, QUIT POP B POP D RET ; DONE EQU $+OFFSET JMP WARM ;QUIT ; ;SUBROUTINES ; ;DISPLAY THE DRIVE AND USER # FROM THE TABLE ENTRY HEADER EQU $+OFFSET PUSH D ;SAVE REGISTERS PUSH B DCX H ;BUMP DOWN 2 DCX H SHLD CHARP ;SAVE POINTER FOR LATER MOV A,M ;GET BYTE ANI 0FH ;GET DRIVE ADI 65 ;MAKE ASCII MOV E,A MVI C,COUT CALL BDOS LHLD CHARP ;GET POINTER BACK MOV A,M ;GET BYTE AGAIN ANI 0F0H ;GET USER # RAR ;ROTATE 4 RAR RAR RAR CPI 9 ;IS IT > 9? JNC DECOUT ;YES, BRANCH TO SUBROUTINE ADI 48 ;NO, SO MAKE ASCII AND PRINT MOV E,A MVI C,COUT CALL BDOS CALL ILPRT DB '> ',0 HEADFIN EQU $+OFFSET POP B ;RESTORE REGISTERS POP D LHLD CHARP ;GET POINTER BACK ONE MORE TIME INX H ;BUMP BACK TO WHERE IT CAME FROM INX H RET ;FINISHED, RETURN ; DECOUT EQU $+OFFSET MOV B,A ;SAVE IT FOR A SEC PUSH B MVI E,'1' ;PRINT FIRST HALF OF VALUE MVI C,COUT CALL BDOS POP B ;GET VALUE BACK MOV A,B SUI 10 ;VALUE-10=SECOND DIGIT VALUE ADI 48 ;MAKE IT ASCII MOV E,A MVI C,COUT CALL BDOS MVI E,'>' MVI C,COUT CALL BDOS JMP HEADFIN ;FINISHED ; ;CONVERT THE ASCII VALUE IN A TO A 2 DIGIT DECIMAL VALUE ;AND PRINT IT ; OUTDEC EQU $+OFFSET ; ;DO A COMPARISON, ABORT IF MATCH FOUND ; ;COMPARE ROUTINE, # OF CHARS IN B, TEXT TO CHECK IN ;DE (INPUT) AND HL (TABLE) ;IF A MATCH, ZERO FLAG WILL BE SET ON EXIT COMPAR EQU $+OFFSET LDAX D ;GET A CHAR. CALL UCASE ;MAKE SURE IT'S UPPER CASE CMP M ;CHECK IT AGAINST TEXT RNZ INX H INX D DCR B JNZ COMPAR RET ; ILPRT EQU $+OFFSET XTHL ILPLP EQU $+OFFSET MOV A,M ORA A JZ ILPRET CALL CTYPE INX H JMP ILPLP ILPRET EQU $+OFFSET XTHL RET ; CTYPE EQU $+OFFSET PUSH B PUSH D PUSH H MOV E,A MVI C,COUT CALL BDOS POP H POP D POP B RET ; UCASE EQU $+OFFSET CPI 061H ;CONVERTS LOWER CASE... RC ;IN A TO UPPER CASE CPI 07BH RNC ANI 05FH RET ;================================================== ;END OF PROGRAM AREA ; ;STORAGE AREA ; USRPWD EQU $+OFFSET DS 080H ;STORAGE FOR INPUT NEWDRV EQU $+OFFSET DS 1 ;STORE NEW DRIVE DRVUSR EQU $+OFFSET DS 1 ; ;***** ;THIS IS THE DEFINITION TABLE SECTION. ; ;FORMAT: ; DB 1,'233333333333334444444444' ; ;BYTE PURPOSE ;--------- ----------------------------------------- ; 1 USER # AND DRIVE (EXAMPLES FOLLOW): ; 00H=A0,01H=B0,010H=A1,011H=B1, ETC. ; 2 ACCESS CODE(* FOR PASSWORDED) ; 3-15 USER-AREA NAME ; 16-25 PASSWORD (IF INDICATED IN ACCESS CODE) ;THE EXAMPLES MAY BE CHANGED, ADDED TO OR DELETED ;AS LONG AS THE PROPER FORMAT IS KEPT. ALL ENTRIES ;IN TABLE SHOULD BE IN UPPER CASE. ; ;FORMAT GUIDE... 1, '233333333333334444444444' TABLE EQU $+OFFSET DB 00H, ' REMOTE ' DB 01H, ' IWOJIMA ' DB 021H,' FILES ' DB 010H,'*RESERVED SORTX ' DB 011H,'*SECRET HOWDY ' DB 012H,' KEEP ' DB 0A1H,' HIGHMEM ' ;NOTE: THE FOLLOWING 4 BYTES MUST BE KEPT AT THE ;END OF THIS TABLE! DB 0,0,0,0 ; ; ;IF YOU WISH TO AUTOBOOT A .COM FILE UPON ENTERING THE ;NEW USER-AREA, SET RUNCOM TO TRUE AND INSERT THE PROPER ;FILE NAME IN COMFIL. ;NOTE: THE .COM FILE YOU CHAIN TO MUST EXIT TO CP/M ;WITH A WARM BOOT OR THE USER-AREA WILL NOT BE CORRECTLY ;SELECTED. ; COMFIL EQU $+OFFSET DB 0,'SD COM' ; ^^^^^^^^^^^ <--MUST BE 11 CHARS. ; CHARP EQU $+OFFSET DS 2 ;NEXT CHAR. ADDRESS POINTER USRLEN EQU $+OFFSET DS 1 ;LENGTH OF USER-AREA SPECIFIED NEWUSR EQU $+OFFSET DS 1 ;NEW USER # TO MOVE TO ; ;** THIS MARKS THE END OF THE CODE TO BE RELOCATED. ; PEND EQU $+OFFSET ; END