REM PROGRAM DIALOG REM A PROGRAM TO AUTOMATICALLY LOG IN AND EXTRACT DATA FROM REM A DATABASE SYSTEM REM REM WRITTEN BY E. VERNON BUCK, SAN LORENZO, CA. (415) 276-4607 REM VERSION 1.1, DEC. 31, 1985. REM REM DIALOG READS "INSTRUCTIONS" FROM AN "INSTRUCTION FILE". THIS FILE REM IS PRODUCED BY ANY EDITOR OR WORD PROCESSOR. THE INSTRUCTION REM FILE TELLS THE PROGRAM HOW TO CONDUCT A "DIALOG" WITH THE REM REMOTE (OR "HOST") COMPUTER. THE INSTRUCTIONS TELL THE PROGRAM REM WHAT MESSAGES TO SEND, AND WHAT MESSAGES TO RECEIVE FROM THE REM HOST. THE PROGRAM CAN ALSO MAKE SOME REM SIMPLE DECISIONS (BRANCHING) BASED ON THE CONTENT OF MESSAGES REM RECEIVED FROM THE HOST. THE DIALOG IS DISPLAYED ON THE REM TERMINAL AS IT HAPPENS, AND (OPTIONALLY) RECORDED REM IN A "LOG" FILE. REM REM THE INSTRUCTIONS AVAILABLE ARE AS FOLLOWS: REM S,ccc...c SEND THE STRING ccc...c TO THE HOST. REM THE SEND COMMAND EXPECTS THE REM CHARACTERS TO BE ECHOED BY THE HOST. REM REM T,ccc...c TRANSMIT THE STRING ccc...c TO THE REM HOST. IDENTICAL TO THE S COMMAND, REM EXCEPT DOES NOT EXPECT AN ECHO. REM REM R,ttt...t RECEIVE A STRING OF CHARACTERS FROM REM THE HOST UNTIL THE "TERMINATION" STRING REM ttt...t IS RECEIVED. ANY NUMBER OF REM CHARACTERS CAN BE RECEIVED BEFORE THE REM TERMINATION STRING IS ENCOUNTERED, BUT REM ONLY THE LAST 2000 (ABOUT 1 SCREENFULL) REM WILL BE RETAINED. REM REM I,ddd...d,n IF THE LAST RECEIVED CHARACTERS REM (INCLUDING THE TERMINATION CHARACTERS REM FROM THE R INSTRUCTION) WERE ddd...d, REM THEN JUMP TO THE INSTRUCTION LINE REM LABELED n. n IS A NUMBER FROM REM 1 TO 9999. REM REM G,n GO TO (JUMP UNCONDITIONALLY) TO THE REM INSTRUCTION LINE LABELED n. REM REM E,i,n IF AN ERROR CONDITION OF TYPE i IS REM DETECTED, THEN GO TO THE REM INSTRUCTION LINE LABELED n. REM i CAN BE: REM "SE" - SEND INSTRUCTION ECHO ERROR REM "RE" - RECEIVE INSTRUCTION REM PARITY, FRAME OR OVERRUN ERROR REM "TO" - TIME OUT REM "CL" - CARRIER LOST. REM n = 0 MEANS IGNORE THE ERROR, AND REM CONTINUE. THIS IS THE DEFAULT. REM n = -1 ("SE" ONLY) MEANS SEND A REM BACKSPACE AND REPEAT THE ERRONEOUS REM CHARACTER REM REM L,lll CONTROL THE AMOUNT OF INFORMATION TO REM BE SAVED IN THE LOG FILE: REM lll=ON -- SAVE RECEIVED DATA ONLY REM lll=OFF-- SAVE NOTHING REM lll=ALL-- SAVE BOTH TRANSMITTED AND REM RECEIVED DATA (DEFAULT) REM REM D,ddd CONTROLS WHETHER THE DIALOG WILL BE REM DISPLAYED ON THE TERMINAL AS IT REM HAPPENS: REM ddd=OFF -- NOT DISPLAYED ON TERMINAL REM ddd=ON -- DISPLAYED ON TERMINAL REM (DEFAULT) REM REM C,p MAKE p THE CONTROL CHARACTER PREFACE REM FOR THE INSTRUCTION LINES THAT FOLLOW. REM I.E., ^M WOULD BE TRANSMITTED AS A REM CTRL-M WHEN p="^". DEFAULT IS "^". REM THE C INSTRUCTION IS NON-EXECUTABLE. REM THAT IS, IT OPERATES ON THE INSTRUC- REM TIONS AS THEY ARE COMPILED, BUT NOT REM AS EXECUTED (SINCE INSTRUCTIONS REM MIGHT BE EXECUTED IN A DIFFERENT REM ORDER). REM REM X EXIT. CLOSE FILES AND RETURN TO CP/M. REM REM INSTRUCTIONS CAN BE PRECEEDED BY A "LABEL NUMBER". THIS IS LIKE A REM LINE NUMBER IN BASIC OR FORTRAN. IT IS OPTIONAL. BUT OF COURSE, IF REM THERE IS AN I, G OR E INSTRUCTION ANYWHERE IN THE INSTRUCTIONS, REM THEN THERE MUST BE A LABELED INSTRUCTION WHICH MATCHES THE REM LABELS GIVEN IN THE I, G OR E INSTRUCTION. EXAMPLE: REM 100,S,hello^M REM ... REM G,100 REM REM NOTES: (1) ALL INSTRUCTION PARAMETERS MUST BE SEPARATED BY COMMAS. REM (2) IF A COMMA IS NEEDED IN A CHARACTER STRING, THEN REM SURROUND THE STRING WITH QUOTES ("..."). REM (3) LEADING BLANKS ARE IGNORED, UNLESS THE STRING IS QUOTED. REM (4) DO NOT USE TAB CHARACTERS (CTRL-I) TO INDENT. REM USE SPACES. REM REM TO INVOKE THE PROGRAM, TYPE REM DIALOG insfile.dlg logfile.log REM WHERE insfile.dlg IS THE FILE CONTAINING THE INSTRUCTIONS, AND REM logfile.log IS THE LOG FILE (TO BE WRITTEN BY DIALOG). THE LOG REM FILE IS OPTIONAL AND CAN SIMPLY BE OMITTED. THERE ARE NO DEFAULT REM FILE NAMES OR EXTENSIONS. REPLACING logfile.log WITH A QUESTION REM MARK WILL CAUSE THE INSTRUCTION FILE TO BE COMPILED, BUT NOT REM EXECUTED, FOR TESTING PURPOSES. REM REM THE INSTRUCTIONS ARE STORED IN VARIABLES REM COMM$ : THE COMMAND REM ARG1$ : THE FIRST ARGUMENT (A STRING) REM ARG2% : THE SECOND ARGUMENT (A NUMBER) REM REM PATCH AREA CONSTANTS: REM DATA.PORT% = I/O DATA PORT FOR MODEM REM CTRL.PORT% = I/O PORT TO READ TO TEST FOR TRANSMIT/RECEIVE REM READY REM TRDY.MASK% = THE BIT TO TEST FOR TRANSMIT READY (IS SET TO 1) REM TRDY.POL% = SET THE SAME BIT AS TRDY.MASK% TO 1 TO REVERSE THE REM POLARITY OF THE TEST (I.E. READY WHEN BIT = 0) REM RRDY.MASK%, RRDY.POL% = SAME FOR RECEIVE READY REM RERR.PORT% = I/O PORT TO READ TO TEST FOR READ ERRORS REM RERR.MASK%, RERR.POL% = BITS TO TEST FOR READ ERRORS (I.E. REM PARITY, FRAME AND/OR OVERRUN), AND POLARITY OF SAME REM RES.PORT% = I/O PORT TO RECEIVE THE FOLLOWING RESET BYTE. (SET TO REM -1 IF NO RESET BYTE IS REQUIRED) REM RERR.RES% = BYTE TO SEND TO RESET PORT TO RESET UART AFTER REM RECEIPT OF PARITY, FRAME OR OVERRUN ERROR REM CARRIER.PORT% = I/O PORT TO READ TO TEST FOR CARRIER PRESENT REM CARRIER.MASK% = THE BIT(S) TO TEST FOR CARRIER PRESENT (E.G. DSR) REM CARRIER.POL% = POLARITY OF CARRIER BIT(S) REM CC.PREF$ = THE CHARACTER THAT PRECEEDS A CHARACTER TO INDICATE REM THAT THE 2ND CHARACTER IS A CONTROL CHARACTER. REM (I.E. ^M = CTRL-M, WHEN CC.PREF$ = "^") REM MAX.TIME = APPROX. TIME OUT TIME. FOR 4MHZ CPU, 1100 ~= 1 SECOND REM REM HOW TO PATCH THE .COM FILE: REM USING DDT.COM, OR SOME OTHER PATCHING PROGRAM, FIND THE FOLLOWING REM DATA STATEMENTS. THEY ARE PREFACED BY THE WORD "PATCH:". CHANGE REM THE NUMBERS FOLLOWING PATCH: TO SUIT YOUR SYSTEM. THEY ARE IN REM DECIMAL AND ASCII, AS FOLLOWS: REM (1) THE UART DATA I/O PORT NUMBER REM (2) THE UART TRANSMIT/RECEIVE READY I/O PORT NUMBER REM (3) THE BIT TO TEST FOR TRANSMIT READY REM (4) THE BIT TO BE EXCLUSIVE OR'ED BEFORE TESTING FOR TRANSMIT REM (5) THE BIT TO TEST FOR RECEIVE READY REM (6) THE BIT TO BE EXCLUSIVE OR'ED BEFORE TESTING FOR RECIEVE REM (7) THE I/O PORT TO READ FOR RECEIVE ERRORS REM (8) THE BIT(S) TO TEST FOR RECEIVE ERRORS (PARITY, FRAME REM AND/OR OVERRUN, ETC.) REM (9) THE BIT(S) TO BE EXCLUSIVE OR'ED WITH THE ERROR BITS REM BEFORE TESTING REM (10) THE I/O PORT TO SEND A RESET BYTE TO (-01 IF NONE) REM (11) BYTE TO SEND TO THE RESET PORT TO RESET UART FOLLOWING REM RECEPTION OF A TRANSMISSION ERROR REM (12) THE I/O PORT TO READ FOR CARRIER PRESENT TEST REM (13) THE BIT(S) TO TEST FOR CARRIER ON (I.E., THE DSR LINE) REM (14) THE BIT(S) TO BE EXCLUSIVE OR'ED WITH THE CARRIER ON BIT REM BEFORE TESTING REM (15) THE DEFAULT CHARACTER TO BE A PREFACE FOR CONTROL REM CHARACTERS REM (16) THE TIME OUT COUNTER MAXIMUM REM DATA "PATCH:",000,001,001,000,002,000,001,008,000 DATA 001,055,001,128,000 DATA "^",066000 REM DIM COMM$(200),ARG1$(200),ARG2%(200),LABEL%(200) DIM BUFFER%(2000) REM REM SET THE I/O PORT PARAMETERS READ GARBAGE$,DATA.PORT%,CTRL.PORT%,TRDY.MASK%,_ TRDY.POL%,RRDY.MASK%,RRDY.POL% READ RERR.PORT%,RERR.MASK%,RERR.POL%,RES.PORT%,RERR.RES%,_ CARRIER.PORT%,CARRIER.MASK%,CARRIER.POL% REM REM SET THE CONTROL CHARACTER PREFACE READ CC.PREF$ REM SET THE TIME OUT COUNTER MAXIMUM READ MAX.TIME REM TRUE% = (0 = 0) FALSE% = (1 = 0) CC.PREF% = ASC(CC.PREF$) REM REM GET THE FILE NAMES FROM CP/M COMMAND REM INST.FILE$ = "" FOR ADDRESS% = 93 TO 100 INST.FILE$ = INST.FILE$ + CHR$(PEEK(ADDRESS%)) NEXT ADDRESS% IF INST.FILE$ = " " THEN GO TO 9600 INST.FILE$ = INST.FILE$ + "." DRIVE% = PEEK(92) IF DRIVE% > 0 THEN _ INST.FILE$ = CHR$(DRIVE% + 64) + ":" + INST.FILE$ FOR ADDRESS% = 101 TO 103 INST.FILE$ = INST.FILE$ + CHR$(PEEK(ADDRESS%)) NEXT ADDRESS% REM LOG.FILE$ = "" FOR ADDRESS% = 109 TO 116 LOG.FILE$ = LOG.FILE$ + CHR$(PEEK(ADDRESS%)) NEXT ADDRESS% NO.LOG.FILE% = (LOG.FILE$ = " " ) COMPILE.ONLY% = (LOG.FILE$ = "? " ) IF NO.LOG.FILE% THEN GO TO 100 LOG.FILE$ = LOG.FILE$ + "." DRIVE% = PEEK(108) IF DRIVE% > 0 THEN _ LOG.FILE$ = CHR$(DRIVE% + 64) + ":" + LOG.FILE$ FOR ADDRESS% = 117 TO 119 LOG.FILE$ = LOG.FILE$ + CHR$(PEEK(ADDRESS%)) NEXT ADDRESS% REM 100 REM REM OPEN THE INSTRUCTION FILE OPEN "I",#1,INST.FILE$ REM REM REM READ THE INSTRUCTIONS INTO MEMORY AND CHECK FOR OBVIOUS REM ERRORS FOR NO.INSTR% = 1 TO 200 REM SET TRAP FOR SYNTAX ERROR & INITIALIZE LABEL% ARRAY LABEL.PRESENT% = FALSE% LABEL%(NO.INSTR%) = 0 REM EXIT LOOP IF NO MORE COMMANDS IF EOF(1) THEN GO TO 500 200 REM INPUT #1, COMMAND$ REM TAKE FIRST CHARACTER AND CONVERT TO UPPER CASE IF NECESSARY ASCII.VAL% = ASC(COMMAND$) IF ASCII.VAL% > 96 AND ASCII.VAL% <= 122 THEN _ FIRST.CHAR$ = CHR$(ASCII.VAL% - 32) ELSE _ FIRST.CHAR$ = CHR$(ASCII.VAL%) REM GO TO APPROPRIATE SECTION TO INTERPRET DIFFERENT INSTRUCTIONS IF FIRST.CHAR$ = "L" THEN GO TO 300 IF FIRST.CHAR$ = "D" THEN GO TO 320 IF FIRST.CHAR$ = "S" OR FIRST.CHAR$ = "R" _ OR FIRST.CHAR$ = "T" THEN GO TO 350 IF FIRST.CHAR$ = "I" THEN GO TO 400 IF FIRST.CHAR$ = "E" THEN GO TO 430 IF FIRST.CHAR$ = "G" THEN GO TO 440 IF FIRST.CHAR$ = "C" THEN GO TO 450 IF FIRST.CHAR$ = "X" THEN GO TO 490 REM REM COMMAND$ IS NONE OF THE INTRINSIC COMMANDS. ASSUME IT IS REM A STATEMENT LABEL REM TEST FOR ILLEGAL COMMAND IF LABEL.PRESENT% OR ASCII.VAL% < 48 OR _ ASCII.VAL% > 57 THEN GO TO 9010 LABEL.VALUE% = VAL(COMMAND$) REM CHECK RANGE OF LABEL IF LABEL.VALUE% < 1 OR LABEL.VALUE% > 9999 THEN GO TO 9015 REM CHECK FOR DUPLICATE LABEL ON A PREVIOUS INSTRUCTION IF NO.INSTR% = 1 THEN GO TO 280 FOR LABEL.NO% = 1 TO NO.INSTR% - 1 IF LABEL%(LABEL.NO%) = LABEL.VALUE% THEN GO TO 9020 NEXT LABEL.NO% 280 REM REM SAVE THIS LABEL LABEL%(NO.INSTR%) = LABEL.VALUE% LABEL.PRESENT% = TRUE% GO TO 200 REM 300 REM REM COMPILE A LOG INSTRUCTION REM READ THE ARGUMENT IF EOF(1) THEN GO TO 9000 INPUT #1, ARGUMENT1$ REM TEST FOR LEGALITY OF ARGUMENT IF ARGUMENT1$ <> "IN" AND ARGUMENT1$ <> "OFF" AND _ ARGUMENT1$ <> "ALL" THEN GO TO 9025 IF ARGUMENT1$ <> "OFF" AND NO.LOG.FILE% THEN GO TO 9005 IF ARGUMENT1$ = "OFF" THEN ARG2%(NO.INSTR%) = 0 IF ARGUMENT1$ = "IN" THEN ARG2%(NO.INSTR%) = 1 IF ARGUMENT1$ = "ALL" THEN ARG2%(NO.INSTR%) = 2 ARG1$(NO.INSTR%) = ARGUMENT1$ GO TO 490 REM 320 REM REM COMPILE D (DISPLAY ON/OFF) COMMAND IF EOF(1) THEN GO TO 9000 INPUT #1, ARGUMENT1$ IF ARGUMENT1$ <> "ON" AND ARGUMENT1$ <> "OFF" _ THEN GO TO 9025 ARG2%(NO.INSTR%) = ( ARGUMENT1$ = "ON" ) ARG1$(NO.INSTR%) = ARGUMENT1$ GO TO 490 REM 350 REM REM COMPILE A SEND OR RECEIVE INSTRUCTION REM READ THE ARGUMENT IF EOF(1) THEN GO TO 9000 INPUT #1, IN.STRING$ REM TEST FOR LEGALITY IF LEN(IN.STRING$) < 1 THEN GO TO 9025 REM CONVERT CONTROL CHARACTERS GO SUB 10000 IF LEN(OUT.STRING$) > 2000 THEN GO TO 9025 ARG1$(NO.INSTR%) = OUT.STRING$ REM SAVE THE CONTROL CHARACTER PREFACE (NEEDED FOR LOGGING) ARG2%(NO.INSTR%) = CC.PREF% GO TO 490 REM 400 REM REM COMPILE AN IF INSTRUCTION REM READ THE 1ST ARGUMENT IF EOF(1) THEN GO TO 9000 INPUT #1, IN.STRING$ REM TEST FOR LEGALITY IF LEN(IN.STRING$) < 1 THEN GO TO 9025 REM CONVERT CONTROL CHARACTERS GO SUB 10000 ARG1$(NO.INSTR%) = OUT.STRING$ REM READ THE 2ND ARGUMENT IF EOF(1) THEN GO TO 9000 INPUT #1, ARGUMENT2% REM TEST FOR REASONABLENESS IF ARGUMENT2% < 1 OR ARGUMENT2% > 9999 THEN GO TO 9030 ARG2%(NO.INSTR%) = ARGUMENT2% GO TO 490 REM 430 REM REM COMPILE AN ON ERROR JUMP IF EOF(1) THEN GO TO 9000 INPUT #1, ARGUMENT1$ IF ARGUMENT1$ <> "RE" AND ARGUMENT1$ <> "SE" _ AND ARGUMENT1$ <> "TO" AND ARGUMENT1$ <> "CL" _ THEN GO TO 9025 ARG1$(NO.INSTR%) = ARGUMENT1$ IF EOF(1) THEN GO TO 9000 INPUT #1, ARGUMENT2% REM TEST FOR REASONABLENESS IF ARGUMENT2% < -1 OR ARGUMENT2% > 9999 THEN GO TO 9030 ARG2%(NO.INSTR%) = ARGUMENT2% GO TO 490 REM REM 440 REM REM COMPILE A JUMP (GOTO) INSTRUCTION IF EOF(1) THEN GO TO 9000 INPUT #1, ARGUMENT2% REM TEST FOR REASONABLENESS IF ARGUMENT2% < 1 OR ARGUMENT2% > 9999 THEN GO TO 9030 ARG2%(NO.INSTR%) = ARGUMENT2% GO TO 490 REM 450 REM REM COMPILE A CHANGE CONTROL CHARACTER PREFACE IF EOF(1) THEN GO TO 9000 INPUT #1, ARGUMENT1$ IF LEN(ARGUMENT1$) <> 1 THEN GO TO 9025 CC.PREF% = ASC(ARGUMENT1$) ARG1$(NO.INSTR%) = ARGUMENT1$ ARG2%(NO.INSTR%) = CC.PREF% GO TO 490 REM 490 REM REM STORE THE COMMAND COMM$(NO.INSTR%) = FIRST.CHAR$ NEXT NO.INSTR% 500 REM NO.INSTR% = NO.INSTR% - 1 REM CLOSE #1 IF NO.INSTR% <= 0 THEN GO TO 9040 REM REM REPLACE THE STATEMENT LABELS IN THE I, E, AND G COMMANDS WITH THE REM ACTUAL LINE NUMBERS REPRESENTED BY THE LABELS FOR I% = 1 TO NO.INSTR% COMMAND$ = COMM$(I%) IF COMMAND$ <> "I" AND COMMAND$ <> "G" _ AND COMMAND$ <> "E" THEN GO TO 800 TARGET.LABEL% = ARG2%(I%) REM IF TARGET IS <= 0, THEN IT'S NOT A LINE NUMBER, SO SKIP IF TARGET.LABEL% <= 0 THEN GO TO 800 REM SEARCH THROUGH THE LIST OF LABELS FOR K% = 1 TO NO.INSTR% IF LABEL%(K%) = TARGET.LABEL% _ THEN GO TO 750 NEXT K% REM LABEL NOT FOUND IN LABEL LIST GO TO 9035 750 REM REM SET ARG2% TO THE LINE NUMBER OF THE LABELED INSTRUCTION ARG2%(I%) = K% 800 REM NEXT I% REM REM REM EXIT IF THIS WAS A COMPILE ONLY RUN IF NOT COMPILE.ONLY% THEN GO TO 900 PRINT "No instruction errors detected in ";INST.FILE$ END REM 900 REM REM EXECUTE THE INSTRUCTIONS REM REM REM OPEN THE LOG FILE IF NOT NO.LOG.FILE% THEN OPEN "O",#2,LOG.FILE$ REM INITIALIZE INSTRUCTION COUNTER INST.LIN% = 0 REM INITIALIZE LOGGING FLAG IF NO.LOG.FILE% THEN LOG.FLAG% = 0 ELSE LOG.FLAG% = 2 REM INITIALIZE TERMINAL DISPLAY ON FLAG DISPLAY% = TRUE% REM INITIALIZE ON ERROR TARGET LINE NUMBER RERR.LIN% = 0 SERR.LIN% = 0 TERR.LIN% = 0 CERR.LIN% = 0 REM INITIALIZE BUFFER POINTER CHAR.NO% = 0 REM REM REM TOP OF EXECUTION LOOP 1000 REM INST.LIN% = INST.LIN% + 1 IF INST.LIN% > NO.INSTR% OR INST.LIN% < 1 _ THEN GO TO 9550 COMMAND$ = COMM$(INST.LIN%) IF COMMAND$ = "S" OR COMMAND$ = "T" THEN GO TO 2000 IF COMMAND$ = "R" THEN GO TO 3000 IF COMMAND$ = "I" THEN GO TO 4000 IF COMMAND$ = "G" THEN GO TO 4400 IF COMMAND$ = "E" THEN GO TO 4500 IF COMMAND$ = "L" THEN GO TO 5000 IF COMMAND$ = "D" THEN GO TO 5100 IF COMMAND$ = "C" THEN GO TO 1000 IF COMMAND$ = "X" THEN GO TO 9550 REM REM 2000 REM REM EXECUTE THE SEND COMMAND REM REM GET THE STRING CHARS.OUT$ = ARG1$(INST.LIN%) REM GET THE NUMBER OF CHARACTERS TO SEND NO.OUT% = LEN(CHARS.OUT$) REM COPY THE CHARACTERS INTO THE OUTPUT BUFFER FOR CHAR.NO% = 1 TO NO.OUT% BUFFER%(CHAR.NO%) = ASC(MID$(CHARS.OUT$,CHAR.NO%,1)) NEXT CHAR.NO% REM REM IF LOG.FLAG% IS 2, WRITE CHARACTERS TO LOG FILE. IF NOT DISPLAY% AND LOG.FLAG% < 2 THEN GO TO 2400 REM MUST REINSERT THE CONTROL CHARACTER PREFACE. PRNT.PREF$ = CHR$(ARG2%(INST.LIN%)) FOR CHAR.NO% = 1 TO NO.OUT% CHAR% = BUFFER%(CHAR.NO%) IF CHAR% < 32 THEN GO TO 2200 PRNT.CHAR$ = CHR$(CHAR%) IF DISPLAY% THEN PRINT PRNT.CHAR$; IF LOG.FLAG% = 2 THEN PRINT #2, PRNT.CHAR$; GO TO 2300 2200 REM REM WRITE PRINTABLE CONTROL CHARACTER IF DISPLAY% THEN PRINT PRNT.PREF$; PRNT.CHAR$ = CHR$(CHAR% + 64) IF DISPLAY% THEN PRINT PRNT.CHAR$; IF LOG.FLAG% < 2 THEN GO TO 2300 PRINT #2, PRNT.PREF$; PRINT #2, PRNT.CHAR$; 2300 REM NEXT CHAR.NO% REM REM WRITE , TO LOG FILE IF DISPLAY% THEN PRINT "" IF LOG.FLAG% = 2 THEN PRINT #2, "" 2400 REM REM REM CLEAR THE MODEM RECEIVER REGISTER IF COMMAND$ = "S" THEN GARBAGE% = INP(DATA.PORT%) REM REM NOW SEND THE CHARACTERS TO THE OUTPUT PORT FOR CHAR.NO% = 1 TO NO.OUT% CHAR.OUT% = BUFFER%(CHAR.NO%) 2420 REM REM REM WAIT FOR READY SIGNAL FROM CONTROL PORT TIME.COUNT = 0.0 2425 REM REM IF ENABLED, TEST FOR TIME OUT IF TERR.LIN% > 0 AND TIME.COUNT > MAX.TIME THEN _ GO TO 2440 ELSE TIME.COUNT = TIME.COUNT + 1.0 REM IF ENABLED, TEST FOR CARRIER STILL PRESENT IF (CERR.LIN% > 0) AND _ ((INP(CARRIER.PORT%) XOR CARRIER.POL%) AND _ CARRIER.MASK%) = 0 THEN GO TO 2445 REM SEE IF TRANSMITTER READY FOR NEW CHARACTER ELSE LOOP IF ((INP(CTRL.PORT%) XOR TRDY.POL%) AND TRDY.MASK%) = 0 _ THEN GO TO 2425 REM REM SEND CHARACTER OUT DATA.PORT%,CHAR.OUT% REM REM SKIP ECHO IF T COMMAND IF COMMAND$ = "T" THEN GO TO 2500 REM WAIT FOR ECHO IN RECEIVER REM TIME.COUNT IS NOT REINITIALIZED UNTIL ECHO IS RECEIVED 2430 REM REM IF ENABLED, TEST FOR TIME OUT IF TERR.LIN% > 0 AND TIME.COUNT > MAX.TIME THEN _ GO TO 2440 ELSE TIME.COUNT = TIME.COUNT + 1.0 REM IF ENABLED, TEST FOR CARRIER PRESENT IF (CERR.LIN% > 0) AND _ ((INP(CARRIER.PORT%) XOR CARRIER.POL%) AND _ CARRIER.MASK%) = 0 THEN GO TO 2445 REM SEE IF ECHOED CHARACTER HAS BEEN RECEIVED, ELSE LOOP IF ((INP(CTRL.PORT%) XOR RRDY.POL%) AND RRDY.MASK%) = 0 _ THEN GO TO 2430 REM REM GET ECHO AND STRIP PARITY BIT ECHO% = INP(DATA.PORT%) AND 127 REM REM TEST ECHO IF ON ERROR TESTING IS ENABLED IF SERR.LIN% = 0 OR ECHO% = CHAR.OUT% THEN GO TO 2500 IF SERR.LIN% = -1 THEN GO TO 2450 INST.LIN% = SERR.LIN% - 1 IF DISPLAY% THEN PRINT "<<<-Send echo error" IF LOG.FLAG% > 0 THEN PRINT #2, _ "<<<-Send echo error" GO TO 2510 REM 2440 REM REM TIME OUT DURING SEND PROCEDURE INST.LIN% = TERR.LIN% - 1 IF DISPLAY% THEN PRINT "<<<-Send time out" IF LOG.FLAG% > 0 THEN PRINT #2, "<<<-Send time out" GO TO 2510 REM 2445 REM REM CARRIER LOST WHILE ATTEMPTING TO SEND A CHARACTER INST.LIN% = CERR.LIN% - 1 REM RESET I/O ERROR SO WON'T GIVE FALSE ALARM ON NEXT CHARACTER IF RES.PORT% >= 0 THEN OUT RES.PORT%,RERR.RES% REM CLEAR THE RECEIVER BUFFER GARBAGE% = INP(DATA.PORT%) IF DISPLAY% THEN PRINT "<<<-Carrier lost" IF LOG.FLAG% > 0 THEN PRINT #2, "<<<-Carrier lost" GO TO 2510 REM 2450 REM REM REM AUTOMATIC RE-TRY OPTION (E INSTRUCTION E,SE,-1) REM WAIT FOR READY SIGNAL FROM CONTROL PORT 2455 REM REM IF ENABLED, TEST FOR TIME OUT IF TERR.LIN% > 0 AND TIME.COUNT > MAX.TIME THEN _ GO TO 2440 ELSE TIME.COUNT = TIME.COUNT + 1.0 REM IF ENABLED, TEST FOR CARRIER STILL PRESENT IF (CERR.LIN% > 0) AND _ ((INP(CARRIER.PORT%) XOR CARRIER.POL%) AND _ CARRIER.MASK%) = 0 THEN GO TO 2445 REM SEE IF TRANSMITTER READY FOR NEW CHARACTER ELSE LOOP IF ((INP(CTRL.PORT%) XOR TRDY.POL%) AND TRDY.MASK%) = 0 _ THEN GO TO 2455 REM REM SEND BACKSPACE CHARACTER OUT DATA.PORT%,8 REM REM GET BACKSPACE ECHO REM WAIT FOR ECHO IN RECEIVER 2460 REM REM IF ENABLED, TEST FOR TIME OUT IF TERR.LIN% > 0 AND TIME.COUNT > MAX.TIME THEN _ GO TO 2440 ELSE TIME.COUNT = TIME.COUNT + 1.0 REM IF ENABLED, TEST FOR CARRIER STILL PRESENT IF (CERR.LIN% > 0) AND _ ((INP(CARRIER.PORT%) XOR CARRIER.POL%) AND _ CARRIER.MASK%) = 0 THEN GO TO 2445 REM GET I/O STATUS BYTE AND LOOP UNTIL CHARACTER READY IF ((INP(CTRL.PORT%) XOR RRDY.POL%) AND RRDY.MASK%) = 0 _ THEN GO TO 2460 REM REM GET ECHOED BACKSPACE GARBAGE% = INP(DATA.PORT%) REM GO BACK AND TRY TO SEND CHARACTER AGAIN GO TO 2425 REM 2500 REM REM NEXT CHAR.NO% 2510 REM REM REM SET CHAR.NO% TO 0. USED AS FLAG BY "I" COMMAND. CHAR.NO% = 0 GO TO 1000 REM 3000 REM REM RECEIVE A STRING. HALT RECEPTION WHEN A TERMINATION REM STRING IS FOUND. REM REM GET TERMINATION STRING TERM.STRING$ = ARG1$(INST.LIN%) REM GET LENGTH OF TERMINATION STRING MINUS 1. NO.TERM.M1% = LEN(TERM.STRING$) - 1 REM INITIALIZE THE TEST STRING AND BUFFER COUNTER TEST.STRING$ = "" CHAR.NO% = 0 WRAPPED% = FALSE% REM 3010 REM REM WAIT FOR CHARACTER READY SIGNAL FROM CONTROL PORT TIME.COUNT = 0.0 3020 REM REM IF ENABLED, TEST FOR TIME OUT IF TERR.LIN% > 0 AND TIME.COUNT > MAX.TIME THEN _ GO TO 3070 ELSE TIME.COUNT = TIME.COUNT + 1.0 REM IF ENABLED, TEST FOR CARRIER STILL PRESENT IF (CERR.LIN% > 0) AND _ ((INP(CARRIER.PORT%) XOR CARRIER.POL%) AND _ CARRIER.MASK%) = 0 THEN GO TO 3060 REM GET I/O STATUS BYTE AND LOOP UNTIL CHARACTER READY IF ((INP(CTRL.PORT%) XOR RRDY.POL%) AND RRDY.MASK%) = 0 _ THEN GO TO 3020 REM REM GET CHARACTER FROM DATA PORT AND STRIP OFF PARITY BIT CHAR% = INP(DATA.PORT%) AND 127 REM ADD THE CHARACTER TO THE BUFFER CHAR.NO% = CHAR.NO% + 1 REM SEE IF BUFFER IS FULL IF CHAR.NO% <= 2000 THEN GO TO 3050 REM WRAP THE BUFFER POINTER BACK TO BEGINNING AND SET FLAG CHAR.NO% = 1 WRAPPED% = TRUE% 3050 REM BUFFER%(CHAR.NO%) = CHAR% REM REM IF ENABLED, CHECK FOR DATA (PARITY, ETC.) ERROR IF (RERR.LIN% <= 0) OR ((INP(RERR.PORT%) XOR RERR.POL%) AND _ RERR.MASK%) = 0 THEN GO TO 3080 REM ERROR FOUND INST.LIN% = RERR.LIN% - 1 REM RESET I/O ERROR SO WONT GIVE FALSE ALARM ON NEXT CHARACTER IF RES.PORT% >= 0 THEN OUT RES.PORT%,RERR.RES% REM PRINT ALERT MESSAGE IF DISPLAY% THEN PRINT "Receive data error->>>" IF LOG.FLAG% >= 1 THEN PRINT #2, _ "Receive data error->>>" REM SKIP THE TERMINATION STRING TEST, BUT LOG AND PRINT THE REM DATA RECEIVED SO FAR GO TO 3090 REM 3060 REM REM CARRIER LOST WHILE TRYING TO RECEIVE INST.LIN% = CERR.LIN% - 1 REM RESET I/O ERROR SO WON'T GIVE FALSE ALARM ON NEXT CHARACTER IF RES.PORT% >= 0 THEN OUT RES.PORT%,RERR.RES% REM CLEAR THE RECEIVER BUFFER GARBAGE% = INP(DATA.PORT%) IF DISPLAY% THEN PRINT "Carrier lost->>>" IF LOG.FLAG% >= 1 THEN PRINT #2, _ "Carrier lost->>>" GO TO 3090 REM 3070 REM REM TIME OUT ERROR EXIT FOR RECEIVE INST.LIN% = TERR.LIN% - 1 IF DISPLAY% THEN PRINT "Receive time out->>>"; IF LOG.FLAG% >= 1 THEN PRINT #2, _ "Receive time out->>>"; GO TO 3090 REM 3080 REM REM DELETE THE LEFT MOST CHARACTER FROM TEST STRING AND ADD REM THE NEW CHARACTER TO THE RIGHT END TEST.STRING$ = RIGHT$(TEST.STRING$,NO.TERM.M1%) + CHR$(CHAR%) REM REM SEE IF TEST STRING IS TERMINATION STRING REM ELSE GO BACK FOR NEXT CHARACTER IF TEST.STRING$ <> TERM.STRING$ THEN GO TO 3010 REM REM TERMINATION STRING FOUND. IF LOGGING IS ON, SAVE TO DISK 3090 REM IF NOT WRAPPED% THEN GO TO 3200 FOR I% = CHAR.NO% + 1 TO 2000 PRNT.CHAR$ = CHR$(BUFFER%(I%)) IF DISPLAY% THEN PRINT PRNT.CHAR$; IF LOG.FLAG% >= 1 THEN PRINT #2, PRNT.CHAR$; NEXT I% 3200 REM FOR I% = 1 TO CHAR.NO% PRNT.CHAR$ = CHR$(BUFFER%(I%)) IF DISPLAY% THEN PRINT PRNT.CHAR$; IF LOG.FLAG% >= 1 THEN PRINT #2, PRNT.CHAR$; NEXT I% REM GO TO 1000 REM 4000 REM REM EXECUTE AN IF MATCH THEN BRANCH INSTRUCTION. REM RIGHT- MOST CHARACTER OF TEST STRING IS ALIGNED WITH THE REM MOST RECENTLY RECEIVED CHARACTER (INCLUDING THE TERMINATION REM CHARACTER(S)) IN THE R COMMAND. REM VARIABLE CHAR.NO% WILL BE > 0 ONLY IF PRECEEDING INSTRUCTION REM WAS A RECEIVE. THE I INSTRUCTION CAN ONLY BE EXECUTED IF REM CHARACTERS HAVE BEEN RECEIVED. IF CHAR.NO% <= 0 THEN GO TO 1000 REM GET THE STRING WE ARE LOOKING FOR TEST.STRING$ = ARG1$(INST.LIN%) NO.TEST% = LEN(TEST.STRING$) REM SEE IF BUFFER HAS AT LEAST AS MANY CHARACTERS AS STRING IF NO.TEST% > CHAR.NO% AND NOT WRAPPED% THEN GO TO 1000 REM VARIABLE TEST.CHAR.NO% POINTS TO A CHARACTER IN TEST STRING TEST.CHAR.NO% = NO.TEST% + 1 REM COMPARE THE CHARACTERS, FROM RIGHT TO LEFT FOR I% = CHAR.NO% TO 1 STEP -1 TEST.CHAR.NO% = TEST.CHAR.NO% - 1 REM IF NO MORE CHARACTERS TO COMPARE IN STRING, THEN IT MATCHED IF TEST.CHAR.NO% = 0 THEN GO TO 4100 TEST.CHAR% = ASC(MID$(TEST.STRING$,TEST.CHAR.NO%,1)) REM END TEST AT FIRST MISMATCH IF BUFFER%(I%) <> TEST.CHAR% THEN _ GO TO 1000 NEXT I% REM REM IN CASE BUFFER WAS WRAPPED, THEN CONTINUE COMPARING CHARS IF NOT WRAPPED% THEN GO TO 4100 REM IF WRAPPED, THEN CONTINUE FROM END OF BUFFER% FOR I% = 2000 TO CHAR.NO% + 1 STEP -1 TEST.CHAR.NO% = TEST.CHAR.NO% - 1 IF TEST.CHAR.NO% = 0 THEN GO TO 4100 TEST.CHAR% = ASC(MID$(TEST.STRING$,TEST.CHAR.NO%,1)) IF BUFFER%(I%) <> TEST.CHAR% THEN _ GO TO 1000 NEXT I% 4100 REM REM IF WE HAVE GOTTEN THIS FAR (I.E. WE HAVE NOT BEEN SENT REM BACK TO LINE 1000) THEN WE DEFINITELY HAVE A MATCH. INST.LIN% = ARG2%(INST.LIN%) - 1 GO TO 1000 REM 4400 REM REM EXECUTE A JUMP (GO TO) INSTRUCTION INST.LIN% = ARG2%(INST.LIN%) - 1 GO TO 1000 REM 4500 REM REM EXECUTE AN ON ERROR GO TO INSTRUCTION ARGUMENT1$ = ARG1$(INST.LIN%) IF ARGUMENT1$ = "RE" THEN _ RERR.LIN% = ARG2%(INST.LIN%) IF ARGUMENT1$ = "SE" THEN _ SERR.LIN% = ARG2%(INST.LIN%) IF ARGUMENT1$ = "TO" THEN _ TERR.LIN% = ARG2%(INST.LIN%) IF ARGUMENT1$ = "CL" THEN _ CERR.LIN% = ARG2%(INST.LIN%) GO TO 1000 REM 5000 REM REM CHANGE THE LOG FLAG LOG.FLAG% = ARG2%(INST.LIN%) GO TO 1000 REM 5100 REM REM CHANGE THE DISPLAY (PRINT TO TERMINAL) FLAG DISPLAY% = ARG2%(INST.LIN%) GO TO 1000 REM 6000 REM REM REM REM ERROR MESSAGES 9000 REM PRINT "Error: end of file at line #";NO.INSTR%; _ ", command = ";FIRST.CHAR$ GO TO 9500 9005 REM PRINT "Error: L instruction without log file name"; _ " in CP/M command" GO TO 9500 9010 REM PRINT "Error: illegal instruction:";FIRST.CHAR$; _ ", at line #";NO.INSTR% GO TO 9500 9015 REM PRINT "Error: illegal label for line #";NO.INSTR% GO TO 9500 9020 REM PRINT "Error: duplicate label ";LABEL.VALUE%; _ " at line #";NO.INSTR% GO TO 9500 9025 REM PRINT "Error: illegal parameter for ";FIRST.CHAR$; _ " command at line #";NO.INSTR% GO TO 9500 9030 REM PRINT "Error: illegal label argument in ";FIRST.CHAR$; _ " command at line #";NO.INSTR% GO TO 9500 9035 REM PRINT "Error: undefined label in line #";I% GO TO 9500 9040 REM PRINT "Error: no instructions found." GO TO 9500 9050 REM PRINT "Error: too many characters in Send string at line #";_ INST.LIN% 9500 REM PRINT "Instruction file ";INST.FILE$ 9550 REM CLOSE END REM 9600 REM PRINT "To run DIALOG, type" PRINT " DIALOG INSTFILE.DLG LOGFILE.LOG" PRINT "where INSTFILE.DLG contains the instructions"; _ " (the input to DIALOG)," PRINT "and LOGFILE.LOG (optional) will receive the log"; _ " (the output from DIALOG)." PRINT "To check for syntax errors only, type" PRINT " DIALOG INSTFILE.DLG ? END REM 10000 REM REM THIS SUBROUTINE CONVERTS ANY CHARACTERS PRECEEDED BY THE REM CONTROL CHARACTER PREFACE TO CONTROL CHARACTERS NO.CHARACTERS% = LEN(IN.STRING$) OUT.STRING$ = "" PREFACE% = FALSE% REM FOR CHAR.NO% = 1 TO NO.CHARACTERS% CHAR% = ASC(MID$(IN.STRING$,CHAR.NO%,1)) REM BRANCH IF PREVIOUS CHARACTER WAS THE CONTROL PREFACE IF PREFACE% THEN GO TO 10050 REM CHECK EACH CHARACTER FOR THE CONTROL PREFACE IF CHAR% <> CC.PREF% THEN GO TO 10100 PREFACE% = TRUE% GO TO 10200 10050 REM REM MAKE CHARACTER INTO CORRESPONDING CONTROL CHARACTER CHAR% = CHAR% - 64 PREFACE% = FALSE% 10100 REM REM COPY THE CHARACTER INTO THE OUTPUT BUFFER OUT.STRING$ = OUT.STRING$ + CHR$(CHAR%) 10200 REM NEXT CHAR.NO% RETURN REM