; ; termite.s ; ; Implementation of Termite specific instructions ; ; © 1995 Straylight ; ;----- Standard header ------------------------------------------------------ GET libs:header GET libs:swis GET libs:stream ;----- External dependencies ------------------------------------------------ GET sh.anchor GET sh.ctrl GET sh.errNum GET sh.error GET sh.express GET sh.getToken GET sh.interp GET sh.stracc GET sh.strBucket GET sh.termscript GET sh.tokens GET sh.upcalls GET sh.var ;----- Main code ------------------------------------------------------------ AREA |TermScript$$Code|,CODE,READONLY ; --- termite_beep --- EXPORT termite_beep termite_beep ROUT TCALL termite_makeBeep ;Make a beep B interp_next ;And go for more LTORG ; --- termite_break --- EXPORT termite_break termite_break ROUT TCALL termite_sendBreak ;Send the break BL termite__error ;Handle possible error B interp_next ;And go for more LTORG ; --- termite_call --- EXPORT termite_call termite_call ROUT BL ctrl_setUpRegs ;Set up the regs then CMP R10,#vType_integer ;Is this an integer? MOVNE R0,#err_numNeeded ;No -- get error number BNE error_report ;...and report the error MOV R14,PC ;Set up return address MOV PC,R9 ;Execute the code LDR R9,=termite__retned ;Point to some space STMIA R9!,{R0-R8} ;Store returned registers MOV R14,PC,LSR #28 ;Get the flags STMIA R9,{R14} ;Strore the flags too LDMFD R13!,{R7-R12} ;Load back position info LDMFD R13!,{R0} ;Load stracc offset BL stracc_free ;Free any strings I had ; --- We have now done the SWI instr --- LDR R0,=termite__retned ;Point to the returned regs BL ctrl_resolveRegs ;Do the other half now B interp_next ;If flags -- return LTORG ; --- termite_chain --- EXPORT termite_chain termite_chain ROUT ; --- Read a parameter --- MOV R0,#0 ;Read an rvalue BL express_read ;Read it then BL express_pop ;And get it off the stack CMP R1,#vType_string ;Is this a string? MOVNE R0,#err_strNeeded ;Nope -- get error number BNE error_report ;...and report the error LDR R1,tsc_stracc ;Get the stracc address LDR R1,[R1] ADD R1,R1,R0,LSR #8 ;Point to the string AND R2,R0,#&FF ;Get the length ADR R0,tsc_misc+8*4 ;Point to the misc buffer BL termite_copyString ;Copy the string over B tsc_end ;End the script, and chain LTORG ; --- termite_close --- EXPORT termite_close termite_close ROUT MOV R0,#-1 ;Close the session B tsc_end ;Do that then LTORG ; --- termite_cls --- EXPORT termite_cls termite_cls ROUT TCALL termite_clearScreen ;Clear the screen BL termite__error ;Handle possible error B interp_next ;And go for more LTORG ; --- termite_download --- EXPORT termite_download termite_download ROUT MOV R0,#0 ;Read an rvalue BL express_read ;Read it then BL express_pop ;And get it off the stack CMP R1,#vType_string ;Is this a string? MOVNE R0,#err_strNeeded ;Nope -- get error number BNE error_report ;...and report the error ; --- Null terminate this --- MOV R2,R0 ;Look after the offset MOV R5,#0 ;Useful, t' be sure BL stracc_ensure ;Ensure we have space STRB R5,[R0,#0] ;Terminate the string ORR R0,R1,#1 ;Get the rvalue BL stracc_added ;Tell stracc about terminator ; --- Check for another string --- CMP R9,#',' ;Do we have a comma? MOVNE R3,#0 ;No -- use default then BNE %10termite_download ;...and jump ahead BL getToken ;Skip over the comma MOV R0,#0 ;Read an rvalue BL express_read ;Read it then BL express_pop ;And get it off the stack CMP R1,#vType_string ;Is this a string? MOVNE R0,#err_strNeeded ;Nope -- get error number BNE error_report ;...and report the error ; --- Null terminate this --- MOV R3,R0 ;Look after the offset MOV R5,#0 ;Useful, t' be sure BL stracc_ensure ;Ensure we have space STRB R5,[R0,#0] ;Terminate the string ORR R0,R1,#1 ;Get the rvalue BL stracc_added ;Tell stracc about terminator ; --- Do the download now --- 10 LDR R1,tsc_stracc ;Load stracc address MOV R4,R2 ;Look after the offet ADD R2,R1,R2 ;Point to protocal name CMP R3,#0 ;Do we have a filename? ADDNE R3,R1,R3 ;Yes -- point to it then TCALL termite_downLoad ;Do the download BL termite__error ;Handle possible error MOV R0,R4 ;Get offset of protocol name BL stracc_free ;Free it now B interp_next ;Do another instruction LTORG ; --- termite_error --- EXPORT termite_error termite_error ROUT CMP R9,#tok_on ;Is this an option? CMPNE R9,#tok_off BEQ %50termite_error ;Yes -- jump ahead ; --- Read a parameter --- MOV R0,#0 ;Read an rvalue BL express_read ;Read it then BL express_pop ;And get it off the stack CMP R1,#vType_string ;Is this a string? MOVNE R0,#err_strNeeded ;Nope -- get error number BNE error_report ;...and report the error LDR R1,tsc_stracc ;Get the stracc address LDR R1,[R1] ADD R1,R1,R0,LSR #8 ;Point to the string AND R2,R0,#&FF ;Get the length MOV R5,R0 ;look after the rvalue ADR R0,tsc_misc ;Point to the misc buffer MOV R14,#1 ;A sillu error number STR R14,[R0],#4 ;Store that BL termite_copyString ;Copy the string over ADR R0,tsc_misc ;Point to the misc buffer B tsc_error ;Return the error ; --- There was an option --- 50termite_error LDR R0,tsc_flags ;Load the flags word CMP R9,#tok_on ;Turn on the errors? ORREQ R0,R0,#tscFlag_error ;Yes -- set the bit then BICEQ R0,R0,#tscFlag_error ;No -- clear it then STR R0,tsc_flags ;Store the flags back BL getToken ;Skip over the token B interp_next ;Do the next one LTORG ; --- termite_exec --- EXPORT termite_exec termite_exec ROUT ; --- Read a parameter --- MOV R0,#0 ;Read an rvalue BL express_read ;Read it then BL express_pop ;And get it off the stack CMP R1,#vType_string ;Is this a string? MOVNE R0,#err_strNeeded ;Nope -- get error number BNE error_report ;...and report the error LDR R1,tsc_stracc ;Get the stracc address LDR R1,[R1] ADD R1,R1,R0,LSR #8 ;Point to the string AND R2,R0,#&FF ;Get the length MOV R5,R0 ;look after the rvalue ADR R0,tsc_misc+8*4 ;Point to the misc buffer BL termite_copyString ;Copy the string over MOV R0,R5 ;Get the rvalue BL stracc_free ;Free the string from stracc ADR R0,tsc_misc+8*4 ;Point to the misc buffer ORR R0,R0,#(1<<30) ;Make this into an exec BL tsc_end ;Exec new script B interp_next ;Continue happily LTORG ; --- termite_finish --- EXPORT termite_finish termite_finish ROUT TCALL termite_finishSession ;Finish the session B interp_next ;And go round for more LTORG ; --- termite_hangup --- EXPORT termite_hangup termite_hangup ROUT TCALL termite_dropCarrier ;Hang up the modem B interp_next ;And go for more LTORG ; --- termite_lclear --- EXPORT termite_lclear termite_lclear ROUT TCALL termite_clearLocal ;Clear the buffer B interp_next ;And go for more LTORG ; --- termite_lecho --- EXPORT termite_lecho termite_lecho ROUT CMP R9,#tok_off ;Is this an option thingy? CMPNE R9,#tok_local CMPNE R9,#tok_remote CMPNE R9,#tok_both BEQ %50termite_lecho ;Yes -- deal seperately ; --- Just echo the result to the screen then --- MOV R0,#0 ;Read an rvalue BL express_read ;Read the next expression BL express_pop ;Get the value in R0,R1 CMP R1,#vType_integer ;Is this an integer? BEQ %10termite_lecho ;Yes -- jump ahead CMP R1,#vType_string ;Or a string? MOVNE R0,#err_arrayBad BNE error_report ; --- Display a string --- LDR R2,tsc_stracc ;Get the stracc address LDR R2,[R2] ADD R2,R2,R0,LSR #8 ;Point to the string AND R3,R0,#&FF ;Get the length BL termite__doSpool ;Maybe spool this lot TCALL termite_sendLocal ;Write out the message BL termite__error ;Handle possible error BL stracc_free ;Free the string from stracc B %20termite_lecho ;Jump ahead ; --- Display an integer on the screen --- 10termite_lecho ADR R1,tsc_misc ;Point to a nice buffer MOV R2,#256 ;The buffer is big SWI OS_ConvertInteger4 ;Convert the number to a str SUB R3,R1,R0 ;Get the length MOV R2,R0 ;Point at the block BL termite__doSpool ;Maybe spool this lot TCALL termite_sendLocal ;Write out the message BL termite__error ;Handle possible error ; --- Maybe write out the return char --- 20termite_lecho CMP R9,#';' ;Is there a semicolon now? BLEQ getToken ;Yes -- get a token BEQ interp_next ;...read another instr LDR R2,tsc_bucket ;Get the bucket anchor LDR R2,[R2] LDR R0,tsc_lnewline ;Load the newline offset CMP R0,#0 ;Is there one? BEQ interp_next ;No -- stop here then ADD R2,R2,R0 ;Point to the string LDRB R3,[R2,#-1] ;Load out the length BL termite__doSpool ;Maybe spool this lot TCALL termite_sendLocal ;Write out the terminator BL termite__error ;Handle possible error B interp_next ;And read another instruction ; --- Handle the options --- 50termite_lecho LDR R0,tsc_flags ;Load the flags word BIC R0,R0,#tscFlag_echoLR+tscFlag_echoLL CMP R9,#tok_local ;Do we require local echoing? CMPNE R9,#tok_both ORREQ R0,R0,#tscFlag_echoLL ;Yes -- set the flag CMP R9,#tok_remote ;Do we require remote echos? CMPNE R9,#tok_both ORREQ R0,R0,#tscFlag_echoLR ;Yes -- set the flag STR R0,tsc_flags ;Store back the flags word BL getToken ;Get another token B interp_next ;Keep on going then! LTORG ; -- termite_linput --- EXPORT termite_linput termite_linput ROUT MOV R0,#1 ;Read an lvalue BL express_read ;Read it in ; --- Now enter a string reading loop --- BL stracc_ensure ;Make sure that there's room MOV R2,R0 ;Look after address MOV R4,R0 ;Twice MOV R5,#0 ;The length so far MOV R3,#1 ;Length of buffer to echo 00 TCALL termite_readLocal ;Read a byte from the buffer CMP R0,#-1 ;Was there one? BLEQ tsc_wait ;No -- wait for it then LDREQ R2,tsc_stracc LDREQ R2,[R2] ADDEQ R2,R2,R1,LSR #8 ADDEQ R2,R2,R5 BEQ %b00 CMP R0,#127 ;Is this a delete? CMPNE R0,#8 BEQ %f05 ;Yes -- deal with that then CMP R0,#32 ;Was it valid? STRGEB R0,[R2,#0] ;Yes -- store the byte BLGE termite_doLEcho ;Echo the buffer ADDGE R2,R2,#1 ;Increment the pointer ADDGE R5,R5,#1 ;Increment the length CMP R0,#13 ;Are we finished? CMPNE R5,#256 BLT %b00 ;No -- get some more then B %f10 ;Finished -- jump ahead ; --- Do a delete operation --- 05 CMP R5,#0 ;Is the buffer empty? BLE %b00 ;Yes -- do nothing MOV R14,#8 ;Get a backspace STRB R14,[R2,#0] ;Store it... STRB R14,[R2,#2] ;In two places MOV R14,#32 ;And a space too STRB R14,[R2,#1] ;Put that in the middle MOV R3,#3 ;Send 3 characters BLGE termite_doLEcho ;Echo the buffer SUB R2,R2,#1 ;Reduce the address SUB R5,R5,#1 ;And the number of chars MOV R3,#1 ;Put R3 back to 1 B %b00 ;Join main loop again ; --- We have finished reading the string --- 10 ORR R0,R1,R5 ;Get the rvalue MOV R1,#vType_string ;This is a string BL stracc_added ;Tell stracc about this MOV R3,R1 ;Move these up a little MOV R2,R0 BL express_pop ;Get my lvalue off BL ctrl_store ;Store this away B interp_next ;Do another command LTORG ; --- termite_lnewline --- EXPORT termite_lnewline termite_lnewline ROUT CMP R9,#'=' ;Next char must be `=' MOVNE R0,#err_expEq ;If it isn't, moan BNE error_report BL getToken ;Skip past the equals sign LDR R0,tsc_lnewline ;Get existing offset BL strBucket_free ;Free it MOV R0,#0 ;Prepare to read rvalue BL express_read ;Read it then BL express_pop ;Pop it off the stack CMP R1,#vType_string ;Is it a string? MOVNE R0,#err_strNeeded ;No -- get error number BNE error_report ;And report the error BL termite__storeStr ;Store in the bucket STR R0,tsc_lnewline ;Store the new offset B interp_next ;And do the next instruction ; --- termite_log --- EXPORT termite_log termite_log ROUT ; --- Load the first parameter --- MOV R0,#0 ;Read an rvalue BL express_read ;Read it then BL express_pop ;And get it off the stack CMP R1,#vType_string ;Is this a string? MOVNE R0,#err_strNeeded ;Nope -- get error number BNE error_report ;...and report the error LDR R1,tsc_stracc ;Get the stracc address LDR R1,[R1] ADD R1,R1,R0,LSR #8 ;Point to the string AND R2,R0,#&FF ;Get the length MOV R5,R0 ;Look after the rvalue ADR R0,tsc_misc ;Point to the misc buffer BL termite_copyString ;Copy the string over TCALL termite_logFileAdd ;Add the string to the log BL termite__error ;Handle possible error MOV R0,R5 ;Get the rvalue back BL stracc_free ;Free it from stracc B interp_next ;Return to main loop LTORG ; --- termite_newsession --- EXPORT termite_newsession termite_newsession ROUT ; --- Read the base name --- MOV R0,#0 ;Read an rvalue BL express_read ;Read it then BL express_pop ;Get the rvalue CMP R1,#vType_string ;Is it a string? MOVNE R0,#err_numNeeded ;No -- get the error number BNE error_report ;And report the error ; --- NULL terminate it --- ; ; We rely on the fact that there can't be anything else ; after this string. It is also important that we remember ; the stracc offset of this string, so that all the strings ; can be removed from stracc in one go. MOV R3,R1 ;Look after the offset MOV R5,#0 ;Useful, t' be sure BL stracc_ensure ;Ensure we have space STRB R5,[R0,#0] ;Terminate the string ORR R0,R1,#1 ;Get the rvalue BL stracc_added ;Tell stracc about terminator ; --- Read the sub-style name --- MOV R0,#0 ;Read an rvalue BL express_read ;Read it then BL express_pop ;Get the rvalue CMP R1,#vType_string ;Is it a string? MOVNE R0,#err_numNeeded ;No -- get the error number BNE error_report ;And report the error ; --- NULL terminate it --- MOV R6,R1 ;Look after the offset BL stracc_ensure ;Ensure we have space STRB R5,[R0,#0] ;Terminate the string ADD R4,R1,#(1<<8) ;The next string will go here ORR R0,R1,#1 ;Get the rvalue BL stracc_added ;Tell stracc about terminator ; --- Now we keep on adding strings to the list --- 05 CMP R9,#',' ;Do we have a comma? BNE %50termite_newsession ;No -- do the deed then BL getToken ;Skip over the comma MOV R0,#0 ;Read an rvalue BL express_read ;Read it then BL express_pop ;Pop off the string CMP R1,#vType_dimStr ;Is this a string array? BEQ %10termite_newsession ;Yes -- jump ahead CMP R1,#vType_string ;Is it a string? MOVNE R0,#err_strNeeded ;No -- get the error number BNE error_report ;And report the error ; --- We have a string then --- CMP R0,#0 ;Does it have a length? BEQ %05termite_newsession ;No -- find another one then BL stracc_ensure ;Ensure we have space STRB R5,[R0,#0] ;Terminate the string ORR R0,R1,#1 ;Get the rvalue BL stracc_added ;Tell stracc about terminator B %05termite_newsession ;Find another string ; --- We have a string array --- 10 MOV R3,R0 ;Look after rvalue MOV R2,#0 ;Start from the beginning 15 MOV R1,R3 ;Put it in R1 BL termite__enumArray ;Get an element BCC %05termite_newsession ;No more, get another string ANDS R14,R0,#&FF ;Get the length BEQ %15termite_newsession ;Zero -- get another one then BL stracc_ensure ;Ensure we have space STRB R5,[R0,#0] ;Terminate the string ORR R0,R1,#1 ;Get the rvalue BL stracc_added ;Tell stracc about terminator B %15termite_newsession ;Find another element ; --- All the strings are in stracc now --- ; ; First, we terminate the list 50 BL stracc_ensure ;Ensure we have space STRB R5,[R0,#0] ;Terminate the string ORR R0,R1,#1 ;Get the rvalue BL stracc_added ;Tell stracc about terminator ; --- Now, point to the strings --- LDR R5,tsc_stracc ;Load stracc anchor LDR R5,[R5] ADD R0,R5,R3,LSR #8 ;Point to the base name ADD R1,R5,R6,LSR #8 ;Point to the sub-style ADD R2,R5,R4,LSR #8 ;Point to strings TCALL termite_newSession ;Open the session BL termite__error ;Handle possible error MOV R0,R3 ;Put the offset in R0 BL stracc_free ;Free all those strings! B interp_next ;Do the next instruction LTORG ; --- termite_oscli --- EXPORT termite_oscli termite_oscli ROUT ; --- Read a parameter --- MOV R0,#0 ;Read an rvalue BL express_read ;Read it then BL express_pop ;And get it off the stack CMP R1,#vType_string ;Is this a string? MOVNE R0,#err_strNeeded ;Nope -- get error number BNE error_report ;...and report the error LDR R1,tsc_stracc ;Get the stracc address LDR R1,[R1] ADD R1,R1,R0,LSR #8 ;Point to the string AND R2,R0,#&FF ;Get the length MOV R5,R0 ;look after the rvalue ADR R0,tsc_misc ;Point to the misc buffer BL termite_copyString ;Copy the string over SWI Wimp_StartTask ;Do the command MOV R0,R5 ;Get the rvalue back BL stracc_free ;Free the string from stracc B interp_next ;Continue happily LTORG ; --- termite_rclear --- EXPORT termite_rclear termite_rclear ROUT TCALL termite_clearRemote ;Clear the buffer B interp_next ;And go for more LTORG ; --- termite_recho --- EXPORT termite_recho termite_recho ROUT CMP R9,#tok_off ;Is this an option thingy? CMPNE R9,#tok_local CMPNE R9,#tok_remote CMPNE R9,#tok_both BEQ %50termite_recho ;Yes -- deal seperately ; --- Just echo the result to the screen then --- MOV R0,#0 ;Read an rvalue BL express_read ;Read the next expression BL express_pop ;Get the value in R0,R1 CMP R1,#vType_integer ;Is this an integer? BEQ %10termite_recho ;Yes -- jump ahead CMP R1,#vType_string ;Or a string? MOVNE R0,#err_arrayBad BNE error_report ; --- Display a string --- LDR R2,tsc_stracc ;Get the stracc address LDR R2,[R2] ADD R2,R2,R0,LSR #8 ;Point to the string AND R3,R0,#&FF ;Get the length TCALL termite_sendRemote ;Write out the message BL termite__error ;Handle possible error BL stracc_free ;Free the string from stracc B %20termite_recho ;Maybe write out return char ; --- Display an integer on the screen --- 10termite_recho ADR R1,tsc_misc ;Point to a nice buffer MOV R2,#256 ;The buffer is big SWI OS_ConvertInteger4 ;Convert the number to a str SUB R3,R1,R0 ;Get the length MOV R2,R0 ;Point at the block TCALL termite_sendRemote ;Write out the message BL termite__error ;Handle possible error ; --- Maybe write out the return char --- 20termite_recho CMP R9,#';' ;Is there a semicolon now? BLEQ getToken ;Yes -- get a token BEQ interp_next ;...read another instr LDR R2,tsc_bucket ;Get the bucket anchor LDR R2,[R2] LDR R0,tsc_rnewline ;Load the newline offset CMP R0,#0 ;Is there one? BEQ interp_next ;No -- stop here then ADD R2,R2,R0 ;Point to the string LDRB R3,[R2,#-1] ;Load out the length TCALL termite_sendRemote ;Write out the terminator BL termite__error ;Handle possible error B interp_next ;And read another instruction ; --- Handle the options --- 50termite_recho LDR R0,tsc_flags ;Load the flags word BIC R0,R0,#tscFlag_echoRR+tscFlag_echoRL CMP R9,#tok_local ;Do we require local echoing? CMPNE R9,#tok_both ORREQ R0,R0,#tscFlag_echoRL ;Yes -- set the flag CMP R9,#tok_remote ;Do we require remote echos? CMPNE R9,#tok_both ORREQ R0,R0,#tscFlag_echoRR ;Yes -- set the flag STR R0,tsc_flags ;Store back the flags word BL getToken ;Get another token B interp_next ;Keep on going then! LTORG ; --- termite_report --- EXPORT termite_report termite_report ROUT ; --- Read a parameter --- MOV R0,#0 ;Read an rvalue BL express_read ;Read it then BL express_pop ;And get it off the stack CMP R1,#vType_string ;Is this a string? MOVNE R0,#err_strNeeded ;Nope -- get error number BNE error_report ;...and report the error LDR R1,tsc_stracc ;Get the stracc address LDR R1,[R1] ADD R1,R1,R0,LSR #8 ;Point to the string AND R2,R0,#&FF ;Get the length MOV R5,R0 ;look after the rvalue ADR R0,tsc_misc ;Point to the misc buffer BL termite_copyString ;Copy the string over TCALL termite_printMessage ;Report the message MOV R0,R5 ;Get the rvalue back BL stracc_free ;Free the string from stracc B interp_next ;Continue happily LTORG ; --- termite_rinput --- EXPORT termite_rinput termite_rinput ROUT MOV R0,#1 ;Read an lvalue BL express_read ;Read it in ; --- Now enter a string reading loop --- BL stracc_ensure ;Make sure that there's room MOV R2,R0 ;Look after address MOV R4,R0 ;Twice MOV R5,#0 ;The length so far MOV R3,#1 ;Length of buffer to echo 00 TCALL termite_checkCarrier ;Get current carrier state CMP R0,#0 ;Is there one? MOVEQ R0,#0 ;No, return "" BEQ %90termite_rinput ;And jump ahead TCALL termite_readRemote ;Read a byte from the buffer CMP R0,#-1 ;Was there one? BLEQ tsc_wait ;No -- wait for it then LDREQ R2,tsc_stracc LDREQ R2,[R2] ADDEQ R2,R2,R1,LSR #8 ADDEQ R2,R2,R5 BEQ %b00 CMP R0,#127 ;Is this a delete? CMPNE R0,#8 BEQ %f05 ;Yes -- deal with that then CMP R0,#32 ;Was it valid? STRGEB R0,[R2,#0] ;Yes -- store the byte BLGE termite_doREcho ;Echo the buffer ADDGE R2,R2,#1 ;Increment the pointer ADDGE R5,R5,#1 ;Increment the length CMP R0,#13 ;Are we finished? CMPNE R5,#256 BLT %b00 ;No -- get some more then B %f10 ;Finished -- jump ahead ; --- Do a delete operation --- 05 CMP R5,#0 ;Is the buffer empty? BLE %b00 ;Yes -- do nothing MOV R14,#8 ;Get a backspace STRB R14,[R2,#0] ;Store it... STRB R14,[R2,#2] ;In two places MOV R14,#32 ;And a space too STRB R14,[R2,#1] ;Put that in the middle MOV R3,#3 ;Send 3 characters BLGE termite_doREcho ;Echo the buffer SUB R2,R2,#1 ;Reduce the address SUB R5,R5,#1 ;And the number of chars MOV R3,#1 ;Put R3 back to 1 B %b00 ;Join main loop again ; --- We have finished reading the string --- 10 ORR R0,R1,R5 ;Get the rvalue 90 MOV R1,#vType_string ;This is a string BL stracc_added ;Tell stracc about this MOV R3,R1 ;Move these up a little MOV R2,R0 BL express_pop ;Get my lvalue off BL ctrl_store ;Store this away B interp_next ;Do another command LTORG ; --- termite_rnewline --- EXPORT termite_rnewline termite_rnewline ROUT CMP R9,#'=' ;Next char must be `=' MOVNE R0,#err_expEq ;If it isn't, moan BNE error_report BL getToken ;Skip past the equals sign LDR R0,tsc_rnewline ;Get existing offset BL strBucket_free ;Free it MOV R0,#0 ;Prepare to read rvalue BL express_read ;Read it then BL express_pop ;Pop it off the stack CMP R1,#vType_string ;Is it a string? MOVNE R0,#err_strNeeded ;No -- get error number BNE error_report ;And report the error BL termite__storeStr ;Store inthe bucket STR R0,tsc_rnewline ;Store the new offset B interp_next ;And do the next instruction ; --- termite_spool --- EXPORT termite_spool termite_spool ROUT CMP R9,#10 ;Is this a newline? CMPNE R9,#':' ;Or a colon CMPNE R9,#&FF ;Or the end of the file? CMPNE R9,#tok_else ;Or an else BEQ %50 ;Yes -- turn off spooling ; --- Turn on spooling --- ; ; Ooh, spooling, I really dig you. MOV R0,#0 ;Read an rvalue BL express_read ;Read the expression BL express_pop ;Pop the result CMP R1,#vType_string ;Do we have a string? MOVNE R0,#err_strNeeded ;No -- moan at thick user BNE error_report ;Do that then ; --- Copy the string to the misc buffer --- LDR R1,tsc_stracc ;Find the stracc buffer LDR R1,[R1,#0] ;Load the pointer out MOV R2,R0 ;Look after the rvalue ADD R0,R1,R0,LSR #8 ;Find the string base AND R1,R2,#&FF ;And get the length ADR R3,tsc_misc ;Point to destination buffer 00 LDRB R14,[R0],#1 ;Load byte from string STRB R14,[R3],#1 ;Store in destination SUBS R1,R1,#1 ;Decrement the counter BGT %b00 ;And carry on going MOV R14,#0 ;Terminate the string STRB R14,[R3],#1 ;Stick that on the end MOV R0,R2 ;Find the string rvalue BL stracc_free ;Remove it from stracc ; --- Make sure we're not spooling right now --- LDR R1,tsc_spool ;Load the current handle CMP R1,#0 ;Are we spooling? MOVNE R0,#0 ;Yes -- close current file SWINE XOS_Find ;So do that then ; --- Now open the file --- MOV R0,#&8F ;Give me lots of errors ADR R1,tsc_misc ;Point to the buffer SWI XOS_Find ;Find a file handle for it BVS error_reportReal ;If failed, report the error STR R0,tsc_spool ;Save the file handle B interp_next ;Now do another instruction ; --- Close the current file --- 50termite_spool LDR R1,tsc_spool ;Load the current handle CMP R1,#0 ;Are we spooling? MOVNE R0,#0 ;Yes -- close current file SWINE XOS_Find ;So do that then BVS error_reportReal MOV R14,#0 ;Get a zero value STR R14,tsc_spool ;Clear the file handle B interp_next ;Now do another instruction LTORG ; --- termite_syscall --- EXPORT termite_syscall termite_syscall ROUT BL ctrl_setUpRegs ;Set up the regs then CMP R10,#vType_string ;Is this a string? LDREQ R14,tsc_stracc ;Yes -- load the stracc addr# LDREQ R14,[R14] ;Grrrr... ADDEQ R9,R14,R9,LSR #8 ;Point to the string MOVEQ R14,PC ;Yes -- set up return address ADDEQ PC,R11,#termite_sysNumString BVS error_reportReal ;Report possible error CMPNE R10,#vType_integer ;Is this an integer? MOVNE R0,#err_arrayBad ;No -- get error number BNE error_report ;...and report the error TCALL termite_sysCall ;Call the call then! ADR R10,termite__retned ;Point to some space STMIA R10!,{R0-R8} ;Store returned registers MOV R14,PC,LSR #28 ;Get the flags STMIA R10!,{R14} ;Strore the flags too ; --- Convert the string if needed --- LDMFD R13!,{R7-R12} ;Load back position info LDMFD R13!,{R0} ;Load stracc offset BL stracc_free ;Free any strings I had ; --- We have now done the SYSCALL instr --- ADR R0,termite__retned ;Point to the returned regs BL ctrl_resolveRegs ;Do the other half now B interp_next ;No error -- happy termite__retned DCD 0,0,0,0,0,0,0,0,0,0,0 ;For SYSCALL, CALL LTORG ; --- termite_upload --- EXPORT termite_upload termite_upload ROUT ; --- Read the protocol name --- MOV R0,#0 ;Read an rvalue BL express_read ;Read it then BL express_pop ;Get the rvalue CMP R1,#vType_string ;Is it a string? MOVNE R0,#err_numNeeded ;No -- get the error number BNE error_report ;And report the error ; --- NULL terminate it --- ; ; We rely on the fact that there can't be anything else ; after this string. It is also important that we remember ; the stracc offset of this string, so that all the strings ; can be removed from stracc in one go. MOV R3,R1 ;Look after the offset MOV R5,#0 ;Useful, t' be sure BL stracc_ensure ;Ensure we have space STRB R5,[R0,#0] ;Terminate the string ADD R4,R1,#(1<<8) ;The next string will go here ORR R0,R1,#1 ;Get the rvalue BL stracc_added ;Tell stracc about terminator ; --- Now we keep on adding strings to the list --- 05 CMP R9,#',' ;Do we have a comma? BNE %50termite_upload ;No -- do the deed then BL getToken ;Skip over the comma MOV R0,#0 ;Read an rvalue BL express_read ;Read it then BL express_pop ;Pop off the string CMP R1,#vType_dimStr ;Is this a string array? BEQ %10termite_upload ;Yes -- jump ahead CMP R1,#vType_string ;Is it a string? MOVNE R0,#err_strNeeded ;No -- get the error number BNE error_report ;And report the error ; --- We have a string then --- CMP R0,#0 ;Does it have a length? BEQ %05termite_upload ;No -- find another one then BL stracc_ensure ;Ensure we have space STRB R5,[R0,#0] ;Terminate the string ORR R0,R1,#1 ;Get the rvalue BL stracc_added ;Tell stracc about terminator B %05termite_upload ;Find another string ; --- We have a string array --- 10 MOV R3,R0 ;Look after rvalue MOV R2,#0 ;Start from the beginning 15 MOV R1,R3 ;Put it in R1 BL termite__enumArray ;Get an element BCC %05termite_upload ;No more, get another string ANDS R14,R0,#&FF ;Get the length BEQ %15termite_upload ;Zero -- get another one then BL stracc_ensure ;Ensure we have space STRB R5,[R0,#0] ;Terminate the string ORR R0,R1,#1 ;Get the rvalue BL stracc_added ;Tell stracc about terminator B %15termite_upload ;Find another element ; --- All the strings are in stracc now --- ; ; First, we terminate the list 50 BL stracc_ensure ;Ensure we have space STRB R5,[R0,#0] ;Terminate the string ORR R0,R1,#1 ;Get the rvalue BL stracc_added ;Tell stracc about terminator ; --- Now, point to the strings --- LDR R1,tsc_stracc ;Load stracc anchor LDR R1,[R1] MOV R5,R3 ;Look after offset ADD R2,R1,R3,LSR #8 ;Point to the protocol name ADD R3,R1,R4,LSR #8 ;Point to files to upload TCALL termite_upLoad ;Upload the files BL termite__error ;Handle possible error MOV R0,R5 ;Put the offset in R0 BL stracc_free ;Free all those strings! B interp_next ;Do the next instruction LTORG ; --- termite_wait --- EXPORT termite_wait termite_wait ROUT ; --- Read a parameter --- MOV R0,#0 ;Read an rvalue BL express_read ;Read it then BL express_pop ;And get it off the stack CMP R1,#vType_integer ;Is this an integer MOVNE R0,#err_numNeeded ;Nope -- get error number BNE error_report ;...and report the error MOV R1,R0 ;Remember this time SWI OS_ReadMonotonicTime ;Read the current time ADD R1,R1,R0 ;Return after this time ; --- Now enter a waiting loop --- 00 SWI OS_ReadMonotonicTime ;Read the current time CMP R0,R1 ;Have we finished waiting? BLCC tsc_wait ;No -- wait some more BCC %b00 ;...and keep on looping B interp_next ;Go round for next command LTORG ; --- termite_watchfor --- EXPORT termite_watchfor termite_watchfor ROUT ; --- See if we are ending the WATCHFOR --- CMP R9,#tok_end ;Are we ending it? BEQ %70termite_watchfor ;Yes -- jump ahead ; --- First, we must set up strings --- ; ; We actually store the strings in the strBucket. ; In the string list, we have a word for the pointer into ; the string list, and a byte for the match position so far. MOV R5,#0 ;Number so far ADR R3,tsc_wForStrings ;Point to the block MOV R4,#0 ;For the match position STR R5,tsc_wForState ;Reset the state to 0 10 CMP R5,#32 ;Are we at the maximum? MOVGE R0,#err_WFTooMany ;Yes -- get error number BEQ error_report ;And report the error ; --- Now read the strings one at a time --- MOV R0,#0 ;Read an rvalue BL express_read ;Read it then BL express_pop ;Pop off this value CMP R1,#vType_dimStr ;Is this a string array? BNE %19termite_watchfor ;No -- jump ahead ; --- We have a string array --- MOV R1,R0 ;Put the array in R1 MOV R2,#0 ;Start from the beginning 00 BL termite__enumArray ;Get the next string BCC %15termite_watchfor ;No more -- jump ahead BL termite__storeStr ;Store the string CMP R9,#&7e ;Are we case insensitive? ORREQ R0,R0,#(1<<31) ;Yes -- set the flag STMIA R3!,{R0,R4} ;Store information ADD R5,R5,#1 ;Increment the counter B %b00 ;And keep doing this ; --- The array has finished --- 15 CMP R9,#&7e ;Should we skip a token? BLEQ getToken ;Yes - do that then B %25termite_watchfor ;Jump ahead a little ; --- See if it's a string then --- 19 CMP R1,#vType_string ;Is it a string? MOVNE R0,#err_strNeeded ;No -- get the error BNE error_report ;And then report it ; --- We have a string in stracc --- CMP R9,#&7e ;Case insensitive? (#'~') BLEQ getToken ;Yes -- skip over it 20 BL termite__storeStr ;Put it in the bucket ORREQ R0,R0,#(1<<31) ;Set the top bit for insens STMIA R3!,{R0,R4} ;Store inforamtion ADD R5,R5,#1 ;Increment the counter ; --- Do any more we have --- 25 CMP R9,#',' ;Do we have a comma BLEQ getToken ;Yes -- skip over it BEQ %10termite_watchfor ;...and then go round STR R5,tsc_wForNumber ;Store the number of strings ; --- Now we must check the ring buffer --- ; ; We keep taking bytes off until either a match is achieved, ; we have read 255 chars or there are no more in the ; buffer. In any case we then on the buffer. ; If we have 255 chars we simply start all over again. ADR R2,tsc_misc ;Point to the buffer MOV R3,#0 ;Number read so far 00 TCALL termite_readRemote ;Get a byte CMP R0,#-1 ;Was there a byte? BEQ %50termite_watchfor ;No -- jump ahead ADD R3,R3,#1 ;Increment the count STRB R0,[R2],#1 ;Store it in the buffer BL termite__checkWF ;Does this make a match? BCS %50termite_watchfor ;Yes -- jump ahead CMP R3,#255 ;Have we had 255 bytes now? BNE %b00 ;No -- keep on going then ; --- Send on the buffer --- ADR R2,tsc_misc ;Point to the buffer BL termite_doREcho ;Echo it appropriately MOV R3,#0 ;Reset the count to 0 B %b00 ;And start all over again ; --- We have stopped reading bytes --- ; ; Either we ran out of bytes, or we got a match, ; for either case we do the same thing 50 ADR R2,tsc_misc ;Point to the buffer BL termite_doREcho ;Echo it appropriately B interp_next ;Do the next instruction ; --- We are ending the watchfor --- 70 BL getToken ;Gobble up the END BL termite__endWF ;End the WATCHFOR B interp_next ;Do the next command LTORG ; --- termite__endWF --- ; ; On entry: -- ; ; On exit: -- ; ; Use: Ends a WATCHFOR condition. termite__endWF ROUT STMFD R13!,{R0-R3,R14} ;Stack some regsiters ADR R1,tsc_wForStrings ;Point to the string list LDR R2,tsc_wForNumber ;Get the number of strings CMP R2,#0 ;Are there any? BEQ %f05 ;No -- jump ahead then MOV R3,R2,LSL #3 ;Multiply by 8 ADD R1,R1,R3 ;Point just past the last one 00 LDR R0,[R1,#-8]! ;Load out an offset BIC R0,R0,#(1<<31) ;Clear the flag BL strBucket_free ;Remove the string SUBS R2,R2,#1 ;Reduce the count BGT %b00 ;And free the rest 05 STR R2,tsc_wForNumber ;Make that clear LDMFD R13!,{R0-R3,PC}^ ;Return to caller LTORG ; --- termite__checkWF --- ; ; On entry: R0 == byte to check ; ; On exit: CS if that byte caused a match, ; CC otherwise ; ; Use: Tests all the strings in the WATCHFOR list, to see if ; the character caused a match. If it did, then WATCH ; is set. termite__checkWF ROUT STMFD R13!,{R0-R9,R14} ;Stack registers LDR R1,tsc_bucket ;Load the bucket anchor LDR R1,[R1,#0] ;Point to it ADR R2,tsc_wForStrings ;Point to the strings LDR R3,tsc_wForNumber ;Load the number of strings ; --- Get the information on the string --- 00 LDR R7,[R2],#4 ;Load the offset CMP R7,#0 ;Is this one blank? ADDEQ R2,R2,#4 ;Yes -- skip over position BEQ %10termite__checkWF ;Zero length -- ignore BICS R4,R7,#(1<<31) ;Clear the 'insens' bit LDR R5,[R2],#4 ;Load position so far ADD R4,R1,R4 ;Point to the string LDRB R6,[R4,#-1] ;Load the string length ADD R4,R4,R5 ;Point to the character ; --- Now do the comparison --- 02 LDRB R14,[R4,#0] ;Load the next byte MOV R9,R0 ;Put byte to comapre in R8 TST R7,#(1<<31) ;Case insensitive? ORRNE R9,R9,#32 ;Yes -- make lower case ORRNE R14,R14,#32 ;Both of them CMP R9,R14 ;Are they the same? BEQ %05termite__checkWF ;Yes -- jump ahead CMP R5,#0 ;Was that the first char? SUB R4,R4,R5 ;Point to the string start MOV R5,#0 ;Put it back to 0 BNE %02termite__checkWF ;No -- test first char STR R5,[R2,#-4] ;...store that back B %10termite__checkWF ;...jump ahead ; --- The characters matched --- 05 ADD R5,R5,#1 ;Increment position CMP R5,R6 ;Has the string been done? BEQ %20termite__checkWF ;Yes -- we jump ahead then STR R5,[R2,#-4] ;Store the new position ; --- Move onto the next string --- 10 SUBS R3,R3,#1 ;Decrement the string count BGT %00termite__checkWF ;And keep on looking LDMFD R13!,{R0-R9,R14} ;Load back registers BICS PC,R14,#C_flag ;And return to caller ; --- We found a matching string --- 20 LDR R14,tsc_wForNumber ;Get teh number of strings SUB R14,R14,R3 ;Get index-1 ADD R14,R14,#1 ;Get the index STR R14,tsc_wForState ;Store as the state BL termite__endWF ;End the current watchfor LDMFD R13!,{R0-R9,R14} ;Load back registers ORRS PC,R14,#C_flag ;And return to caller LTORG ; --- termite_remoteInput --- ; ; On entry: R0 == handle of script ; R2 == buffer containing bytes read ; R3 == number of bytes in buffer ; R11 == upcall block ; ; On exit: R2 == new buffer containing bytes to put into ring buffer ; R3 == number of bytes in this buffer ; ; Use: If we are not doing a watchfor, then this call will return ; immediately, resulting in all the buffer being sent ; to the ring buffer. ; If we are in a watchfor, then all data received, up until ; a match, is echoed immediatley, and not sent to the buffer. EXPORT termite_remoteInput termite_remoteInput ROUT STMFD R13!,{R14} ;Stack the link register LDR R14,[R0,#:INDEX:tsc_wForNumber] CMP R14,#0 ;Are we in a WATCHFOR? LDMEQFD R13!,{PC}^ ;No -- return AQAP then STMFD R13!,{R0,R4,R5,R12} ;Stack some more registers MOV R12,R0 ;Put workspace in R12 MOV R4,R2 ;Look after buffer address MOV R5,R3 ;Remember number of bytes ; --- Scan the buffer --- 00 LDRB R0,[R4],#1 ;Load a byte SUB R5,R5,#1 ;Reduce the count BL termite__checkWF ;Does this cause a match BCS %10termite_remoteInput ;We have a match CMP R5,#0 ;Have we finished? BGT %b00 ;More to go -- loop ; -- Send this buffer then --- BL termite_doREcho ;Send the buffer MOV R3,#0 ;Put nothing in the buffer B %90termite_remoteInput ;And return to caller ; --- We got a match --- 10 SUB R3,R3,R5 ;Get number to send BL termite_doREcho ;Send the buffer MOV R3,R5 ;Get bytes left MOV R2,R4 ;Point to rest of buffer 90 LDMFD R13!,{R0,R4,R5,R12,PC}^ ;Return to caller LTORG ;----- Utility routines ----------------------------------------------------- ; --- termite_copyString --- ; ; On entry: R0 == buffer to copy string to ; R1 == point to the string ; R2 == length of string to copy ; ; On exit: -- ; ; Use: Copies the string into the buffer. EXPORT termite_copyString termite_copyString ROUT STMFD R13!,{R0-R2,R14} ;Stack registers CMP R2,#0 ;Is this a short string? 00 LDRGTB R14,[R1],#1 ;Load a character STRGTB R14,[R0],#1 ;And then store it SUBS R2,R2,#1 ;Reduce the count BGT %b00 ;And keep on goin' MOV R14,#0 ;Get a terminator STRB R14,[R0],#1 ;Store the byte and return LDMFD R13!,{R0-R2,PC}^ ;Return to caller LTORG ; --- termite_doLEcho --- ; ; On entry: R2 == pointer to the buffer ; R3 == number of bytes to send ; ; On exit: -- ; ; Use: Echos the buffer to local and remote according to the ; current flags, assuming the buffer came from the local input EXPORT termite_doLEcho termite_doLEcho ROUT STMFD R13!,{R0,R3,R14} ;Stack some registers LDR R0,tsc_flags ;Load the flags word TST R0,#tscFlag_echoLR ;Should we echo to remote? MOVNE R14,PC ;Yes -- set up return address ADDNE PC,R11,#termite_sendRemote ;...and send the bytes TST R0,#tscFlag_echoLL ;Should we echo to local? BLNE termite__doSpool ;Yes -- check for spooling MOVNE R14,PC ;Yes -- set up return address ADDNE PC,R11,#termite_sendLocal ;...and send the bytes LDMFD R13!,{R0,R3,PC}^ ;Return to caller LTORG ; --- termite_doREcho --- ; ; On entry: R2 == pointer to the buffer ; R3 == number of bytes to send ; ; On exit: -- ; ; Use: Echos the buffer to local and remote according to the ; current flags, assuming the buffer came from remote input EXPORT termite_doREcho termite_doREcho ROUT STMFD R13!,{R0,R3,R14} ;Stack some registers LDR R0,tsc_flags ;Load the flags word TST R0,#tscFlag_echoRR ;Should we echo to remote? MOVNE R14,PC ;Yes -- set up return address ADDNE PC,R11,#termite_sendRemote ;...and send the bytes TST R0,#tscFlag_echoRL ;Should we echo to local? BLNE termite__doSpool ;Yes -- check for spooling MOVNE R14,PC ;Yes -- set up return address ADDNE PC,R11,#termite_sendLocal ;...and send the bytes LDMFD R13!,{R0,R3,PC}^ ;Return to caller LTORG ; --- termite__doSpool --- ; ; On entry: R2 == pointer to data to spool ; R3 == size of the data ; ; On exit: -- ; ; Use: Maybe writes the data to the current spool file. termite__doSpool ROUT STMFD R13!,{R0-R4,R14} ;Save some registers LDR R1,tsc_spool ;Load the spool handle CMP R1,#0 ;Is spooling enabled? MOVNE R0,#2 ;Yes -- write to the file SWINE XOS_GBPB ;Do the write LDMFD R13!,{R0-R4,PC}^ ;And return to caller LTORG ; --- termite__storeStr --- ; ; On entry: R0 == rvalue of string ; ; On exit: R0 == offset into bucket of string ; ; Use: Puts the string in stracc, into the string bucket. termite__storeStr ROUT STMFD R13!,{R1-R4,R14} ;Stack some registers MOV R2,R0 ;Put the string in R2 MOV R4,R0 ;And in R4 ANDS R0,R2,#&FF ;Get the length MOVEQ R0,#0 ;Zero length, get a zero BEQ %90termite__storeStr ;And return to caller BL strBucket_alloc ;Allocate the bucket LDR R3,tsc_stracc ;Load the bucket anchor LDR R3,[R3] ;This is getting annoying ADD R3,R3,R2,LSR #8 ;Point to the string AND R2,R2,#&FF ;Get the length 00 LDRB R14,[R3],#1 ;Load a character STRB R14,[R0],#1 ;Copy it over SUBS R2,R2,#1 ;Reduce the counter BGT %b00 ;Keep on looping MOV R0,R4 ;Put the rvalue in R0 BL stracc_free ;Remove it from stracc MOV R0,R1 ;Return offset in R0 90 LDMFD R13!,{R1-R4,PC}^ ;Return to caller LTORG ; --- termite__enumArray --- ; ; On entry: R1 == offset of array definition ; R2 == item to read next ; ; On exit: CS if item found, and ; R0 == rvalue of item ; R2 == updated ; CC otherwise ; ; Use: Goes through an string array, returning each item. termite__enumArray ROUT STMFD R13!,{R1,R3,R4,R14} ;Stack registers LDR R3,tsc_varTree ;Point at the tree LDR R3,[R3] ADD R0,R3,R1 ;Point at the array MOV R4,R2 ;Remember the count LDR R14,[R0,#8] ;Load number of items CMP R2,R14 ;Have we finished? BEQ %95termite__enumArray ;Yes -- return then LDR R14,[R0,#4] ;Load number of subscripts ADD R0,R0,#12 ;Point to them ADD R0,R0,R14,LSL #2 ;Point past them ADD R0,R0,R2,LSL #2 ;Point at the item SUB R0,R0,R3 ;Make that an offset MOV R1,#vType_lvString ;The item is a string BL ctrl_load ;Load it out MOV R0,R2 ;Put the rvalue in R0 ADD R2,R4,#1 ;Increment the item pos LDMFD R13!,{R1,R3,R4,R14} ;Load back registers ORRS PC,R14,#C_flag ;And return success 95 LDMFD R13!,{R1,R3,R4,R14} ;Load back registers BICS PC,R14,#C_flag ;And return failure LTORG ; --- termite__error --- ; ; On entry: V flag and R0 determine error condition ; ; On exit: -- ; ; Use: This call will generate an error, if ERROR ON has been ; done, or set the ERROR$ variable otherwise. termite__error ROUT STMFD R13!,{R0-R2,R14} ;Save regiters LDR R1,tsc_flags ;Load the fags word BVS %50termite__error ;Jump ahead if there's an err ; --- There was no error --- TST R1,#tscFlag_error ;Do we generate errors? BNE %90termite__error ;Yes -- just return then ; --- Put a NULL string into ERROR$ --- LDR R0,tsc_errorS ;Get the exesting offset BL strBucket_free ;Free it MOV R0,#0 ;Get a 0 length string STR R0,tsc_errorS ;Save that away B %90termite__error ;Return to caller ; --- There was an error --- 50 TST R1,#tscFlag_error ;Do we generate errors? BNE error_reportReal ;Yes -- report the error then ; --- Copy the string into ERROR$ --- ADD R2,R0,#4 ;Put string pointer in R2 LDR R0,tsc_errorS ;Get the exesting offset BL strBucket_free ;Free it MOV R1,R2 ;Point to the string MOV R0,#0 ;Current sting length 00 LDRB R14,[R1],#1 ;Load a byte CMP R14,#0 ;Is it a NULL one? ADDNE R0,R0,#1 ;No -- increment the length BNE %b00 ;And keep on going ; --- Now copy over the string --- BL strBucket_alloc ;We need this much room STR R1,tsc_errorS ;Store this offset away 00 LDRB R14,[R2],#1 ;Load a byte from string CMP R14,#0 ;Is this the end? STRNE R14,[R0],#1 ;No -- store in ERROR$ BNE %b00 ;And keep doing this ; --- Return to caller --- 90 LDMFD R13!,{R0-R2,PC}^ ;Return to caller LTORG ;----- That's all, folks ---------------------------------------------------- END