; M4LOG/ASM ; LOGON SCRIPT INTERPRETER ; ; OUTPUT STRING TO PORT ; ; This code performs the OUTPUT function. Control characters ; are ignored in the output string as far as matching is concerned, ; and they are also ignored in the input port. This allows more ; flexability as far as text recognition is concerned. ; ; e.g. The string XYZPDQ will be output exactly as ; specified, but only the characters "XYZPDQ" will be matched if ; SET OUTPUT HOST-ECHO is ON. Any control characters will be ; ignored. ; OUTPUT EQU $ LD A,CMTXT ;GET SOME TEXT TO SEND LD DE,DATA ;WHERE TO PUT THE STRING LD (SOUPTR),DE ;SET THE ORIGINAL DATA ADDRESS CALL COMND ;GET IT JP KERMT3 ;SAY NOT CONFIRMED ON ERROR LD A,1 LD (SNDFLG),A OUTPUT1 CALL GETFCH ;GET A CHARACTER JR NZ,OUTPUT5 CALL GTREAL ;GET THE ACTUAL IF IT IS SPECIAL JP NZ,SOU400 ;QUIT ON AN ERROR LD E,A ;PUT IT IN E FOR OUTCHR LD A,(DLYFLG) ;WAS IT A DELAY IFZ OUTPUT2 ;Jump is no delay XOR A LD (DLYFLG),A ;RESET THE FLAG JR OUTPUT1 ;GET A NEW CHARACTER OUTPUT2 CALL OUTCHR ;OUT THE PORT WITH IT LD A,(LOGFLG) ;DO WE NEED TO LOGIT TO THE FILE OR A LD A,E ;RESTORE THE CHARACTER IN A CALL NZ,LOGIT ;LOG IT IF LOGFLG IS SET IFALT 32,OUTPUT1 LD A,(ECHFLG) ;IS ECHO ON? IFZ OUTPUT1 ;If not than get the next to send LD A,E ;GET THE CHARACTER BACK IN A PUSH AF ;SAVE IT FOR A SEC OUTPUT3 CALL INPORT ;GET ONE CHARACTER FROM THE PORT JR Z,OUTPUT4 ;Got a character so check it CALL CONIN ;IS THERE A KEY PRESSED? IFZ OUTPUT3 ;Go if there isn't CP 128 ;IS IT BREAK JP Z,SBORT ;QUIT IF IT IS CP 27 ;IS IT ESCAPE JP Z,QUTOUT ;Skip this command CP 129 ;CHECK FOR F1 PRESSED JP Z,QUTOUT ;Skip this command JR OUTPUT3 ;TRY AGAIN TO GET THE ECHO OUTPUT4 LD E,A LD A,(OTDSP) ;LOCAL ECHO ON? OR A LD A,E ;RESTORE A FOR THE CALL TO TRMOUT CALL NZ,TRMOUT ;DISPLAY THE CHARACTER LD A,(LOGFLG) ;IS LOGGING SET? OR A LD A,E CALL NZ,LOGIT ;LOG WHAT WE RECEIVED CALL SETCSE ;SET THE CASE LD E,A ;PUT IT IN E POP AF ;GET THE CHARACTER WE SENT CALL SETCSE ;SET THE CASE IFA E,OUTPUT1 LD A,E IFALT 32,OUTPUT1 ;Ignore CNTL that doesn't match LD DE,NOECHO ;LOAD NO REMOTE-HOST ECHO ERROR JP SBORT2 ;QUIT, NO MATCH OUTPUT5 XOR A ;RESET STATE FLAG LD (SNDFLG),A JP KERMIT ;GET A NEW COMMAND ; ; Do receive character matching. ; ; The KMP pattern matching algorithm is used here for the fun of ; it. In reality, we probably don't need this much power, but ; it is rather elegant!!! ; INPUT EQU $ LD A,CMTXT ;GET SOMETHING TO SEND LD DE,DATA ;WHERE TO PUT THE TEXT LD (SOUPTR),DE ;SAVE THE ADDRESS FOR GETFCH CALL COMND ;GET SOME TEXT, OR FAIL JP KERMT3 ;SAY NOT CONFIRMED ON FAILURE LD A,1 LD (RECFLG),A LD HL,STRING ;GET ADDRESS OF THE BUFFER LD B,0 ;B IS THE LENGTH COUNTER ; ; Gather the string to receive ; INPUT1 CALL GETFCH ;GET A CHARACTER JP NZ,INPUT3 ;QUIT ON AN ERROR CALL GTREAL ;CONVERT ESCAPES, ETC... JP NZ,SOU400 ;QUIT ON AN ERROR LD E,A ;SAVE THE CHARACTER FOR A SEC LD A,(DLYFLG) ;WAS IT A DELAY? IFZ INPUT2 ;Jump if not XOR A ;CLEAR A LD (DLYFLG),A ;RESET THE FLAG JR INPUT1 INPUT2 LD (HL),E ;STORE WHAT WE GOT INC HL ;POINT TO THE NEXT INC B ;ONE MORE TO LENGTH JR NZ,INPUT1 ;JUMP IF NOT BUFFER OVERFLOW LD DE,STOBIG ;LOAD error MESSAGE STRING CALL PRTSTR ;PRINT IT ON THE SCREEN. JP SOU540 ;Jump to end INPUT3 LD (HL),0 ;END IT WITH A NULL ; ; KMP really begins here. The basic C code is in the comments! ; Build the failure link table... ; LD A,B ;B IS THE LENGTH LD (LENGTH),A ;SAVE THE LENGTH M=STRLEN(STR) XOR A ;ZERO a FOR FLINK[1]=0 LD C,1 ;SUBSCRIPT 1 CALL SETLNK ;FLINK[1]=0; LD D,2 ;I=2; INPUT4 LD C,D ;GET I LD A,(LENGTH) ;GET THE LENGTH OF THE STRING CP C ;IF (I <= M) { JP M,INPUT7 ;Jump if I > M LD C,D ;c = I DEC C ;c = I-1 CALL GETLNK ;a = FLINK[c] LD E,A ;J = FLINK[I-1] INPUT5 INC E ;IF (I != 0 DEC E JR Z,INPUT6 ;JUMP IF I = 0 LD C,E ;c = J CALL GETSTG ;a = STRING[J] LD B,A ;b = a LD C,D ;c = I DEC C ;c = I - 1 CALL GETSTG ;a = STRING[I-1] IFA B,INPUT6 LD C,E ;c = J CALL GETLNK ;a = FLINK[J] LD E,A ;J = FLINK[J] JR INPUT5 INPUT6 LD A,E ;A = J INC A ;A = J+1 LD C,D ;C = I CALL SETLNK ;FLINK[I] = J+1 INC D ;I++ JR INPUT4 INPUT7 LD E,0 ;J = 0 LD A,(HSTCHR) ;GET ANY LEFT OVER CHARACTERS IFZ INPUT12 LD C,A ;SAVE A FOR A SEC XOR A ;CLEAR IT OUT LD (HSTCHR),A ;SAY NO REMAINING HOST CHARACTER LD A,C ;RESTORE A INPUT8 LD (CHRGOT),A LD C,A ;SAVE THE CHARACTER LD A,(INDSP) ;CHECK IF WE SHOULD DISPLAY IFZ INPUT9 LD A,C ;GET THE CHARACTER BACK CALL TRMOUT ;PRINT IT INPUT9 LD A,(LOGFLG) ;IS LOGGING ON OR A ;SET THE FLAGS LD A,C ;RESTORE THE CHARACTER INTO A CALL NZ,LOGIT ;LOG THE CHARACTER TO THE FILE INC E ;++J INPUT10 INC E ;IS E == 0 DEC E JR Z,INPUT11 LD C,E ;C = J DEC C ;C = J-1 CALL GETSTG ;A = STRING[J-1] CALL SETCSE ;ADJUST THE CASE LD C,A ;C = A LD A,(CHRGOT) CALL SETCSE ;ADJUST THE CASE IFA C,INPUT11 LD C,E ;C = J CALL GETLNK ;A = FLINK[J] LD E,A ;J = FLINK[J] JR INPUT10 INPUT11 LD A,(LENGTH) ;ARE WE AT THE END IFA E,INPUT13 INPUT12 CALL INPORT ;GET A CHARACTER IF THERE JR Z,INPUT8 ;GO IF WE GOT ONE CALL CONIN ;IS THERE A KEY PRESSED IFZ INPUT12 CP 128 ;IS BREAK PRESSED JP Z,SBORT ;SBORT IF IT IS CP ESC ;IS IT ESCAPE JP Z,QUTOUT ;Skip this command CP 129 ;CHECK IF F1 IS PRESSED AS ESCAPE JP Z,QUTOUT ;Skip this command PUSH DE ;SAVE E LD E,A ;OUTCHR NEEDS CHAR IN E CALL OUTCHR ;SEND IT OUT THE PORT POP DE ;RESTORE E JR INPUT12 ;CHECK AGAIN INPUT13 XOR A ;RESET RECEIVE STATE FLAG LD (RECFLG),A JP KERMIT ;GET A NEW COMMAND ; ; DO MULTIPLE/REPEATING TRANSMITTION UNTIL A CHARACTER IS RECEIVED ; PULSE EQU $ LD A,CMTXT ;GET SOME TEXT LD DE,DATA ;WHERE TO PUT IT LD (SOUPTR),DE ;SAVE THE ADDRESS OF THE BUFFER CALL COMND ;GET SOME TEXT JP KERMT3 ;SAY NOT CONFIRMED ON FAILURE LD A,1 LD (MULFLG),A LD HL,MULBUF ;GET THE BUFFER LD (BUFPTR),HL ;SAVE THE START PULSE1 CALL GETFCH ;GET A CHARACTER JP NZ,PULSE3 ;QUIT ON AN ERROR CALL GTREAL ;GET THE ACTUAL CHARACTER JP NZ,SOU400 LD E,A LD A,(DLYFLG) ;WAS IT A DELAY? IFZ PULSE2 XOR A ;CLEAR A LD (DLYFLG),A ;RESET THE FLAG JR PULSE1 ;GET A NEW CHARACTER PULSE2 LD (HL),E ;SAVE THE CHARACTER INC HL ;POINT TO THE NEXT JR PULSE1 ;DO IT AGAIN PULSE3 PUTHL A ;Save the CR just found LD (HL),0 ;Terminate with a NULL PULSE4 LD BC,3000 ;DELAY COUNTER, MAGICAL NUMBER?!? PULSE5 CALL INPORT ;CHECK FOR A CHARACTER FIRST. JR Z,PULSE9 ;GO IF WE GOT ONE PUSH BC ;SAVE BC CALL CONIN ;CHECK THE KEYBOARD IFZ PULSE6 CP 128 ;IS IT BREAK? POP BC JP Z,SBORT ;SBORT IF IT IS CP ESC ;IS IT ESCAPE? JP Z,QUTOUT ;Skip this command CP 129 ;IS F1 PRESSED FOR ESCAPE? JP Z,QUTOUT ;Skip this command PUSH BC LD E,A ;PUT CHAR IN E FOR OUTCHR CALL OUTCHR ;OUTPUT THE SUCKER! LD A,(LOGFLG) ;CHECK FOR LOGGING TO FILE OR A LD A,E ;GET THE CHARACTER BACK CALL NZ,LOGIT ;GO LOG IT TO THE FILE IF FLAG PULSE6 POP BC DEC BC ;DECREMENT OUR COUNTER LD A,B ;CHECK IT FOR ZERO OR C JR NZ,PULSE5 ;LOOP UNTIL IT IS LD HL,MULBUF ;GET THE STRING ADDRESS PULSE7 LD A,(HL) ;GET A CHARACTER TO SEND CP CR ;IS IT THE END OF THE STRING? JR NZ,PULSE8 ;If not CR than jump INC HL ;CHECK FOR NULL TERMINATOR LD A,(HL) ;GET THE CHARACTER AFTER CR DEC HL ;POINT BACK ONE FOR FAIL IFZ PULSE4 PULSE8 INC HL ;POINT TO NEXT CHAR PUSH HL ;SAVE THE ADDRESS LD E,A ;SEND IT TO THE PORT CALL OUTCHR LD A,(LOGFLG) ;CHECK FOR LOGGING OR A LD A,E ;GET THE CHARACTER BACK CALL NZ,LOGIT ;GO LOG IT TO THE FILE POP HL ;GET THE ADDRESS BACK JR PULSE7 ;TO OF THE LOOP PULSE9 LD (HSTCHR),A ;SAVE THE SENT CHARACTER XOR A ;RESET THE STATE FLAG LD (MULFLG),A JP KERMIT ;GET A NEW COMMAND ; ; PAUSE FOR A CERTAIN NUMBER OF SECONDS ; PAUSE EQU $ LD A,CMNUM ;GET A WHILE TO PAUSE CALL COMND ;GET A NUMBER JP KERMT3 ;SAY NOT CONFIRMED ON AN ERROR IFNZ PAUSE1 ;Jump if at least one digit given LD DE,1 ;Use one second for the default PAUSE1 LD L,E ;SAVE IT LD H,D ;HL IN THE COUNT LD C,30 ;Count * 30 * HL = seconds delay CALL XMUL16 ;Multiply 16 bit HL by 8 bit C LD H,L ;Put the lower 16 bit of the 24 LD L,A ;bit result into HL LD (TIMER),HL ;STORE THE NUMBER LD C,8 ;TASK SLOT # 8 PAUSE2 CALL XCKTSK ;Is the task available? JR NZ,PAUSE3 LD IY,(FLAGS) ;Reset the special key bits in kflag$ LD A,(IY+10) ;Get it AND 0F8H ;Throw out , , and LD (IY+10),A ;Put it back LD DE,ALRMAD ;ADDRESS OF THE ALARM CALL XADTSK ;Add the task JR PAUSE5 ;Go wait for completion PAUSE3 INC C ;Get the next slot CP 11 JR NZ,PAUSE2 STROUT NODELAY ;Issue errormessage LD BC,0FFFFH ;Get a big value CALL XPAUSE ;Use @PAUSE to sleep for awhile JP KERMIT PAUSE5 LD HL,(TIMER) ;CHECK FOR ZERO YET LD A,H OR L JR NZ,PAUSE5 ;LOOP UNTIL EXPIRES JP KERMIT ;QUIT WHEN FLAG IS ZERO ; ; Set or ignore case based on "CSEFLG" ; SETCSE PUSH AF ;SAVE THE CHARACTER LD A,(CSEFLG) ;IS THE OPTION ON? IFZ CPS10 POP AF ;GET THE CHARACTER BACK CPTAL CP 'a' ;CHECK FOR LOWER CASE RET M CP 'z'+1 RET P AND 5FH ;MAKE IT UPPER IF IT IS LOWER JR CAPS20 CPS10 POP AF ;RESTORE AF CAPS20 RET ;RETURN TO THE CALLER ; ; INDEX STRING BY "C" ELEMENTS, AND PUT THE VALUE THERE IN A ; GETSTG LD HL,STRING ;GET STRING AS THE BASE JR GET100 ;JOIN THE CODE GETLNK LD HL,FLINK ;GET FLINK AS THE BASE GET100 PUSH BC ;SAVE BC FOR THE ADD LD B,0 ;MAKE BC A BYTE COUNT ADD HL,BC ;HL NOW POINTS TO IT LD A,(HL) ;A = HL[c] POP BC ;RESTORE BC RET ; ; ASSIGN THE C'th ELEMENT OF A STRING THE VALUE IN A ; SETSTG LD HL,STRING ;GET STRING AS THE BASE JR SET100 ;JOIN THE CODE SETLNK LD HL,FLINK ;GET FLINK AS THE BASE SET100 PUSH BC ;SAVE BC FOR THE ADD LD B,0 ;MAKE BC A BYTE OFFSET ADD HL,BC ;HL POINT TO IT NOW LD (HL),A ;HL[c] = A POP BC ;RESTORE BC RET ; ; PRINT THE MESSAGE IN DE AND QUIT WITH AN ERROR ; SBORT2 CALL PRTSTR ;DISPLAY THE MESSAGE JR SBORT ;CLOSE THE FILE AND EXIT ; ; ISSUE A SYSTEM ERROR MESSAGE FIRST AND SBORT ; SBORT1 CALL XERROR0 ;PRINT A SYSTEM MESSAGE SBORT STROUT LGFAIL ;Operation aborted message JP SOU540 ; ; SURRENDER THE TERMINAL TO THE USER ; QUTOUT STROUT QUTMES ;TELL THEM WHAT WE ARE DOING LD HL,(CMCPTR) LD (HL),EOS STROUT CMDBUF JP KERMIT ;GET A NEW COMMAND ; ; CONTROL COMES HERE AT EOF ; SOU400 LD A,(ESFLG) ;DID WE DIE IN AN ESC SEQ IFZ SOU420 STROUT PREESC ;Print the message JR SOU540 ;CHECK STATE FLAGS SOU420 LD A,(CTLFLG) ;DID WE DIE IN A CTL SEQ IFZ SOU430 STROUT PRECTL ;Print the message JR SOU540 ;CHECK STATE FLAGS SOU430 LD A,(OPTFLG) ;CHECK FOR TYPE EOF OR A JP Z,KERMIT ;ON THIS ONE, GOTO KERMIT STROUT PREOPT ;Print the message JR SOU540 SOU540 LD A,(EXTFLG) ;CHECK FOR EXIT AT EOF OR A ;IS IT SET JP Z,KERMIT ;GOTO GET MORE COMMANDS IF NOT LD A,(TAKFLG) ;CHECK IF TAKE ACTIVE OR A JP Z,KERMIT ;GOTO KERMIT IF NOT LD DE,TFCB CALL XCLOSE ;CLOSE THE TAKE FILE XOR A ;TURN TAKE OFF LD (TAKFLG),A JP KERMIT ;GET A NEW COMMAND ; ; GET \ ESCAPED OR CONTROL'D CHARACTER IF CONTENTS OF "A" SAY SO. ; ALSO , , , ARE RECOGNIZED HERE FOR SEND AND RECEIVE. ; HL MUST CONTAIN ADDRESS OF ROUTINE TO CALL FOR NEXT CHARACTER. ; RETURNS NZ STATUS IF SECOND GET FAILED, OTHERWIZE RETURNS Z. ; GTREAL PUSH HL ;SAVE THE REGS! PUSH BC PUSH DE IFANOT '\',GT010 XOR A LD B,A INC A LD (ESFLG),A CALL GETFCH ;CALL THE SPECIAL ROUTINE JP NZ,GT060 ;QUIT IF END IS FOUND CP '0' JP M,GT005 CP '9'+1 JP P,GT005 GT002 CP '0' JP M,GT003 CP '9'+1 JP P,GT003 SUB '0' SLA B SLA B SLA B ADD A,B LD B,A CALL GETFCH ;CALL THE SPECIAL ROUTINE JR Z,GT002 ;Go on success GT003 LD HL,(SOUPTR) ;Unput the character DEC HL LD (SOUPTR),HL LD (HL),A GT004 LD A,B GT005 PUSH AF XOR A LD (ESFLG),A POP AF JP GT050 GT010 IFANOT '^',GT020 ;Jump if not a control sequence LD A,1 ;SET THE FLAG FOR A GET ERROR LD (CTLFLG),A CALL GETFCH ;CALL THE SPECIAL ROUTINE JP NZ,GT060 SUB 40H ;CONTROLIFY IT BY SUBTRACTING "@" PUSH AF XOR A LD (CTLFLG),A POP AF JP GT050 GT020 CP '<' ;Is it an ANSI sequence JP NZ,GT050 ;RETURN Z STATUS IF NOT LD A,1 ;SET THE STATE FLAG LD (OPTFLG),A LD HL,GTSTRG ;WHERE TO STORE THE STRING GT023 CALL GETFCH ;GET A CHARACTER JP NZ,GT060 ;QUIT ON AN ERROR IFA '>',GT026 CALL CPTAL ;MAKE IT A CAPITAL PUTHL A ;Save the character JR GT023 ;GET SOME MORE GT026 LD (HL),0FFH ;IMPOSSIBLE CHARACTER AS EOL LD HL,CTLTBL ;TOP OF THE TABLE LD B,(HL) ;GET THE NUMBER OF ENTRIES INC HL ;POINT AT THE FIRST CHAR GT028 LD DE,GTSTRG ;Get the buffer we stored into GT030 LD A,(DE) ;Get a character IFANOT (HL),GT040 ;Does it match GT035 GETHL A ;Get the next character INC DE ;Point to next IFALT '0',GT037 ;Check valid range of characters IFAGE 'Z'+1,GT037 ;Jump if we are at the end marker JR GT030 ;Go get the rest of the string GT037 LD C,A ;Save the character LD A,(DE) ;Get the next IFANOT 0FFH,GT040 ;Error if not terminator LD A,C ;RESTORE THE CHARACTER CP DLY ;Is it a delay string? JP Z,DELAY ;Go do it if it is PUSH AF XOR A ;Reset the state flag for EOF LD (OPTFLG),A POP AF JP GT050 ;RETURN Z STATUS GT040 LD C,A ;SAVE THE CHARACTER LD A,(HL) ;WILD CARD? IFANOT '*',GT042 ;Jump if not wild LD A,C ;Get the delay character LD (WLDBUF),A ;SAVE IT IN THE BUFFER JR GT035 ;Join the code for end check GT042 LD A,0FEH ;WHAT TO LOOK FOR PUSH BC ;DON'T KILL B LD BC,0 ;Set max count CPIR ;LOOK AHEAD FOR THE NEXT POP BC ;RESTORE B DJNZ GT028 ;GO LOOK SOMEMORE JP NOCODE ;PRINT A MESSAGE DELAY LD A,(WLDBUF) ;GET THE CHARACTER SUB 48 ;MAKE IT BINARY LD L,A ;SAVE IT LD H,0 ;HL IN THE COUNT LD C,30 ;33.33 MILLISECS * 30 * HL = SECS CALL XMUL16 LD H,L ;SHIFT IT ALL INTO HL LD L,A ;HL = HL * 120 LD (TIMER),HL LD IY,(FLAGS) ;Reset the special key bits in kflag$ LD A,(IY+10) AND 0F8H LD (IY+10),A LD C,8 ;TASK SLOT # 8 LD DE,ALRMAD ;ADDRESS OF THE ALARM CALL XADTSK GT034 LD HL,(TIMER) ;CHECK FOR ZERO YET LD A,H OR L JR NZ,GT034 ;LOOP UNTIL EXPIRES LD A,1 LD (DLYFLG),A ;SET THE DELAY FLAG GT050 CP A ;SET Z STATUS GT060 POP DE ;RESTORE REGS POP BC POP HL RET ;RETURN TO THE CALLER ; ; Print an error message about a bad string inside <...>'s ; NOCODE STROUT BADCD ;PRINT A MESSAGE XOR A INC A ;SET NZ STATUS JR GT060 ; ; ALARM COUNTER ; ALARM PUSH HL ;Save the registers PUSH AF PUSH IY LD IY,(FLAGS) ;Get the system flags LD HL,(TIMER) ;PREVIOUS TIMER VALUE DEC HL ;DECREMENT IT LD (TIMER),HL ;SAVE THE NEW VALUE LD A,H ;IS IT ZERO YET OR L JR NZ,ALARM2 ALARM1 EQU $ RES 0,(IY+10) ;Reset the break bit POP IY POP AF POP HL CALL XKLTSK ;Remove the alarm task, doesn't return RET ;Just in case ALARM2 EQU $ BIT 0,(IY+10) ;Check the break bit JR Z,ALARM5 LD HL,0 LD (TIMER),HL LD H,50 ALARM3 DEC HL LD A,H OR L JR NZ,ALARM3 JR ALARM1 ALARM5 EQU $ POP IY POP AF POP HL RET ; ; GET THE NEXT CHARACTER FROM THE BUFFER ; GETFCH PUSH HL LD HL,(SOUPTR) LD A,(HL) INC HL LD (SOUPTR),HL IFA CR,GTF010 CP A POP HL RET GTF010 CP CR+1 ;Force NZ to be set POP HL RET END ;end of file