home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
c
/
m4kerm.jar
< prev
next >
Wrap
Text File
|
2020-01-01
|
481KB
|
15,205 lines
This file is a text archive of the files for Tandy Model 4 Kermit.
Each file begins with a line <<< name >>>, where "name" is the name of
the file. The files begin on the next line.
<<< m4boo.bas >>>
10 INPUT "Input filename";INFILE$
20 INPUT "Output filename (/CMD file)";OUTFILE$
30 OPEN "I",1,INFILE$:OPEN "O",2,OUTFILE$
40 WHILE (EOF(1)=0)
50 INPUT #1,A$:IF INSTR(A$,"*****")<>0 THEN 150
60 FOR T=1 TO LEN(A$) STEP 2: B=VAL("&h"+MID$(A$,T,2))
70 SUM=(SUM+B) AND -4097
80 PRINT #2,CHR$(B);
90 NEXT T
100 WEND
110 PRINT "Error: Early End-Of-File Encountered!"
120 PRINT "Last record read:"
130 PRINT A$
140 CLOSE: END
150 I=INSTR(A$," ")+1:J=INSTR(I,A$," ")-I:NEWSUM=VAL(MID$(A$,I,J))
160 IF NEWSUM=SUM THEN PRINT "Checksum OK:";NEWSUM;"=";SUM: GOTO 180
170 PRINT "Bad checksum:";NEWSUM;"<>";SUM
180 CLOSE: END
<<< m4h19.equ >>>
*LIST OFF
;*********
; TRSDOS/LDOS 6.x Supervisor Call Equate File
; (c) 1983 Mark Vasoll - All rights reserved
; Licensed to Softronics Computer Systems
;*********
@ABORT EQU 015H
@ADTSK EQU 01DH
@BANK EQU 066H
@BKSP EQU 03DH
@BREAK EQU 067H
@CHNIO EQU 014H
@CKDRV EQU 021H
@CKEOF EQU 03EH
@CKTSK EQU 01CH
@CLOSE EQU 03CH
@CMNDI EQU 018H
@CMNDR EQU 019H
@CTL EQU 005H
@DATE EQU 012H
@DCINIT EQU 02AH
@DCRES EQU 02BH
@DCSTAT EQU 028H
@DEBUG EQU 01BH
@DECHEX EQU 060H
@DIRRD EQU 057H
@DIRWR EQU 058H
@DIV8 EQU 05DH
@DIV16 EQU 05EH
@DODIR EQU 022H
@DSP EQU 002H
@DSPLY EQU 00AH
@ERROR EQU 01AH
@EXIT EQU 016H
@FEXT EQU 04FH
@FLAGS EQU 065H
@FNAME EQU 050H
@FSPEC EQU 04EH
@GET EQU 003H
@GTDCB EQU 052H
@GTDCT EQU 051H
@GTMOD EQU 053H
@HDFMT EQU 034H
@HEXDEC EQU 061H
@HEX8 EQU 062H
@HEX16 EQU 063H
@HIGH$ EQU 064H
@INIT EQU 03AH
@IPL EQU 000H
@KBD EQU 008H
@KEY EQU 001H
@KEYIN EQU 009H
@KLTSK EQU 020H
@LOAD EQU 04CH
@LOC EQU 03FH
@LOF EQU 040H
@LOGER EQU 00BH
@LOGOT EQU 00CH
@MSG EQU 00DH
@MUL8 EQU 05AH
@MUL16 EQU 05BH
@OPEN EQU 03BH
@PARAM EQU 011H
@PAUSE EQU 010H
@PEOF EQU 041H
@POSN EQU 042H
@PRINT EQU 00EH
@PRT EQU 006H
@PUT EQU 004H
@RAMDIR EQU 023H
@RDHDR EQU 030H
@RDSEC EQU 031H
@RDSSC EQU 055H
@RDTRK EQU 033H
@READ EQU 043H
@REMOV EQU 039H
@RENAM EQU 038H
@REW EQU 044H
@RMTSK EQU 01EH
@RPTSK EQU 01FH
@RREAD EQU 045H
@RSLCT EQU 02FH
@RSTOR EQU 02CH
@RUN EQU 04DH
@RWRIT EQU 046H
@SEEK EQU 02EH
@SEEKSC EQU 047H
@SKIP EQU 048H
@SLCT EQU 029H
@SOUND EQU 068H
@STEPI EQU 02DH
@TIME EQU 013H
@VDCTL EQU 00FH
@VER EQU 049H
@VRSEC EQU 032H
@WEOF EQU 04AH
@WHERE EQU 007H
@WRITE EQU 04BH
@WRSEC EQU 035H
@WRSSC EQU 036H
@WRTRK EQU 037H
AFLAG$ EQU 0
CFLAG$ EQU 2
DFLAG$ EQU 3
EFLAG$ EQU 4
FEMSK$ EQU 5
IFLAG$ EQU 8
KFLAG$ EQU 10
MODOUT EQU 12
NFLAG$ EQU 13
OPREG$ EQU 14
RFLAG$ EQU 17
SFLAG$ EQU 18
TFLAG$ EQU 19
UFLAG$ EQU 20
VFLAG$ EQU 21
WRINTMASK$ EQU 22
SVCTABPTR EQU 26
VERSIONBYTE EQU 27
ICNFGVECTOR EQU 28
KITSKVECTOR EQU 31
;*********
; End of Equate File
;*********
*LIST ON
<<< m4h19.hex >>>
050648313920202001020030181D000006244845415448000000005F5F14007D00000000000000
000029002803C336363E65EF79E67F4F3264372A07377CB52808E5210000220737C979FE1BCA50
31FE20DA4E30CD5936C341363A6437874F0600216630095E2356EB7CB53A6437CA4136E9000000
0000000000000000000000A630D030D5300631000018313E310000000000000000000000000000
000000000000000000000000000000000000000000003A1230B7CA47323A11306FED5B13303E01
D390424B0B78B120FBAFD390424B0B78B120FB2D20E8C341363E18C3D831C50604F53E0FEFF1C1
3E4F95FE08D2F0303E1DCD31363E1AC331367DC608E6F86FC5D5E50603F53E0FEFF101020031E1
D1C1C341363E1ACDD8313A1C30E6023E1DC4D831C34136210000C5D5E50603F53E0FEFF1E1D1C1
C3AE33210000C5D5E50603F53E0FEFF1E1D1C1C341363E1DCDD8313A1C30E6013E1AC4D831C341
36217431220737C341364142434445464748494A4B4C4D4E4F594066717078796A6B626F6C3A64
37215931061B11A0314EB9280E23131310F7210000220737C34136EB5E2356210000220737EB3A
6437E9D6310631DE31D0301831E331E6312B31E931AE33223483357F353D3482349B3489344732
913496349B349B349132B33205335733D8323E1B326437C32E363E19C3D831C34136C34136C506
04F53E0FEFF1C17CB7C2D6313E0FCD31363E17212F01020032FF117FFF015000F5F5F3FD7E0EE6
FED384F1EDB8F5FD7E0EF601D384FBF1F13D20E2111337D5D5E1133620014F00EDB02600D1C5E5
D506090E00F53E0FEFF1D1E1C13E0EC331363E10CD31360E00C52600111337C5E5D506090E01F5
3E0FEFF1D1E1C1E5626B06507EEE80772310F9E1C5E5D506090E00F53E0FEFF1D1E1C1247CFE18
20CCFBC1790CB728C23E11C3D831ED5BF136C50604F53E0FEFF1C1EBE5010737B7ED42E1280773
23722322F136C341362AF13601F336B7E5ED42E128152B562B5E22F136EBC5D5E50603F53E0FEF
F1E1D1C1C34136C50604F53E0FEFF1C1E52E00C5D5E50603F53E0FEFF1E1D1C1CD2234E1C5D5E5
0603F53E0FEFF1E101020033D1C1C34136C50604F53E0FEFF1C1CDBB361100F8B7ED52444D78B1
28372100F81101F8F5F3FD7E0EE6FED384F13620F5FD7E0EF601D384FBF10B78B12816F5F3FD7E
0EE6FED384F1EDB0F5FD7E0EF601D384FBF1C34136C50604F53E0FEFF1C1E5CDBB36EBE12E00CD
BB36EBB7D5ED52444D78B12835E1545D13F5F3FD7E0EE6FED384F13620F5FD7E0EF601D384FBF1
0B78B12816F5F3FD7E0EE6FED384F1EDB0F5FD7E0EF601D384FBF1C34136C50604F53E0FEFF1C1
CDBB36E5E5C1217FFFB7ED42E5C1E12857E5D113C5D5E53E0FCD3136E1D1C1F5F3FD7E0EE6FED3
84F13620F5FD7E0EF601D384FBF13E1EF5F3FD7E0EE6FED384F1F578B12812F1EDA0010200343D
20F5F5FD7E0EF601D384FBF118DDF1F5FD7E0EF601D384FBF13E0EC33136C34136C50604F53E0F
EFF1C1E5CDBB36E32E4FCDBB36C1C579BD28E41883111337D5C50604F53E0FEFF1C1E5C5E5D506
090E01F53E0FEFF1D1E1C13E4F95260019E5D1B728064F060023EDB03E2012E1D1C5E5D506090E
00F53E0FEFF1D1E1C1C34136AF320937C341363E01320937C341363E11C3D8313E10C3D83121CE
342207373A6437320B37C34136FD34FD34FD3428353F35FD34FD3400350A35FD34FD34FD343A35
3535FD34FD3414351E353A0B37FE782808FE79206B0E1218020E003A6437D631FE09D24136FE00
DA4136CB27814F060021AA34095E2356D5C9C34136010200353A1C30F601321C3018F33A1C30F6
02321C3018E93A1C30E6FE321C3018DF3A1C30E6FD321C3018D52A0C377CB5CA4136114136D5E9
3E0FC3D8312A0E3718EC3E0EC3D8313A6437D620DA4136FE18D24136321237215D35220737C341
363A6437D620DA4136FE50D241366F3A123767C5D5E50603F53E0FEFF1E1D1C1C341363E011801
AF320A37C50604F53E0FEFF1C13E1794286BFDE5E5C5D5F53E0FCD3136F1D1C1E1FDE13A0A37B7
282DE52E00CDBB36F1E5D101500009F5F3FD7E0EE6FED384F1C5EDB0C1F5FD7E0EF601D384FBF1
3CFE1720E36718303E1794212FFF117FFF015000F5F3FD7E0EE6FED384F1C5EDB8C1F5FD7E0EF6
01D384FBF13D20E501F50036C50604F53E0FEFF1C1E5111337D5D5E113014F003620EDB0D1E1C5
E5D506090E00F53E0FEFF1D1E1C13E0EC331363A64374F0602B7BFDDE5DD2A0B303E14EFDDE13A
6437BFC9210000C5D5E50603F53E0FEFF1E1D1C1C3AE33F5C50604F53E0FEFF1C1E53A0937B728
38111337C5E5D506090E01F53E0FEFF1D1E1C13E4F954F0600B7281D2E4F260019D55D542BEDB8
D1E1C5E5D506090E00F53E0FEFF1D1E1C1E5E1F1C32E3606083A0F304F3E0FEFC906083A10304F
3E0FEFC9C5F5D5E5D12100F801500015FACD360918F9160019D1F1C1C9C5F5D50100F8B7ED4216
00015000B7ED42DAEB361418F70962D1F1C1C9F336010E07370000000000A736B136000000016D
64370048313920456D756C61746F722D66696C74657220666F7220545253444F5320362E322E20
5772697474656E2062793A2020477265676720576F6E6465726C791D1A4C6F6164206164647265
73733A2003202020202020202020456E64696E6720616464726573733A200301021F380000ED53
0B303E65EFFD2210372165373E0AEF21000006003E64EF221530220230E521FEF3C1B7E5ED42E1
3802C5E123016507B7ED42E52B22173006003E64EFD1ED531F3821CF37E53E63EF3603E13E0AEF
2A1F38010030B7E5ED42221A30E101650709E521B5373E0AEFD121CF37E53E63EF360DE13E0AEF
DD21EB38ED4B1A30DD6E00DD23DD6600DD23DDE5E5DDE1DD6E00DD660109DD7500DD7401C1C5DD
E121693AB7ED4220D4016507ED5B1F38210030EDB0DD2A0B30ED5B1F38DD360047DD7301DD7202
210000BFC9CC3122302C302F303A304130463049304C304F305630603063307430763078307A30
7E308030A730AB30AE30B330CE30D330E43001021F39CE31E930EE300431093129313C31413151
3154315731753178317D318C318F3199319D31A031A231A431A631A831AA31AC31AE31B031B231
B431B631B831BA31BC31BE31C031C231C431C631C831CA31D931DC31E131E431E731F531233245
3252328F32B8331D343E348034843487348C348F34943499349C349F34A234A534A834CF342935
2E3531353B3545354A354F355235553558355B355E35633568356C357D358535A735B0350B362C
362F363A3665366B36A536AA36B436C836E6360C370E3742365736FA314A329E35E0340C319332
A132AE32B132B432B732C532D632F136D031D231D431F23203330F33553362336933AC33383542
35AA34AC34014C1F3AAE34B034B234B434B634B834BA34BC34BE34C034C234C434C634C834CA34
CC34EC34F534FE3444314B314E3113311631013506350B35103515351A351F352435E7342D3433
34D13320340202213800000000000000000000000000000000
***** 768 *****
<<< m4h19.mac >>>
; m4h19/mac
*LIST OFF
SWAP_IN MACRO
PUSH AF
DI
LD A,(IY+SCR_MASK)
AND S_IN
OUT (132),A
POP AF
ENDM
;
SWAP_OUT MACRO
PUSH AF
LD A,(IY+SCR_MASK)
OR S_OUT
OUT (132),A
EI
POP AF
ENDM
;
SVC MACRO #P1
PUSH AF
LD A,#P1
RST 28H
POP AF
ENDM
;
SSVC MACRO #P1
LD A,#P1
RST 28H
ENDM
;
GET_CURSOR MACRO
PUSH BC
LD B,4
SVC @VDCTL
POP BC
ENDM
;
PUT_CURSOR MACRO
PUSH BC
PUSH DE
PUSH HL
LD B,3
SVC @VDCTL
POP HL
POP DE
POP BC
ENDM
;
GET_LINE MACRO
PUSH BC
PUSH HL
PUSH DE
LD B,9
LD C,1
SVC @VDCTL
POP DE
POP HL
POP BC
ENDM
;
PUT_LINE MACRO
PUSH BC
PUSH HL
PUSH DE
LD B,9
LD C,0
SVC @VDCTL
POP DE
POP HL
POP BC
ENDM
;
*LIST ON
<<< m4h19s.hex >>>
05065345544831390102002511B32901FF00ED53AF29EDB01100273E53EFC2E726E5DDE111C92A
2AAF297EFE0DCA3B26FE2828032318F32B3E11EFC23B263AD02AB72811E660C2D5262A58297CB7
C2CD267DDD770F3ADA2AB72811E660C2D5262A56297CB7C2CD267DDD77103AE42AB72849E6A0C2
D52606002100003E64EFC2DF26DD7E174FDD7E1847B7ED42C2C426DD7E156FDD7E166706003E64
EFC2DF262168293E19EF2172293E19EF217C293E19EF2187293E19EFC337263AF12AB7280EE660
C2D5262A5E29DD7513DD74143AFD2AB72811E660C2D5262A5C297CB7C2CD267DDD77113A052BB7
CAEC25E6A0C2D5263A6029DD77123A1F2BB7CA0D26E6A0C2D526DD4E1DDD461EDDE501020026E1
090EFF3A6629B728020E7F713A0D2BB7280CE6A0C2D5263A6229B7C43B263A152BB72812E6A0C2
D5263A6429B7CA372621C2273E0AEF210000C92178273E0AEFDD6E102600CDAD262188273E0AEF
DD6E0F2600CDAD260E0D3E02EF21B4273E0AEF21BB27DD7E12B7200321BE273E0AEF2199273E0A
EFDD6E112600CDAD2621A6273E0AEFDD6E13DD6614CDAD262124273E0AEFDD4E1DDD461EDDE5E1
097E213527FEFF20032139273E0AEFC911B52AD53E61EFEB3603E13E20BE20032318FA3E0AEFC9
2107273E0AEFC39425216827DD213C27DD2154273E0AEF21FFFFC9F6C04F3E1AEF18F43AB129B7
20E43C32B1292195293E19EF21A1293E19EFC30C25010200272448454154480043616E206E6F74
207265636C61696D2075736564206D656D6F7279210D0A537472697020387468206269743A2003
5945530D4E4F0D43616E206E6F742066696E64204831392066696C7465720D4261642070617261
6D657465722076616C75650D56616C756520746F6F206C617267650D4E6F726D616C2063757273
6F723A20032C20426C6F636B20637572736F723A20032C204475726174696F6E3A20032C204672
657175656E63793A200342656C6C3A20034F4E034F4646035265636F676E697A65642070617261
6D65746572733A0A435552534F522020202020202D2020204E6F726D616C20637572736F722063
6861726163746572010200280A424C4F434B202020202020202D202020426C6F636B2063757273
6F72206368617261637465720A42454C4C20202020202020202D2020205475726E2062656C6C20
4F4E206F72204F46460A4652455155454E43592020202D2020204672657175656E6379206F6620
62656C6C2028696E7665727365206F66207265616C2066726571290A4455524154494F4E202020
202D2020204C656E677468206F6620746F6E652028323535204D4158290A535452495038202020
2020202D20202052656D6F766520387468206269742066726F6D20636861726163746572732028
64656661756C743D4F4E290A52454D4F56452020202020202D20202052656D6F766501B8002920
7468652066696C7465722066726F6D206D656D6F72790A53484F5720202020202020202D202020
53686F7720616C6C2076616C7565730A48454C5020202020202020202D20202054686973206D65
73736167650A0D0000000000000000000000000000000000007265736574202A736F0D72657365
74202A68700D72656D6F7665202A68700D726F757465202A736F202A646F0D736574202A687020
6831390D66696C746572202A736F202A687000000020202020015CC92A8085424C4F434B005829
86435552534F520056294652454D4F5645005A29994652455155454E4359005E29984455524154
494F4E005C294442454C4C0060294453484F570062294448454C50006429465354524950380066
290002020025000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000
***** 3468 *****
<<< m4ker.src >>>
<<< m4add.asm >>>
; m4add/asm
;
; Input a line from a take file
;
DOTAKE EQU $
LD HL,CMDBUF ;WHERE TO PUT THE TEXT
LD B,0 ;CHARACTER COUNTER
CALL CONIN
IFA 128,TAKERR ;Jump if break was pressed
TAKLOP LD DE,TFCB ;FCB FOR TAKE FILE
CALL XGET ;Call @GET svc
JR NZ,TAKERR ;QUIT ON AN ERROR
LD (HL),A ;SAVE THE CHARACTER
INC HL ;POINT TO THE NEXT
INC B ;ADD TO CHARACTER COUNT
IFA CR,TAK020 ;Go if at the end of string
LD C,A
LD A,(TAKLOG) ;IS DISPLAY OF TAKE FILES ON?
OR A
LD A,C
CALL NZ,CONOUT
JR TAKLOP
TAK020 RET ;RETURN WITH THE STRING
TAKERR LD DE,TFCB ;GET READY TO CLOSE THE FILE
CALL XCLOSE ;Close the file
XOR A ;TURN THE TAKE FLAG OFF
LD (TAKFLG),A ;RESET IT
LD A,29
CALL CONOUT
SCF ;SET CARRY FOR A PARSE ERROR
RET
;
; This routine is used by the command parser routines to input a
; string from the keyboard. It recognizes the TAKFLG which tells
; it to input a string from the active take file.
; Input to the routine is HL which points to the string buffer,
; and B which has an initial count of the number of characters
; already in the buffer.
;
GETSTR LD A,(TAKFLG) ;Is there a TAKE file active
OR A
JP NZ,DOTAKE ;If so than go fill buffer from file.
LD IY,(FLAGS) ;Get the flags address.
BIT 5,(IY+18) ;Check if JCL active.
JR Z,SKIP_JCL ;Jump if JCL not active.
LD HL,CMDBUF ;Get the input buffer.
LD BC,5000H ;Set B to max count, and C to zero.
JP XKEYIN ;Get a line from JCL and return.
;
SKIP_JCL PUSH HL ;Save the registers
PUSH DE
LD A,B ;Save the number of character already in
LD (TEMP4),A ;the buffer for later
GET010 CALL XKEY ;Get a character from the keyboard
JP NZ,GETEXT ;Humm, what do we do on an error
IFANOT 8,GET030 ;Go if not backspace
LD E,A ;Save the KEY we got
LD A,B ;Get the number of characters
IFZ GET010 ;Go if no place to backspace over
DEC B ;At least one space left
DEC HL ;Back up the buffer pointer
LD A,E ;Get the character
CALL CONOUT ;Display it
JR GET010 ;Go get a new key
GET030 IFA CR,GET040 ;Go if enter pressed
IFANOT 24,GET036 ;Jump if not SHIFT <-
GET035 LD A,B ;NUMBER LEFT
IFZ GET010 ;Go if all were erased
LD A,8 ;BACKSPACE
CALL CONOUT ;PRINT IT
DEC B ;ONE MORE LEFT
DEC HL ;BACKUP IN THE BUFFER
JR GET035 ;KEEP LOOPING
GET036 IFA ESC,GET040 ;Go if it was escape
IFANOT 129,GET038 ;Go if not F1 (Also escape)
LD A,ESC ;GET AN ESCAPE
JR GET040 ;JOIN THE CODE FOR EXIT
GET038 IFA 128,GET040 ;Go it it was a break
IFALT 20H,GET010 ;Ignore other control keys
GET040 INC B ;ONE LESS CHARACTER LEFT
LD (HL),A ;PUT THE CHARACTER IN THE BUFFER
JR NZ,GET050 ;WHEN nZ IS SET, NO MORE CHARS LEFT
DEC B ;SAY WE STILL HAVE ONE
JR GET060 ;MIGHT BE '?' WHICH IS IGNORED AS LAST
GET050 IFA CR,GETEXT ;Finish up if CR pressed
IFA ESC,GETEXT ;Same for escape
IFA 128,GETEXT ;Same for break
INC HL ;ONE MORE IN THE BUFFER
CALL CONOUT ;PRINT WHAT WAS TYPED
GET060 CP '?' ;WAS IT A '?' ?
JP NZ,GET010 ;GET A NEW KEY IF NOT
LD A,8 ;GET A BACKSPACE
CALL CONOUT ;PRINT IT TO REMOVE THE '?'
DEC HL ;POINT AT THE '?'
PUSH HL ;HL -> IY
POP IY
LD A,' ' ;LOOK FOR A PREVIOUS SPACE
IFA (IY-1),GETEXT ;Look for a previous space
LD A,B ;ARE WE AT THE START OF THE LINE
DEC A
;IF Z IS SET THAN THE CURSOR IS AT HOME ON THE LINE. NO SPACE WILL
;BE ADDED IN THIS CASE.
LD A,' ' ;PUT A SPACE ON THE DISPLAY
CALL NZ,CONOUT ;PRINT IT
GETEXT LD A,B ;GET NUMBER ON THE LINE
DEC A
JR NZ,GET110 ;AT LEAST ONE CHAR ON THE LINE
PUSH AF ;PUT AF INTO BC
POP BC
LD A,(HL) ;WAS '?' THE TERMINATOR?
CP '?'
LD A,B ;GET THE LENGTH IN A
JR NZ,GET120
GET110 INC A ;COUNT THE TERMINATOR IF IT IS '?'
GET120 LD B,A ;SAVE THE LENGTH
LD A,(HL) ;GET THE TERMINATOR
IFA ESC,GET130 ;Skip normal return if escape
SLA A ;CHECK FOR BREAK (128 IS NEGATIVE)
JR C,GET130 ;ALSO GIVES C STATUS LIKE @KEYIN
SRL A ;FIX IT BACK
OR 10H ;MAKE CR, CHR$(29), '?' IS UNDISTURBED
CALL CONOUT ;PRINT THE CHARACTER
GET130 POP DE ;RESTORE THE REGS
POP HL
RET ;RETURN TO THE CALLER
;
STDOUT LD A,16 ;REVERSE VIDEO ON
JP CONOUT ;USE THE RETURN ON THE STACK
STDEND LD A,17 ;REVERSE VIDEO OFF
JP CONOUT ;USE THE RETURN ON THE STACK
;
;ENTRY POINT FOR INTERUPT DRIVEN RECEIVE CHARACTER ROUTINE.
;
GETINT JR NZ,GTIN10 ;NO CHARACTER AVAILABLE
LD HL,(CURCHR) ;CURRENT POS IN BUFFER
LD (HL),C ;CHARACTER IS IN C, STORE IT
INC L ;POINT TO NEXT WRITE POSITION
LD A,(NXTCHR) ;CHECK FOR OVERFLOW
IFA L,GTIN10
LD (CURCHR),HL ;SAVE ADDRESS OF NEXT STORE
LD A,(MAXCNT)
LD E,A
LD HL,INCNT ;Get the address of the count
INC (HL) ;Add one to the count
LD A,(HL) ;Get the count
IFALT E,GTIN10 ;Jump if below count
LD A,(FLOFLG) ;ARE WE DOING FLOW CONTROL?
IFZ GTIN10 ;Go if not doing flow control
LD A,C ;GET THE CHARACTER JUST RECEIVED
IFA XOFF,GTIN06 ;Jump if XOFF received
IFANOT XON,GTIN07 ;Jump if not time for XON
XOR A
GTIN06 LD (XOFREC),A ;Store the new flag value
GTIN07 LD A,(XFFLG) ;SEE IF WE ALREADY SENT IT
IFNZ GTIN10 ;Go if XOFF already sent
INC A ;MAKE IT NON-ZERO
LD (XFFLG),A ;SET IT
LD E,XOFF ;Get an XOFF character
CALL OUTCHR ;SENT IT OUT
GTIN10 RET
;
;LOG THE CHARACTER IN THE LOG FILE
;
LOGIT PUSH AF ;Save the character to log
LD A,(LOGFLG) ;Check if logging active
IFANOT 2,LOGITO ;Go if logging not on, or file not open
POP AF ;Get the character back
PUSH AF ;Put the character back
IFANOT LF,LOGT0 ;Is it LINE FEED? Jump if not
LD A,(PREVLCHR) ;Check if previous character was <CR>
IFA CR,LOGITO ;Throw out <LF> if previous was <CR>
LD A,LF ;Get a line feed character back
LOGT0 PUSH DE ;Save the registers
LD (PREVLCHR),A ;Save the previous character
LD DE,LFCB ;Get the FCB address
LOGT1 CALL XPUT ;@PUT the character to the file
JR Z,LOGEXT ;Exit if no errors on output
LOGT2 CALL XERROR0 ;Print the system message given in A
LD DE,LFCB ;Get the FCB back
CALL XCLOSE ;Make sure that the file is closed
STROUT ERMS20 ;Say that the file was closed
XOR A ;Reset the logging flag
LD (LOGFLG),A ;Store the new value
LOGEXT POP DE ;Restore DE
LOGITO POP AF ;Restore the character
RET ;Back to caller
;
; These are the TRSDOS 6.x SVC definitions
;
XPARAM DOSVC 17 ;@PARAM SVC (Parse ()'d argument list).
XFSPEC DOSVC 78 ;@FSPEC SVC (Convert filename to TRSDOS)
XINIT DOSVC 58 ;@INIT SVC (Create a file on disk device)
XOPEN DOSVC 59 ;@OPEN SVC (Open a file)
XREAD DOSVC 67 ;@READ SVC (Read a record)
XSKIP DOSVC 72 ;@SKIP SVC (Skip a logical record)
XCLOSE DOSVC 60 ;@CLOSE SVC (Close a file)
XVER DOSVC 73 ;@VER SVC (Write with verification)
XCTL DOSVC 5 ;@CTL SVC, perform control operation
XPRT PUSH BC ;Send character to printer
PUSH AF
LD C,A
LD A,6
JR SVCSAV
XVDCTL DOSVC 15 ;@VDCTL SVC (Perform video operations)
XGET DOSVC 3 ;@GET SVC (Get a character from a file)
;
; SVC'S that require the character passed in A to be in C should
; look like this.
;
XPUT PUSH BC ;SAVE BC
PUSH AF ;SAVE AF
LD C,A
LD A,4 ;@PUT SVC
SVCSAV RST 28H ;CALL AN SVC
POP BC ;POPPING BC DOES NOT AFFECT THE FLAGS
LD (XERRNO),A ;Store last error number
LD A,B ;B HAS OLD A SO RESTORE
POP BC ;GET OLD BC
RET ;RETURN TO THE CALLER
XKEYIN DOSVC 9 ;Get a string from *DO (@KEYIN SVC)
XHIGH DOSVC 100 ;@HIGH$ SVC
XLOAD DOSVC 76 ;@LOAD SVC (Load an executable)
XCHKDRV DOSVC 33 ;@CHKDRV SVC (Check if drive is ready)
XTIME DOSVC 19 ;@TIME SVC (Get current system time)
XADTSK DOSVC 29 ;@ADTSK SVC (Add a task to the table)
XCKTSK DOSVC 28 ;@CKTSK SVC (Check if task slot available)
XRMTSK DOSVC 30 ;@RMTSK SVC (Remove task from table)
XKLTSK DOSVC 32 ;@KLTSK SVC (Kill current exec task)
XPAUSE DOSVC 16 ;@PAUSE SVC (Delay for count in BC)
XFLAGS DOSVC 101 ;@FLAGS SVC (Get system flags address)
XREMOVE DOSVC 57 ;@REMOV SVC (Remove opened file)
XKILL EQU XREMOVE
XDECHEX DOSVC 96 ;@DECHEX SVC (Convert ASCII to binary)
XHEXDEC DOSVC 97 ;@HEXDEC SVC (Convert binary to ASCII)
XKBD DOSVC 8 ;@KBD SVC (Get a keyboard char, no wait)
XKEY DOSVC 1 ;@KEY SVC (Get a keyboard char, wait)
XCMNDR DOSVC 25 ;@CMNDR SVC (Execute system command)
XMUL16 DOSVC 91 ;@MUL16 SVC (Multiply 8 bit by 16 bi&t)
XDSP PUSH BC ;SAVE BC
PUSH AF ;SAVE AF
LD C,A
LD A,2 ;@DSP SVC
JP SVCSAV
XGTDCB DOSVC 82 ;@GTDCB SVC (Get the DCB for given device)
XEXIT LD L,A ;A HAS OUR RETURN CODE
LD H,0 ;MAKE HL THE RETURN CODE
DOSVC 22 ;Do @EXIT SVC
XERROR0 LD A,0 ;Get the last error number
XERRNO EQU $-1
XERROR PUSH BC ;SAVE BC AND AF
PUSH AF
LD IY,(FLAGS) ;GET @FLAGS ADDRESS
RES 6,(IY+2) ;RESET ALL SPECIAL BITS
RES 7,(IY+2)
RES 6,(IY+18)
OR 0C0H ;MAKE SIMPLE MESSAGES
LD C,A ;C NEEDS THE ERROR NUMBER
CALL NEWLIN ;Get a new line for the messages
LD A,26 ;@ERROR SVC (ISSUE A SYSTEM MESSAGE)
JP SVCSAV ;GO CALL IT
;
; Set up interrupt and device information
;
SETINT EQU $
;
; This code sets up the interrupt driven receiver. It calls @CTL
; to pass the address of the "GETINT" routine, which is called
; each time a character is received by the UART
;
LD IY,GETINT ;Where to transfer control to
LD DE,(CLDCB) ;Which device to get
LD C,4 ;Ctl function 4
CALL XCTL ;Do @CTL
;
; Install *FO and *FI devices
;
LD DE,0 ;Find a new DCB for this device
CALL XGTDCB
JR NZ,NODCB ;Abort if an error occured
LD (FOTDCB),HL ;Save the pointer to the DCB
PUSH HL ;Move it to IX to do indexing
POP IX
LD (IX+6),'F' ;Store the name in the DCB
LD (IX+7),'O'
LD A,2 ;Select @PUT capabilities only
LD (IX),A
LD HL,FILOUT ;Get the entry point
LD (IX+1),L ;Store it
LD (IX+2),H
LD DE,0 ;Get a new DCB for the input device
CALL XGTDCB
JR NZ,NODCB ;Abort if an error occurs
LD (FINDCB),HL ;Save the address of the DCB
PUSH HL ;Put the address in IX for indexing
POP IX
LD (IX+6),'F' ;Store the device name in the DCB
LD (IX+7),'I'
LD A,1 ;Select @GET capabilites only
LD (IX),A
LD HL,FILIN ;Get the entry point
LD (IX+1),L ;Store the address
LD (IX+2),H
RET ;Done!
;
; Print no DCB's available message
;
NODCB STROUT NONDCB ;Print NO NEW DCB's message
JP EXIT1 ;Exit from KERMIT
;
; Get a new line to print on
;
NEWLIN PUSH AF ;Save the acumulator
LD A,CR ;Get a <CR><LF> equivilent
CALL CONOUT ;Output it to the screen
POP AF ;Restore A
RET ;Return to caller
;
; Set the default disk drive command
;
SETDSK EQU $
LD A,CMNUM ;PARSE A NUMBER
CALL COMND
JP KERMT3
OR A ;If no number than say bad command
JP Z,KERMT2
LD A,D ;Check for number above 255
IFNZ SETDRV_2 ;Jump if number bigger than 255
LD C,E ;Get the lower order byte
CALL XCHKDRV ;Check the disk drive
JR NZ,SETDRV_2 ;Jump if TRSDOS doesn't like it
PUSH BC ;Save the binary number
JR NC,SETDRV_1 ;If carry set the drive is write protected
STROUT WRTPROT ;Say drive is write protected
SETDRV_1 STROUT DSKOK ;Say default drive changed
POP BC ;Get the drive number back
LD A,C ;Get the binary value into a
ADD A,48 ;Make it and ASCII digit
LD (DEFDSK),A ;Save it as the new default
JP KERMIT ;Get a new command
;
; Print bad drive message
;
SETDRV_2 LD A,32 ;Get the illegal drive message number
CALL XERROR ;Have TRSDOS print the message
JP KERMIT ;Go get a new command
;
; Clear any buffered characters from input buffer
;
CLRPRT PUSH AF
LD A,(NXTCHR) ;Set the next, and current positions
LD (CURCHR),A ;within the buffer to be the same
XOR A ;Set buffered character count to zero
LD (INCNT),A
LD (XOFREC),A ;Reset XOFF'd state
LD (XFFLG),A ;Haven't sent XOFF either
POP AF
RET
;
; Display the directory
;
;This code makes an educated guess as to whether it is running on a
;6.1 or a 6.2 TRSDOS machine. This is to determine if we should
;issue the DIR command for 6.1 or the CAT command for 6.2
;
DIR EQU $
LD A,CMTXT ;Get text for DIR/CAT command
LD DE,DIRBUF
CALL COMND
JP KERMT3
IFNZ DIR1C ;Jump if some text given
DIR1B LD A,(DEFDSK) ;Otherwise, use default drive
LD (DIRBUF),A ;Put in the text
LD A,CR ;Put in the terminator
LD (DIRBUF+1),A
DIR1C CALL NEWLIN ;Get new lines
CALL NEWLIN
LD IY,(FLAGS) ;Check if using 6.1, or 6.2 TRSDOS
LD A,(IY+27) ;Get the version number
AND 0FH ;KEEP JUST THE X OF 6.X
LD HL,DO62DR ;Get 6.2 command (CAT)
IFA 2,DIR1E ;Jump if 6.2
LD HL,DO61DR ;Get 6.1 command (DIR)
DIR1E LD DE,DIRCMD ;Where to put the text
LD BC,4 ;How much to move
PUSH DE ;Save the start
LDIR ;Move the command
POP HL ;Restore the start
CALL XCMNDR ;Let TRSDOS do it for us
DIR1D JP KERMIT ;Get a new command
;
; Erase a file from the system
;
ERA EQU $
LD A,CMTXT ;Get some text
LD DE,MFNBUF
PUSH DE ;Save the buffer address
CALL COMND
JP KERMT3
IFZ ERA3 ;Jump if no text given
CALL NEWLIN ;Get a newline
POP HL ;Get the address back
LD (MFNPTR),HL
XOR A
LD (LOGNAMES),A ;Reset the log names flag
CALL BUILDF ;Do wild carding
LD A,(FILECNT) ;Check if anything found
IFZ ERA3
LD (MFNPTR),HL ;Save the start of the list
ERA2 CALL MFNAME ;Get one filename from the buffer
JR C,ERA3 ;Jump if no more
LD DE,MFREQ ;Get the name
LD B,0 ;Select 256 LRL
LD HL,DATA ;Get the address of a temp buffer
CALL XOPEN ;Try to open it
JR Z,ERA1 ;Jump if opened
CP 42 ;Was it an LRL error message?
JR Z,ERA1 ;Jump if it was
ERA0 CALL XERROR0 ;Issue the message indicated in A
JR ERA3 ;Get a new command
;
; Print the removing message, then remove it
;
ERA1 LD HL,FCB ;Convert ETX to EOS in FCB
LD BC,32 ;Max distance
LD A,3 ;What to find
CPIR ;Look
DEC HL ;Ignore errors
LD (HL),EOS ;Change it
STROUT REMOVSTR ;Output 'Removing: ' message
STROUT FCB ;Output the filename
CALL NEWLIN ;Get a newline
LD DE,MFREQ ;Get the FCB
CALL XKILL ;Remove the file
JR Z,ERA2 ;Abort if error occurs
JR ERA0 ;Get the next one
;
ERA3 JP KERMIT ;Get a new command
;
; This routine sets up KERMIT/INI as initialization. The trick
; is to just make it look like the user typed 'TAKE KERMIT/INI'.
;
CHKTAK CALL XFLAGS ;Get the flags area into IY
LD A,(IY+10) ;Get the KFLAG$
AND 0F8H ;Reset the <ENTER>, <BREAK> and
LD (IY+10),A ;the <PAUSE> bits, and store it
LD B,46 ;Pause for a good deal of time
CALL XPAUSE
LD A,(IY+10) ;Get the KFLAG$ mask back
AND 7 ;Any of the keys pressed?
RET NZ ;Stop if BREAK, ENTER, or PAUSE
LD DE,TFCB ;LOAD THE FCB ADDRESS
LD HL,TKNAME ;NAME OF THE FILE
LD BC,TKLEN ;LENGTH OF THE STRING
LDIR
LD DE,TFCB ;GET IT AGAIN
LD HL,TBUF ;GET THE INPUT BUFFER
LD B,0 ;256 BYTE LRL
CALL XOPEN ;OPEN THE FILE
JR Z,CHKT_1 ;Jump if everything OK
CP 42
RET NZ ;Return if NOT LRL error
CHKT_1 LD A,1 ;SET THE TAKE COMMAND ACTIVE FLAG
LD (TAKFLG),A
RET ;GO DO IT.
;
; Print ESCAPE character sequence as CONTROL-?
;
ESCPR LD A,(ESCCHR) ;GET THE ESCAPE CHAR.
ESCPR1 IFAGE ' ',ESCPR2 ;IS IT A CONTROL CHAR?
PUSH AF
STROUT INMS10 ;Output CONTROL-
POP AF ;GET THE CHAR BACK
OR 100O ;DE-CONTROLIFY.
ESCPR2 CALL CONOUT
RET
;
; Swap screens between connect mode, and KERMIT command modes
;
SWAPIN LD A,15 ;cursor off
CALL CONOUT ;Tell *DO to turn it off
LD HL,2600H ;Get the destination
LD B,6
CALL XVDCTL ;Move screen image to temp space
LD HL,SWTBUF ;Move the buffer to the screen
LD B,5
CALL XVDCTL ;Move it
LD HL,2600H ;Now move temp buffer to swap buffer
LD DE,SWTBUF
LD BC,1920
LDIR ;Move it
LD A,14 ;cursor back on
CALL CONOUT
RET ;Return to the caller
;
; Put connect command screen in view
;
SCRCON EQU $
CALL SWAPIN ;Swap screens
LD B,4 ;Select get cursor position option
CALL XVDCTL ;SVC @VDCTL to get position
LD (CMDCRS),HL ;Save the cursor
LD HL,(CONCRS) ;Get the connect cursor postion
LD B,3 ;Select SET cursor position
CALL XVDCTL ;SVC @VDCTL to set it
LD A,14 ;Make sure that the cursor is ON
CALL CONOUT
RET ;Return to caller
;
; Swap in Kermit command screen
;
SCRCMD EQU $
CALL SWAPIN ;Swap screens
LD B,4 ;Get the current cursor position
CALL XVDCTL ;SVC @VDCTL to get it
LD (CONCRS),HL ;Save it
LD HL,(CMDCRS) ;Get the Kermit command cursor position
LD B,3 ;Set the current cursor position
CALL XVDCTL ;SVC @VDCTL to set it
LD A,14 ;Make sure the cursor is on
CALL CONOUT
RET ;Return
;
; *FI Device driver is here
;
; Valid memory module headers are used here, but are not necessary
; since the drivers are not in the High or Low memory chain of
; modules.
;
FILIN JR INPFIL ;Jump to code
DW ENDIN ;End of module
DB 4 ;Module name length
DB 'INP$'
FINDCB DW 0 ;Pointer to our DCB
DW 0
PRECHR DB 0 ;Previous character received
INPFIL CALL INPORT ;Get an input character
JR Z,INP04 ;Jump if successful
CALL CONIN ;Failed, read the keyboard
IFZ INPFIL ;Jump if no key pressed
IFANOT 128,INP03 ;Jump if not break
LD A,28 ;Return at EOF indicator
OR A ;Set NZ status
RET ;return to caller
INP03 LD E,A ;Get the keyboard character
CALL OUTCHR ;Output it to the port
JR INPFIL ;Read the port again
INP04 LD C,A ;Get the input character
LD A,(FLOFLG) ;Are we doing flow control?
IFNZ INP05 ;Jump if not doing flow control
LD A,C ;Get the character back
IFA XON,INPFIL ;Ignore XON if sent
IFA XOFF,INPFIL ;Ignore that also
INP05 LD A,(PRECHR) ;Get the previous character
CP CR ;Was it CR?
LD A,C ;Get the current character
JR NZ,INP09 ;Jump if not CR
LD A,(FILTYPE) ;Check if should convert
OR A ;Is it binary mode?
LD A,C
JR NZ,INP09 ;It is, so do not translate
CP LF ;Is the current character LF?
LD (PRECHR),A ;Store new previous
JR Z,INPFIL ;Ignore LF after CR
INP09 CP A ;Set Z status
RET ;Return byte to caller in A
ENDIN EQU $
;
; *FO Device driver is here
;
FILOUT JR FIOUT ;Jump to code
DW OUTEND-1 ;Normal header
DB 4
DB 'OUT$'
FOTDCB DW 0
DW 0
FIOUT LD E,C ;Get the character to send
FIOUT1 CALL OUTCHR ;Output it. We will hang till output
LD A,C ;Get the character sent
CP A ;Set the Z flag
RET ;Return the byte sent out, and Z status
OUTEND EQU $
; end of file
<<< m4chgs.asm >>>
; m4chgs/asm
Version 5.2
9/21/86 Change <ESC-CHAR> ? to not destroy the screen while in connect
mode. Save screen, and then restore it after the user presses
a key.
9/20/86 Fix bug in SET KEY that caused garbage to be returned
when a new key was defined after ANY key definition
was used.
7/20/86 Moved SET FILE-WARNING to SET FILE WARNING.
7/1/86 Add wild carding to KILL command.
6/15/86 Add transaction and DEBUG logging.
6/14/86 Fixed dumb terminal emulation, and moved DUMB terminal
translations to TRMOUT() so that LOCAL ECHO would also
work correctly.
6/6/86 Changed FILE-TYPE, and FILE-DISPOSITION to be options
under a new SET value called FILE. Now the corresponding
commands are SET FILE TYPE, and SET FILE DISPOSITION.
6/6/86 SHOW was changed also to reflect the changes in SET.
6/3/86 Add (SYSTEM,INVIS) parameters to send command to allow
these types of files to be ignored. Neither type is
allowed by default. The first letter is enough to
qualify the full name.
5/30/86 Fixed problem with ^C and ^E exits from the protocol.
Changed CALL XKLTSK to JP XKLTSK. TRSDOS evidently
did not like the extra word on the stack.
5/30/86 Fix error is LOGOUT, BYE, and FINISH retry handling
that caused weird behavior when MAXTRY retries were
reached.
5/29/86 Logging now translates CR/LF pairs to just CR
5/28/86 Added wild carding to SEND command
Version 5.1 (Never released)
5/24/86 Restructure output of SHOW ALL to include everything
5/2/86 Make it possible to use break to abort a PAUSE
5/2/86 Fixed problem with PAUSE, backwards test changed.
This error made PAUSE work for one second, no matter
what the parameter was.
Version 5.0
A large number of changes were made between version
5 and version 4. Added REMOTE commands, restructured
the code quite a bit to clean up some things. There
were too many changes to document all of them here.
; end of file
<<< m4cmd.asm >>>
; M4CMD/ASM
;
; Jumping to this location will cause the return address on the
; stack to be incremented by 3, and then jumped to. This is used
; in several places to make error handling easier. Code using
; this mechanism might look like.
;
; ROUTINE: EQU $
; ...
; CALL SPACK
; JP ABORT ;Die on an error
; ... ;Continue normally
;
; RET
; SPACK: EQU $
; ...
; LD A,B ;Check result
; CP C ;Must be equal
; RET NZ ;Error if not equal
; LD A,(LEN) ;Get the length for return
; JP RSKP ;Normal return
;
RSKP POP HL ;GET THE RETURN ADDRESS.
INC HL ;INCREMENT BY THREE.
INC HL
INC HL
JP (HL) ;Return to return+3 bytes
;
; Output the value in HL as an ASCII decimal string
;
NOUT EQU $
PUSH HL ;Save the registers
PUSH BC
PUSH DE
LD DE,NBUFF ;Get the string buffer
PUSH DE ;Save the address
CALL XHEXDEC ;Convert from binary to ASCII
EX DE,HL ;HL = end of buffer + 1
LD (HL),EOS ;Add EOS for printing
POP HL ;Restore the starting address
LD A,' ' ;Remove leading spaces
NOUT1 IFANOT (HL),NOUT2 ;Go if not blank
INC HL ;Point to next character
JR NOUT1 ;Back to top of loop
NOUT2 EX DE,HL ;DE is now start of string to print
CALL PRTSTR ;Print the number
POP DE ;Restore the registers
POP BC
POP HL
RET
;
;
; Command parsing routines
;
; This routine prints the prompt pointed to by DE, and then
; sets up the appropriate values to allow a reparse at any point
;
PROMPT POP HL ;Get the return address
PUSH HL ;Put it back
LD (CMRPRS),HL ;Save it as the reparse address
LD (CMOSTP),SP ;Save the stack pointer as well
LD (CMPRMP),DE ;Save the prompt to print
LD HL,CMDBUF ;Get the start of the command buffer
LD (CMCPTR),HL ;Initialize the pointer into it
LD (CMDPTR),HL ;Save 2 copies
XOR A
LD (CMAFLG),A ;Zero the flags
LD (CMCCNT),A ;No characters
CPL ;Make it non zero
LD (CMSFLG),A ;Set these flags
LD A,(TAKFLG) ;Check if take is active
IFZ PRMT10 ;Jump if not
LD A,(TAKLOG) ;Is the take-file display flag set?
IFZ PRMT20 ;Jump if not
PRMT10 CALL NEWLIN ;Get a newline
LD DE,(CMPRMP) ;Print the prompt
CALL PRTSTR
PRMT20 RET ;Return to the caller
;
; Come to here to initiate a reparse
;
REPARS LD SP,(CMOSTP) ;GET THE OLD STACK POINTER.
LD HL,CMDBUF
LD (CMDPTR),HL
LD A,0FFH ;TRY IT THIS WAY (DAPHNE.)
LD (CMSFLG),A
LD HL,(CMRPRS) ;GET THE REPARSE ADDRESS.
JP (HL) ;GO THERE.
;
;THIS ADDRESS CAN BE JUMPED TO ON A PARSING ERROR.
;
PRSERR LD SP,(CMOSTP) ;GET THE OLD STACK POINTER.
LD HL,CMDBUF
LD (CMCPTR),HL ;INITIALIZE THE COMMAND POINTER.
LD (CMDPTR),HL
CALL NEWLIN
XOR A
LD (CMAFLG),A ;ZERO THE FLAGS.
LD (CMCCNT),A
LD A,0FFH ;TRY IT THIS WAY (DAPHNE.)
LD (CMSFLG),A
LD DE,(CMPRMP) ;GET THE PROMPT.
CALL PRTSTR
LD HL,(CMRPRS)
JP (HL)
;
;This routine parses the specified function in A. Any additional
;information is in DE and HL.
; Returns to RETURN+3 on success
; Returns to RETURN on failure. (Assumes that a JP follows CALL)
;
COMND LD (CMSTAT),A ;Save what we are presently parsing.
CALL CMINBF ;Get chars until action or erase char.
CP CMNUM ;Is the function "PARSE a number"?
JP Z,CMDNUM ;Jump if so
CP CMCFM ;Parse a confirm?
JP Z,CMCFRM ;Jump if so
CP CMKEY ;Parse a keyword from a table?
JP Z,CMKEYW ;Jump if so
CP CMIFI ;Parse a file spec?
JP Z,CMIFIL ;If so jump
CP CMIFIN ;Other file type?
JP Z,CMIFIL ;If so use same routine
CP CMOFI ;ditto
JP Z,CMIFIL
CP CMTXT ;Parse a text string?
JP Z,CMTEXT ;If so jump
LD DE,CMER00 ;Otherwise parser calling error
CALL PRTSTR ;So print a message
RET ;And return error
;
;This routine parses arbitrary text up to a <ENTER>
;
; DE=address of text buffer
;
; A=number of characters typed (zero or more) on return
;
CMTEXT EX DE,HL ;Put the pointer to the buffer in HL
LD (CMPTAB),HL ;Save the pointer
LD B,0 ;Initialize the count to zero
CMTXT1 CALL CMGTCH ;Get a character
OR A ;Test the high bit for some terminator
JP P,CMTXT5 ;If not then jump
AND 7FH ;Turn off the high bit
CP ESC ;Is it escape
RET Z ;Return failure if so
CMTXT2 IFA '?',CMTXT7 ;Jump if the user needs help
IFA ' ',CMTXT5 ;If blank, add it to text
LD A,B ;Get the counter
LD HL,(CMPTAB) ;Get the updated pointer
LD (HL),CR ;Put the terminator in
EX DE,HL ;Move ending pointer to DE
JP RSKP ;Return success
;
CMTXT3 LD HL,CMAFLG ;Point to the action flag
LD (HL),0 ;Reset it
CMTXT5 INC B ;Add one to the count of characters
CMTXT6 LD HL,(CMPTAB) ;Get the pointer
PUTHL A ;Add the character and increment
LD (CMPTAB),HL ;Save the update pointer
JR CMTXT1 ;Go get another character
;
CMTXT7 LD DE,TXTHLP ;Get the help message
CALL REPRNT ;Print the message
JP REPARS ;Jump to the reparse
;
;This routine parses an input number in ASCII decimal
;
CMDNUM LD B,0 ;Reset the character count
LD HL,0 ;Initialize the value to zero
LD (THEVAL),HL
CMNM10 CALL CMGTCH ;Get a character
OR A ;Check for high bit set terminator
JP P,CMNM50 ;Jump if not
AND 7FH ;Trim the high bit
CP ESC ;Is it ESCAPE (abort)
RET Z ;Return error if so
CMNM20 IFA '?',CMNM70 ;Go if the user needs help
LD A,B ;Get the count
LD DE,(THEVAL) ;Get the number found
JP RSKP ;Return success
;
CMNM50 INC B ;Add one to count of characters
PUSH HL ;Save the values
PUSH DE
PUSH BC
LD HL,(THEVAL) ;Get the current number
LD C,10 ;Multiply by 10
PUSH AF ;Save AF too
CALL XMUL16 ;Multiply 8 bit by 16 bit
LD H,L ;Move the 24 bit result into HL as 16
LD L,A
POP AF ;Get the character to add
SUB 48 ;Convert to a binary number
JP P,CMNM60 ;Jump if no underflow
CMNM55 POP BC ;Restore the regs
POP DE
POP HL
LD DE,ERMES2 ;Print error message
CALL PRTSTR
JP KERMIT ;GET A NEW COMMAND
;
CMNM60 IFAGE 10,CMNM55 ;Jump if too big
LD C,A ;Get it into BC for 16 bit MATH
LD B,0 ;Zero the MSB
ADD HL,BC ;Compute the new number
LD (THEVAL),HL ;Save the result
POP BC ;Restore the registers
POP DE
POP HL
JR CMNM10 ;Loop on
;
CMNM70 LD DE,NUMHLP ;Get the HELP message
CALL REPRNT ;Print the message, and reprint prompt
JP REPARS ;Plus the rest of the text, and restart
;
; Get a confirmation of the command by accepting only <ENTER>
;
CMCFRM CALL CMGTCH ;GET A CHARACTER FROM THE BUFFER
OR A ;WHAT WAS IT, CONTROL?
RET P ;NOPE, SO EXIT VIA ERROR RETURN
AND 7FH ;STRIP THE SIGN BIT FLAG
IFANOT '?',CMCFR3 ;Go if not help request
LD DE,CMIN00 ;TELL THEM NO MORE HELP
CALL REPRNT ;PRINT THE MESSAGE
JP REPARS ;PRINT THE MESSAGE AND THE PROMPT AGAIN
CMCFR3 CP ESC ;IS IT ABORT?
RET Z ;TAKE ERROR EXIT IF SO
JP RSKP ;TAKE NORMAL RETURN
;THIS ROUTINE PRINTS THE MESSAGE IN DE AND SETS UP FOR A REPARSE
REPRNT CALL PRTSTR
XOR A
LD (CMAFLG),A
CALL NEWLIN
LD DE,(CMPRMP)
CALL PRTSTR
LD HL,(CMCPTR)
DEC HL
LD (HL),EOS
LD (CMCPTR),HL
LD DE,CMDBUF
CALL PRTSTR
RET
;THIS ROUTINE PARSES A KEYWORD FROM THE TABLE POINTED
;TO IN DE. THE FORMAT OF THE TABLE IS AS FOLLOWS
;
;ADDR DB N Where N is the number of entries in the table
; DB K Where K is 2+length of longest keyword.
; Repeated for each entry in the table...
; DB M Where M is the length of the keyword
; DB 'STRING',EOS Where string is the KEYWORD.
; DB A,B Where A & B are pieces of DATA
; to be returned, (Must be two bytes worth)
;
;THE KEYWORDS MUST BE IN ALPHABETICAL ORDER.
;**** NOTE THE DATA VALUE A IS RETURNED IN REGISTERS A AND E. THE
;**** DATA VALUE B IS RETURNED IN REGISTER D. THIS ALLOWS THE TWO DATA
;BYTES TO BE STORED AS
;DW XXX
;AND RESULT IN A CORRECTLY FORMATTED 16-BIT VALUE IN REGISTER PAIR
;DE.
CMKEYW LD (CMPTAB),DE ;SAVE THE BEGINNING OF KEYWORD for ?
LD A,(DE) ;GET THE NUMBER OF ENTRIES IN THE TABLE.
LD B,A ;SAVE IN B
INC DE ;Point past the keyword count
INC DE ;POINT PAST THE MAX LENGTH NUMBER
LD (CMKPTR),DE ;Save it for later
LD HL,(CMDPTR) ;Save the command buffer pointer
LD (CMSPTR),HL
CMKEY2 LD A,B ;Get the keyword counter
OR A ;ANY LEFT?
RET Z ;IF NOT WE FAILED.
LD HL,(CMKPTR) ;Get the current keyword pointer
INC HL ;Skip the visibility
LD E,(HL) ;Get the length of the keyword
INC HL ;Skip the length
CMKEY3 DEC E ;DECREMENT THE NUMBER OF CHARS LEFT.
LD A,E
CP -1
JP M,CMKEY5 ;IF SO GO TO THE NEXT.
CALL CMGTCH ;GET A CHAR.
OR A ;IS IT A TERMINATER?
JP P,CMKEY4 ;IF POSITIVE, IT IS NOT.
AND 7FH ;TURN OFF THE MINUS BIT.
CP '?' ;Is this help?
JP NZ,CMKY35
PUSH HL ;SAVE HL FOR A SEC
PUSH DE
XOR A
LD (CMAFLG),A ;TURN OFF THE ACTION FLAG.
LD DE,HLPMES ;PRINT ONE OF THE FOLLOWING...
CALL PRTSTR
LD HL,CMCCNT ;DECREMENT THE CHAR COUNT.
DEC (HL)
POP DE
POP HL
LD HL,(CMPTAB) ;GET THE START OF THE KEYWORD TABLE
LD B,(HL) ;B IS HOW MANY IN THE TABLE
INC HL ;Point at the column spacing value
LD A,(HL) ;Get the length
LD (MAXLEN),A ;Save it for later
XOR A
LD (CURCOL),A ;Set column to starting column
INC HL ;Point at the visible attribute
CM1010 LD A,(HL) ;Get the visibility
LD (VISIBLE),A
INC HL ;POINT AT THE FIRST ENTRY
LD C,(HL) ;C IS HOW MANY CHARACTERS IN NAME
LD A,C ;SAVE THE LENGTH FOR LATER
LD (CURLEN),A
INC HL ;POINT AT THE TEXT FOLLOWING
LD (CMKPTR),HL ;SAVE THE ADDRESS TO PRINT FROM ON MATCH
LD DE,(CMSPTR) ;GET THE ADDRESS OF THE TYPED KEYWORD
CM1020 LD A,(DE) ;GET A CHARACTER
IFA '?',CM1040 ;Go if request for help
CALL CAPTAL ;MAKE SURE LETTERS ARE UPPER CASE
INC DE ;POINT TO THE NEXT.
CP (HL) ;SAME AS IN KEYWORD TABLE?
INC HL ;POINT TO THE NEXT
JR NZ,CM1050 ;JUMP IF NO MATCH
DEC C ;ONE LESS CHARACTER IN THE KEYWORD
JP P,CM1020
LD A,(DE)
IFA '?',CM1040 ;Jump if help request
CP 0 ;Set flags to P,NZ
JP CM1050 ;Join other code
CM1040 EQU $
LD A,(VISIBLE) ;Is this a visible command?
IFZ CM1045 ;Jump if it is not
PUSH DE ;SAVE THE REGS
PUSH HL
PUSH BC
LD DE,(CMKPTR) ;Get the string
CALL STRLEN ;Get length into BC
LD A,(MAXLEN) ;Get the padded length
LD B,A ;Save it for now
LD A,(CURCOL) ;Get current screen column
ADD A,B ;Compute new column
LD B,A ;Save it
LD A,(MAXCOL) ;Get right margin
IFALT B,CM1042 ;Are we passed the edge? Jump if so
LD A,B ;Get new column
LD (CURCOL),A ;Save it
LD A,(MAXLEN)
JR CM1043 ;Join code
CM1042 CALL NEWLIN ;Print a newline
LD A,(MAXLEN) ;Get the padded length
LD (CURCOL),A ;Set new position
CM1043 SUB C ;Compute blanks to print
LD C,A ;Put it into C
PUSH BC ;Save count for now
LD DE,(CMKPTR) ;Get the string to print
CALL PRTSTR ;Print the keyword
POP BC ;Restore count
CM1044 LD A,' ' ;Get a blank
CALL CONOUT ;Display it
DEC C ;Decrement counter
JR NZ,CM1044 ;Jump if not there
POP BC ;RESTORE THE REGS
POP HL
POP DE
CM1045 LD A,3 ;SKIP OVER THE EOS AND THE DISCRIPTOR
ADD A,C ;PLUS THE CHARACTERS LEFT IN THE STRING
LD E,A ;PUT IT IN DE TO ADD
LD D,0 ;MAKE IT A BYTE VALUE IN 16 BITS
ADD HL,DE ;GOT THE NEW ADDRESS
DJNZ CM1010 ;GET THE NEXT
JR CM1190 ;END OF THE TABLE
CM1050 DEC HL ;CORRECT HL FROM LAST INCREMENT
JP P,CM1045 ;IF (TABLE) > (COMMAND) KEEP LOOKING
JR Z,CM1045
XOR A ;RESET THE ACTION FLAG
LD (CMAFLG),A
CM1190 CALL NEWLIN ;PRINT A NEW LINE
CM1200 CALL NEWLIN ;PRINT A NEW LINE
LD DE,(CMPRMP) ;GET THE PROMPT TO REPRINT
CALL PRTSTR ;PRINT IT
LD HL,(CMDPTR) ;GET THE END OF THE COMMAND LINE
LD (HL),EOS ;TERMINATOR FOR PRINTING
LD HL,(CMCPTR) ;GET THE LAST CHARACTER
DEC HL
LD (CMCPTR),HL ;IGNORE THE '?' AT THE END
LD DE,CMDBUF ;GET THE START OF THE BUFFER
CALL PRTSTR ;PRINT THE COMMAND LINE
JP REPARS ;REPARSE THE ENTIRE LINE
CMKY35 CP ESC
RET Z
PUSH HL
PUSH DE
CALL CMAMBG
JP CMKY36
LD HL,(CMCPTR) ;GET THE END OF THE COMMAND
LD BC,CMDBUF ;GET THE START OF THE BUFFER
OR A ;RESET THE CARRY
SBC HL,BC ;COMPUTE THE OFFSET
LD DE,CMER01
CALL PRTSTR ;SAY ITS AMBIGUOUS.
JP PRSERR ;GIVE UP.
CMKY36 POP DE
POP HL
CMKY37 INC E ;ADD ONE IN CASE IT IS NEGATIVE.
LD D,0
ADD HL,DE ;INCREMENT PAST THE KEYWORD.
INC HL ;PAST THE EOS.
LD E,(HL) ;GET THE DATA.
INC HL
LD D,(HL)
LD A,E
JP RSKP
CMKEY4 CALL CAPTAL ;MAKE IT UPPER CASE IF LOWER
CMKY41 CP (HL) ;Check the next character
JR NZ,CMKEY5
INC HL
JP CMKEY3
CMKEY5 LD D,0
LD A,E ;GET THE NUMBER OF CHARS LEFT.
OR A ;IS IT NEGATIVE?
JP P,CMKY51
LD D,0FFH
CMKY51 EQU $
ADD HL,DE ;INCREMENT PAST THE KEYWORD.
INC HL ;PLUS 4
INC HL
INC HL
INC HL
LD (CMKPTR),HL
DEC B ;DECREMENT THE NUMBER OF ENTRIES LEFT.
LD HL,(CMSPTR) ;GET THE OLD CMDPTR.
LD (CMDPTR),HL ;RESTORE IT.
JP CMKEY2 ;GO CHECK THE NEXT KEYWORD.
;CONVERT CONTENTS OF A TO UPPER CASE IF IT IS LOWER
CAPTAL IFALT 'a',CAPS10
IFAGE 'z'+1,CAPS10
AND 137O ;MAKE IT UPPER CASE
CAPS10 RET ;RETURN TO THE CALLER
;CHECK AMBIGUITY OF A COMMAND
CMAMBG DEC B ;DECREMENT THE NUMBER OF ENTRIES LEFT.
RET M ;IF NONE LEFT THEN IT IS NOT AMBIGUOUS.
INC E ;THIS IS OFF BY ONE;ADJUST.
LD C,E ;SAVE THE CHAR COUNT.
LD A,E
OR A ;ANY CHARS LEFT?
RET Z ;NO, IT CAN'T BE AMBIGUOUS.
LD D,0
ADD HL,DE ;INCREMENT PAST THE KEYWORD.
LD E,4 ;PLUS THE EOS AND DATA.
ADD HL,DE
LD B,(HL) ;GET THE LENGTH OF THE KEYWORD.
INC HL
EX DE,HL
LD HL,(CMKPTR) ;GET POINTER TO KEYWORD ENTRY.
INC HL
LD A,(HL) ;GET THE LENGTH OF THE KEYWORD.
SUB C ;SUBTRACT HOW MANY LEFT.
LD C,A ;SAVE THE COUNT.
IFA B,CMAMB0
RET P ;IF LARGER THAN THE NEW WORD THEN NOT AMB
CMAMB0 LD HL,(CMSPTR) ;GET THE POINTER TO WHAT PARSED.
CMAMB1 DEC C ;DECREMENT THE COUNT.
JP M,RSKP ;IF WE ARE DONE THEN IT IS AMBIGUOUS.
EX DE,HL ;EXCHANGE THE POINTERS.
LD B,(HL) ;GET THE NEXT CHAR OF THE KEYWORD
INC HL
EX DE,HL ;EXCHANGE THE POINTERS.
LD A,(HL) ;GET THE NEXT PARSED CHAR.
INC HL
CALL CAPTAL ;MAKE IT UPPER IF LOWER
CMAMB2 CP B ;ARE THEY EQUAL?
RET NZ ;IF NOT THEN ITS NOT AMBIGUOUS.
JP CMAMB1 ;CHECK THE NEXT CHAR.
;
; Parse a file specification. This includes a call to @FSPEC to
; do case conversion, and any other necessary stuff to make a
; legal file spec. On normal return, A has the count of characters
; that are in the passed buffer
;
CMIFIL LD (CMFCB),DE ;SAVE WHERE TO PUT THE CHARACTERS
LD DE,CLBUF
LD B,0 ;Set the count to zero
CMIFI1 CALL CMGTCH ;GET A CHARACTER
OR A ;CHECK FOR A CONTROL CHARACTER ?,CR,ESC
JP P,CMIFI3 ;GO IF NOT CONTROL
AND 7FH ;STRIP THE HIGH BIT
CP ESC ;WAS IT ABORT?
RET Z ;TAKE THE ERROR EXIT
IFANOT '?',CMIFI4 ;Go if not help request
LD DE,FILHLP ;PRINT A MESSAGE
CALL REPRNT ;SET UP FOR REPARSE
JP REPARS ;GET A NEW CHARACTER
CMIFI3 LD (DE),A ;STORE THE CHARACTER
INC DE ;POINT TO NEXT POS
INC B ;INCREMENT CHARACTER COUNT
JR CMIFI1 ;GET ANOTHER ONE
CMIFI4 LD A,CR ;Get the end of name marker
LD (DE),A ;Put in a terminator
LD A,B ;Get the count
IFZ CMIFI5 ;Skip fspec if no characters given
PUSH HL ;Save the pointer
LD HL,CLBUF ;GET THE TEXT TO FSPEC
LD DE,(CMFCB) ;WHERE TO PUT THE RESULT
CALL XFSPEC ;MAKE IT A FILE SPEC
JP NZ,CMIFI6 ;Oops, bad fspec
EX DE,HL ;Move start to HL
LD A,3 ;Get the character to find
LD BC,40 ;Get the maximum distance to look
CPIR ;Find it
LD HL,39 ;Find out how far we looked
OR A ;Reset the carry
SBC HL,BC ;Compute the distance
LD B,L ;Get the length
POP HL ;Restore pointer which is...
CMIFI5 LD (CMDPTR),HL ;Next place to put characters at
LD A,B ;Copy the length to A
JP RSKP ;Return normal
;
CMIFI6 POP HL ;Restore the stack
JP XERROR0 ;Print a system message and return
;
; Get input characters from the keyboard, up to an action character
; The actual character input is retrieved via GETSTR().
;
CMINBF PUSH AF
PUSH DE
PUSH HL
LD A,(CMAFLG) ;IS THE ACTION CHAR FLAG SET?
IFNZ CMINB9 ;Go if it is
LD HL,(CMCPTR) ;Get the position
PUSH HL ;Save it for later
LD DE,CMDBUF ;Get EOB
OR A ;Reset carry
SBC HL,DE ;Compute number of characters typed in
LD B,L ;Get number of characters
POP HL ;Get the value back
CALL GETSTR ;Input up to an action character
JP C,PRSERR ;Jump if user pressed break
LD A,B ;SAVE THE COUNT
LD (CMCCNT),A
LD C,B ;GET THE NUMBER OF CHARACTERS IN BUFFER
LD B,0
LD HL,CMDBUF ;Get the start
PUSH HL ;Save it
ADD HL,BC ;Add the count
LD (CMCPTR),HL ;Save next input position
POP BC ;Get the start
OR A ;Reset the carry
SBC HL,BC ;Are there any characters in the buffer?
JP Z,PRSERR ;IF NO CHARACTERS START OVER
CMINB6 LD A,0FFH ;SET THE ACTION FLAG.
LD (CMAFLG),A
CMINB9 POP HL ;Restore the registers
POP DE
POP AF
RET ;Return
;
; Get a character from the command input buffer. If an action
; character is found, then the MSB of the character will be set
;
CMGTCH PUSH HL
PUSH BC
CMGTC1 LD A,(CMAFLG)
OR A ;IS IT SET.
CALL Z,CMINBF ;IS THE ACTION CHAR FLAG SET?
LD HL,(CMDPTR) ;GET A POINTER INTO THE BUFFER.
LD A,(HL) ;GET THE NEXT CHAR.
INC HL
LD (CMDPTR),HL
IFA ' ',CMGTC2
IFANOT TAB,CMGTC3
CMGTC2 LD A,(CMSFLG) ;GET THE SPACE FLAG.
IFNZ CMGTC1 ;Was last char a space?
LD A,0FFH ;SET THE SPACE FLAG.
LD (CMSFLG),A
LD A,' '
POP BC
POP HL
JR CMGTC5
CMGTC3 PUSH AF
XOR A
LD (CMSFLG),A ;ZERO THE SPACE FLAG.
POP AF
POP BC
POP HL
IFA ESC,CMGTC5 ;Go if escape abort
IFA '?',CMGTC4 ;Go answer a help request
IFA CR,CMGTC4
CP LF
RET NZ ;NOT AN ACTION CHAR, JUST RETURN.
CMGTC4 PUSH HL
LD HL,(CMDPTR)
DEC HL
LD (CMDPTR),HL
POP HL
CMGTC5 OR 80H ;MAKE THE CHAR NEGATIVE TO INDICATE IT IS
RET ;A TERMINATOR.
STRLEN EQU $
PUSH AF
PUSH DE
LD BC,0
STRLEN_1 EQU $
LD A,(DE)
IFA EOS,STRLEN_2
INC DE
INC BC
JR STRLEN_1
STRLEN_2 EQU $
POP DE
POP AF
RET
;end of file
<<< m4equ.asm >>>
;
; Symbolic defintions for some ASCII characters
;
EOS EQU 0 ;Printed string terminator
BELL EQU 07O ;ASCII BEL (CONTROL-G)
CTRLC EQU 03O ;ASCII ETX (CONTROL-C)
TAB EQU 11O ;ASCII TAB (CONTROL-I)
LF EQU 12O ;ASCII LINE FEED (CTRL-J)
FF EQU 14O ;ASCII FORM FEED (CTRL-L)
CR EQU 15O ;ASCII CARRIAGE RETURN (CTRL-M)
XON EQU 21O ;THE THE ASCII CHARACTER USED FOR XON
XOFF EQU 23O ;THE THE ASCII CHARACTER USED FOR XOFF
ESC EQU 33O ;ASCII ESCAPE
SUBT EQU 32O ;ASCII SUB (CTRL-Z)
DEL EQU 177O ;ASCII DELETE (RUBOUT)
DEFESC EQU 31 ;<CLEAR> KEY ON KEY BOARD
MAXPKT EQU '~'-' '+2O ;MAXIMUM SIZE OF A PACKET.
DRPSIZ EQU 5EH ;DEFAULT RECEIVE PACKET SIZE.
DSPSIZ EQU 20H ;DEFAULT SEND PACKET SIZE.
DSTIME EQU 15 ;DEFAULT SEND TIME OUT INTERVAL.
DRTIME EQU 10 ;DEFAULT RECEIVE TIME OUT INTERVAL.
DSPAD EQU 00H ;DEFAULT SEND PADDING.
DRPAD EQU 00H ;DEFAULT RECEIVE PADDING.
DSPADC EQU 00H ;DEFAULT SEND PADDING CHAR.
DRPADC EQU 00H ;DEFAULT RECEIVE PADDING CHAR.
DSEOL EQU CR ;DEFAULT SEND EOL CHAR.
DREOL EQU CR ;DEFAULT RECEIVE EOL CHAR.
DSQUOT EQU '#' ;DEFAULT SEND QUOTE CHAR.
DRQUOT EQU '#' ;DEFAULT RECEIVE QUOTE CHAR.
DSCHKT EQU '1' ;DEFAULT CHECKSUM TYPE
SOH EQU 01H ;START OF HEADER CHAR.
CMKEY EQU 01H ;PARSE A KEYWORD.
CMIFI EQU 02H ;PARSE AN INPUT FILE SPEC.
CMOFI EQU 03H ;PARSE AN OUTPUT FILE SPEC.
CMCFM EQU 04H ;PARSE A CONFIRM.
CMTXT EQU 05H ;PARSE TEXT.
CMNUM EQU 06H ;PARSE ASCII DECIMAL STRING
CMIFIN EQU 10H ;PARSE AN INPUT FILE SPEC
<<< m4file.asm >>>
; m4file/asm
;
; The close command. At present, only SESSION is valid
;
CLSFLS CALL GETLOGF ;Get the logfile descriptor
IFNZ CLSF10 ;Skip if not SESSION LOG FILE
LD A,(LOGFLG) ;Check to see if session log open
IFZ CLSF07 ;If already closed, then jump to message
XOR A ;Reset the FILE OPEN flag
LD (LOGFLG),A
LD DE,LFCB ;Get the FCB for the CLOSE
CALL XCLOSE ;Close the file if possible
CALL NZ,XERROR0 ;Print a message if file not closed right
JR CLSF08 ;Back for another command
CLSF07 STROUT NOLOGF ;Print LOG FILE NOT OPEN message
CLSF08 JP KERMIT ;Back for another command
;
; Check the debug logfile
;
CLSF10 IFANOT 1,CLSF30 ;If not debug then try transaction
LD A,(DEBLOG) ;Check if logging in effect
IFZ CLSF07
XOR A ;Zap the open flag
LD (DEBLOG),A
LD DE,DFCB ;Get the FCB
CALL XCLOSE
CALL NZ,XERROR0
JR CLSF08
;
; Check the transaction logfile
;
CLSF30 LD A,(TRANLOG) ;Check if it is open
IFZ CLSF07
XOR A ;Zap the open flag
LD (TRANLOG),A ;Reset it
LD DE,TRFCB ;Get the transaction FCB
CALL XCLOSE ;Close the file
CALL NZ,XERROR0 ;Print system message if error
JR CLSF08 ;Back for another command
;
; THIS IS THE LOG COMMAND.
;
LOG EQU $
CALL GETLOGF ;Get the logfile descriptor
OR A
JP Z,LOGSES ;If zero then session logging
CP 2
JP Z,LOGTRAN ;Go do transaction logging
;
; Debug logging
;
LD A,(DEBLOG) ;See if logging already in effect
IFZ LOG_3
LOG_1 STROUT LOGOPN ;Print LOG OPEN message
JP KERMIT ;RETURN TO COMMAND PARSER
LOG_3 LD DE,DFCB
PUSH DE ;Save it for later
LD A,CMIFI ;Get a file spec
CALL COMND ;Parse it
JP KERMT3 ;Exit if not confirmed
IFNZ LOG_3A
LD HL,DEFDEBLOG ;Get the default name
LD DE,DFCB
LD BC,32
LDIR ;Move it into place
LOG_3A POP DE ;Get the FCB back
LD HL,DBUFF ;Get the buffer
LD B,0 ;Use 256 LRL
CALL XINIT ;Create the output file
JR Z,LOG_5
IFA 42,LOG_5 ;Ignore a LRL error
LOG_4 CALL XERROR0
JP KERMIT
LOG_5 LD A,1
LD (DEBLOG),A ;Set the log file open flag
JP KERMIT
;
; Session logging
;
LOGSES LD A,(LOGFLG) ;Check if session log open
IFZ LOG_6
JP LOG_1 ;Oops, log already open
LOG_6 LD A,CMIFI ;PARSE AN INPUT FILE SPEC.
LD DE,LFCB ;Get the session log FCB
PUSH DE ;Save it for later
CALL COMND ;Parse it
JP KERMT3
IFNZ LOG_6A ;Jump if text was given
LD HL,DEFSESLOG ;Get the default name
LD DE,LFCB ;Get the FCB
LD BC,32 ;Get the count
LDIR ;Move the block
LOG_6A LD HL,LBUFF ;Get the buffer
POP DE ;Get the session log FCB
LD B,0 ;Select 256 byte records
CALL XINIT ;Create a new file
JR Z,LOG_8 ;Continue on a no error return
IFANOT 42,LOG_4 ;If not LRL error, then abort
LOG_8 XOR A
LD (PREVLCHR),A ;Reset the previous character
LD A,2
LD (LOGFLG),A ;Turn logging on
JP KERMIT ;Jump to get a new command
;
; Transaction logging
;
LOGTRAN LD A,(TRANLOG) ;Get the flag
IFZ LOG_9
JP LOG_1 ;Oops log already open
LOG_9 LD A,CMIFI ;Get a file spec
LD DE,TRFCB
PUSH DE ;Save it for later
CALL COMND ;Parse a file name
JP KERMT3 ;Abort if no confirm
IFNZ LOG_9A ;Jump if text given
LD HL,DEFTRLOG ;Get the default
LD DE,TRFCB
LD BC,32
LDIR ;Move it
LOG_9A POP DE
LD HL,TBUFF ;Get the buffer
LD B,0 ;Select 256 LRL
CALL XINIT ;Create the output file
JR Z,LOG_10
IFANOT 42,LOG_4
LOG_10 LD A,1 ;Set the flag to ON
LD (TRANLOG),A
JP KERMIT ;Back for another command
;
; Get a logfile identifier
;
GETLOGF LD A,CMKEY ;PARSE A KEYWORD
LD DE,CLSTAB ;GET THE PARSE TABLE
CALL COMND ;GET A KEYWORD
JP KERMT2 ;ABORT ON AN ERROR
RET ;Return to caller
;
; Output a normal string terminated by EOS.
;
OUTLOG LD A,EOS
JP OUTLOGCH
;
; Output a message to a log file
; HL=message, DE=FCB, A=terminator character
;
OUTLOGCH EQU $
PUSH HL ;Save the registers
PUSH DE
LD (ENDCH),A ;Store the terminator
OUTL_1 LD A,(HL) ;Get a character
CP EOS
ENDCH EQU $-1 ;Address of terminator character
JR Z,OUTL_2
PUSH HL ;Save the string address, and the FCB
PUSH DE
CALL XPUT ;@PUT the character
POP DE ;Restore the addresses
POP HL
JR NZ,OUTL_3 ;On error, abort
INC HL ;Point to next character
JR OUTL_1 ;Loop on
OUTL_2 POP DE ;Restore stack
POP HL
JP RSKP ;Return normal
;
; Log file error
;
OUTL_3 CALL XERROR0 ;Print system message
STROUT LOGERROR ;Print a message on the console
POP DE ;Restore the stack
POP HL
RET ;Return error
;end of file
<<< m4get.asm >>>
; M4GET/ASM
; RECEIVE COMMAND
READ EQU $
CALL NEWLIN
NSTATE 'R' ;Set initial protocol state
LD DE,DATA ;WHERE TO PUT THE TEXT (IF ANY.)
LD A,CMTXT
CALL COMND ;GET EITHER SOME TEXT OR A CONFIRM.
JP KERMT3 ;DIDN'T GET ANYTHING.
OR A ;GET ANY CHARS?
JR Z,READ1 ;NOPE, JUST A REGULAR SEND.
LD (ARGBLK+1),A ;STORE THE NUMBER OF CHARS.
LD (TEMP4),A ;Save the length
EX DE,HL ;GET POINTER INTO HL.
LD (HL),EOS ;Put in the print terminator
NSTATE 'r' ;Set state to receive init with file
READ1 CALL INIT ;Clear input line and init buffers
LD HL,0 ;Reset all the flags
LD (NUMPKT),HL ;SET THE NUMBER OF PACKETS TO ZERO.
LD (NUMRTR),HL ;SET THE NUMBER OF RETRIES TO ZERO.
LD (KTRANS),HL
XOR A
LD (PKTNUM),A ;SET THE PACKET NUMBER TO ZERO.
LD (NUMTRY),A ;SET THE NUMBER OF TRIES TO ZERO.
LD (CZSEEN),A ;Reset the control-Z seen flag
LD A,'R' ;Get the state character
LD (DISFLG),A ;Set the display flag
CALL CONDCHR ;Display it as well
CALL CLRPRT ;CLEAR OUT THE COMMUNICATIONS PORT
STROUT HELPMSG
CALL PROTO
JP KERMIT
;
; This is the complete state
;
COMP EQU $
LD DE,INFMS3 ;PUT IN "COMPLETE" MESSAGE.
LD A,(CZSEEN)
OR A ;...
JR Z,COMP1
XOR A ;YES, CLEAR FLAG.
LD (CZSEEN),A
LD DE,INMS13 ;ISSUE "INTERRUPTED" MESSAGE.
COMP1 LD A,(DISFLG) ;But only if we are supposed to
OR A
CALL NZ,FINMES ;PRINT COMPLETION MESSAGE
JP KERMIT
;
; This is the abort state
;
SABORT EQU $
LD DE,INFMS4 ;Message to print
JR COMP1 ;Go print it conditionally
;
; Initialize the buffers, and clear the line
;
INIT XOR A ;BUFFER SIZE.
LD (CHRCNT),A ;NUMBER OF CHARS LEFT.
LD HL,BUFF ;ADDR FOR BEGINNING.
LD (BUFPNT),HL ;STORE ADDR FOR BEGINNING.
CALL CLRPRT
RET
;
; RECEIVE ROUTINES
;
; RECEIVE INIT with no previous file header
;
RINIT CALL CHKTRYS ;Check retry threshold
LD A,'1' ;RESET BLOCK CHECK TYPE TO SINGLE CHAR
LD (CURCHK),A ;STORE AS CURRENT TYPE FOR INITIALIZATION
CALL RPACK ;GET A PACKET.
JP NAK ;TRASHED PACKET NAK, RETRY.
JR RINIT_1
;
; This entry point is for GET's. The file name is in DATA, and
; and 'R' packet will be sent out to ask for the file.
;
RINITF CALL CHKTRYS ;Check retry threshold
LD A,'1' ;START WITH SINGLE CHARACTER CHECKSUM
LD (CURCHK),A ;SAVE THE TYPE
LD A,(TEMP4) ;Get the length
LD (ARGBLK+1),A ;Put it in the packet
XOR A ;Start at packet zero
LD (ARGBLK),A
LD A,'R' ;Send RECV INIT
CALL SPACK
JP RECABORT ;Die if SEND fails
LD A,'1' ;Reset the blk check type to 1
LD (CURCHK),A ;Store it
CALL RPACK ;Get a packet
JP QUIT ;Trashed, return to protocol
JR RINIT_1 ;Join other code
;
; Common receive init code
;
RINIT_1 EQU $
IFANOT 'S',RINIT3 ;Send initiate packet?
LD A,(NUMTRY) ;GET THE NUMBER OF TRIES.
LD (OLDTRY),A ;SAVE IT.
XOR A
LD (NUMTRY),A ;RESET THE NUMBER OF TRIES.
LD A,(ARGBLK) ;RETURNED PACKET NUMBER. (SYNC THEM.)
CALL INCPKT ;Increment the packet number
CALL INCDISPKT
LD A,(ARGBLK+1) ;GET THE NUMBER OF ARGUMENTS RECEIVED.
LD HL,DATA ;GET A POINTER TO THE DATA.
CALL SPAR ;GET THE DATA INTO THE PROPER VARIABLES.
LD HL,DATA ;GET A POINTER TO OUR DATA BLOCK.
CALL RPAR ;SET UP THE RECEIVE PARAMETERS.
LD (ARGBLK+1),A ;STORE THE RETURNED NUMBER OF ARGUMENTS.
LD A,'Y' ;ACKNOWLEDGE PACKET.
CALL SPACK ;SEND THE PACKET.
JP RECABORT ;FAILED, ABORT.
LD A,(INICHK)
LD (CURCHK),A ;FOR ALL FUTURE PACKETS
NSTATE 'f'
LD A,'F'
CALL CONDCHR ;Display which packet
RET
RINIT3 IFANOT 'E',NAK_0 ;Is it a NAK ?
CALL ERROR
JP RECABORT
;
; THESE ARE SOME UTILITY ROUTINES.
;
; RECABORT
;
RECABORT EQU $
LD IX,RTRANS ;Get the receive data area
CALL UPDTRANS ;Update the transfer statics
ABORT NSTATE 'A' ;Set state to abort
ABORT_1 LD A,(LOGTRAN) ;Check if logging active
CP 1 ;Is it on?
RET NZ ;Return if not
LD DE,TRFCB ;Get the FCB
TRLOG TRANABRT,ABORT_2;Log the aborted message
RET ;Return
;
; Close up after a tranaction log error
;
ABORT_2 XOR A ;Reset the logging active flag
LD (LOGTRAN),A
LD DE,TRFCB ;Close the log file
CALL XCLOSE
RET
;
; SNDABORT
;
SNDABORT NSTATE 'A'
LD IX,STRANS
CALL UPDTRANS
JP ABORT_1
;
; Nack a packet.
;
NAK_0 XOR A ;Reset to first packet
LD (PKTNUM),A ;Set the packet number
JR NAK ;Join NAK code
;
NAK_RTR CALL UPDRTR ;Update retries
;
NAK LD A,(PKTNUM) ;GET THE PACKET NUMBER WE'RE WAITING FOR.
LD (ARGBLK),A
XOR A ;NO DATA.
LD (ARGBLK+1),A
LD A,'N' ;NAK THAT PACKET.
CALL SPACK
JP RECABORT ;GIVE UP.
LD A,'N' ;Display NAKed character
CALL CONDCHR
RET ;GO AROUND AGAIN.
;
; Update the retry count
;
UPDRTR EQU $
LD HL,(NUMRTR)
INC HL ;INCREMENT THE NUMBER OF RETRIES
LD (NUMRTR),HL
RET
;
; THIS ROUTINE SETS UP THE DATA FOR INIT PACKET (EITHER THE
; SEND_INIT OR ACK PACKET).
;
RPAR ADDPUT RPSIZ ;GET THE RECEIVE PACKET SIZE.
ADDPUT STIME ;Add send timeout
ADDPUT RPAD ;Add padding amount
LD A,(RPADCH) ;Get the pad character
ADD A,100O ;UNCONTROL IT.
PUTHL A ;Put the pad character in
ADDPUT REOL ;Put the end of line character
LD A,(RQUOTE) ;GET THE QUOTE CHAR.
PUTHL A
LD A,(EBQFLG) ;Is eighth bit quoting on?
IFZ RPAR1 ;If not, then say no
PUTHL 'Y' ;Say yes to anything
JR RPAR2
RPAR1 PUTHL 'N' ;Say no eighth bit quoting
RPAR2 LD A,(INICHK) ;Check type
PUTHL A
LD A,(RPTQ) ;Get the repeat quote
PUTHL A
LD A,9 ;Nine pieces of data
RET
;
; Tochar() A, and store indirect HL, then increment HL
;
TCHPUT ADD A,' ' ;Tochar(A)
PUTHL A ;Store it, and increment
RET ;Return
;
; THIS ROUTINE READS IN ALL THE SEND_INIT PACKET INFORMATION.
;
SPAR LD (TEMP4),A ;Save the number of arguments
PUSH BC
XOR A
LD B,A
LD (RPTFLG),A ;Set everything to default
CALL CHKSPAR ;Check number of characters in packet
LD A,(HL) ;Get THEIR Max packet size
SUB 20H ;Make it real
LD (SPSIZ),A ;Save the value
CALL CHKSPAR ;Check the count
GETHL A
SUB 20H ;Make it real
LD (RTIME),A ;Send packet timeout value
CALL CHKSPAR ;Check the count
GETHL A
SUB 20H ;Make it real
LD (SPAD),A ;Save the padding character
CALL CHKSPAR ;Check the count of characters
GETHL A
ADD A,100O ;RE-CONTROLIFY IT.
AND 7FH ;Keep us honest
LD (SPADCH),A ;Save the padding character
CALL CHKSPAR ;Check the count
GETHL A
SUB 20H ;Make it the real value
LD (SEOL),A ;Save the value
CALL CHKSPAR ;Check the count
GETHL A
LD (SQUOTE),A ;Save it
CALL CHKSPAR ;Check the count
INC HL
LD A,(EBQFLG)
IFZ SPAR7
LD A,(HL)
IFA 'Y',SPAR4
IFANOT 'N',SPAR5
XOR A
JR SPAR6
SPAR4 LD A,'&'
SPAR5 LD (EBQ),A
SPAR6 LD (EBQFLG),A
SPAR7 CALL CHKSPAR ;Check the count
GETHL A
LD C,A ;COPY VALUE
LD A,(CHKTYP) ;GET OUR TYPE
IFA C,SPAR8
LD A,'1' ;NO, USE SINGLE CHARACTER
SPAR8 LD (INICHK),A
CALL CHKSPAR ;Check the count
GETHL A
IFA ' ',SPAR10
LD C,A
LD (RPTQ),A ;Save it
LD (RPTFLG),A
SPAR10 EQU $
POP BC
RET ;AND RETURN
;
; Check the count of characters left in the packet.
;
CHKSPAR EQU $
LD A,(TEMP4)
INC B
CP B
RET P
POP HL ;Remove return address
POP BC ;Restore original BC
RET ;Return to caller
;
; RECEIVE FILE
;
RFILE CALL CHKTRYS ;Check retry threshold
CALL RPACK ;GET A PACKET.
JP NAK ;TRASHED PACKET NAK, RETRY.
IFANOT 'S',RFILE2 ;If not send init, then jump
CALL CHKOLD ;Make sure we have not surpassed retries
CALL CHKBLKDEC ;Check if previous packet number
JP NZ,NAK_RTR ;No, NAK it, and try again
CALL UPDRTR ;Update the retry count.
LD HL,DATA ;Get the data address
CALL RPAR ;Set up the parameter information
LD (ARGBLK+1),A ;Save the number of bytes in the packet
LD A,'Y' ;Acknowledge with parameters
CALL SPACK ;Send the packet
JP RECABORT ;Send failed, abort
LD A,'S' ;Show the state as still send init
CALL CONDCHR
RET
;
RFILE2 IFANOT 'Z',RFILE3 ;EOF packet? Jump if not
CALL CHKOLD ;Check retry treshold
CALL CHKBLKDEC ;Was it previous packet in sequence?
JP NZ,NAK_RTR ;No, NAK it and try again
CALL UPDRTR ;Update the number of retries
XOR A ;Set length to zero
LD (ARGBLK+1),A ;No data
LD A,'Y' ;Send an ACK
CALL SPACK ;Send the packet
JP RECABORT ;Send failed, abort
LD A,'Z' ;Show state as EOF
CALL CONDCHR
RET
RFILE3 IFANOT 'F',RFILE4 ;Jump if not FILE header packet
CALL CHKBLK ;Check packet number against current
JP NZ,NAK_RTR ;If not the same, then NAK and try again
CALL INCPKT ;Increment the packet number
CALL INCDISPKT ;Increment the real packet count
LD A,'F'
LD (DISFLG),A ;Set the non-generic mode flag
CALL CONDCHR ;Print the state character
CALL GOFIL ;Get the file
JP RECABORT ;Abort on an error
CALL INIT ;Initialize everything else
CALL NUM2OLD ;Reset the retry number
LD (ARGBLK+1),A ;On return, A is zero, so NO DATA
LD A,'Y' ;Send an ACK
CALL SPACK ;Send the packet
JP RECABORT ;Send failed, abort
NSTATE 't' ;Set the state to receive transition
LD A,(CZSEEN) ;Check if user requested EOF or EOT
CP 'Z' ;Was it EOF?
RET Z ;If it was EOF, then not yet
XOR A ;Otherwise, must be EOT, so reset
LD (CZSEEN),A ;Reset the flag
RET ;And return, ignoring other states
RFILE4 IFANOT 'B',RFILE5 ;Jump if not EOT
CALL CONDCHR ;Display the state
CALL CHKBLK ;Check packet number against current
JP NZ,NAK_RTR ;If not right, then NAK and try again
XOR A ;Set data length to zero
LD (ARGBLK+1),A ;Store it for later
LD A,'Y' ;Send an ACK
CALL SPACK ;Send the packet
JP RECABORT ;Send failed, abort
NSTATE 'C' ;Set state to complete
RET ;Return to caller
RFILE5 CP 'X' ;Type on tty packet?
JP NZ,BADERROR ;Bad packet if not
CALL CHKBLK ;Make sure the packet number is right
RET NZ ;Return if not
CALL SETUPDIS ;Set up to type on terminal
CALL PRTPKTOUT ;Print the packet contents
CALL NEWLIN ;Get a newline
CALL NUM2OLD ;Get new retry count
LD (ARGBLK+1),A ;Zero length (A is zero on return)
LD A,'Y' ;Send an ACK
CALL SPACK ;Send the packet
JP RECABORT ;Quit if send fails
LD A,(PKTNUM) ;Get the packet number
CALL INCPKT ;Add one
CALL INCDISPKT ;Increment count for display
NSTATE 'd' ;Set the state to receive data
RET ;Return to protocol switch
;
; Transition between receive file, and receive data
;
RECTRAN EQU $
STROUT KERREC ;Print the receiving message
STROUT TFILNAM ;Print the name of the file
LD A,(TRANLOG) ;Get the flag
IFZ RTRAN_1 ;Test the flag and jump if not set
LD DE,TRFCB ;Get the FCB
TRLOG KERREC,RTRAN_3 ;Log the string
TRLOG TFILNAM,RTRAN_3 ;Log the file name
TRLOG TIMEMES,RTRAN_3 ;Log the time message
CALL PRTTIME ;Print the current time
RTRAN_1 EQU $
LD DE,FCB ;Get the file FCB address
LD (RFIDCB),DE ;Save it as the output FCB
CALL RSETPKT ;Reset the packet coding routines
NSTATE 'd' ;Set the state to receive data
RET
;
; Clean up on log file failure
;
RTRAN_3 XOR A ;Clear A
LD (TRANLOG),A ;Reset the logging flag
LD DE,TRFCB ;Get the FCB
CALL XCLOSE
JR RTRAN_1 ;Ignore rest of logging code
;
; RECEIVE DATA
;
RDATA CALL CHKTRYS ;Check the retry threshold
CALL RPACK ;Get a packet
JP NAK ;NAK it if bad packet
IFANOT 'D',RDATA2 ;If not data check others
RDAT11 CALL CHKBLK ;Check packet number against current
JR Z,RDAT14 ;Jump if current packet
CALL CHKOLD ;Check tries
CALL CHKBLKDEC ;Check packet number against previous
JP NZ,NAK_RTR ;Was not previous, so NAK it and retry
CALL UPDRTR ;Update the number of retries
XOR A ;Clear A
LD (NUMTRY),A ;Reset the number of tries
LD (ARGBLK+1),A ;Set the data length to zero
LD A,'Y' ;Send ACK packet
CALL SPACK ;Send the packet
JP RECABORT ;Send failed, abort
LD A,'%' ;Say we already saw this packet
CALL CONDCHR ;and just stay in the same state
RET ;Next packet
RDAT14 CALL INCPKT ;Increment the packet number
CALL INCDISPKT ;Increment the real packet count
LD A,(NUMTRY) ;Get the number of retries
LD (OLDTRY),A ;Save it
LD A,(ARGBLK+1) ;Get the length of the data
CALL PTCHR ;Decode the data packet and write it out
JP RECABORT ;Can't write to output, abort
XOR A ;Clear A
LD (NUMTRY),A ;Reset the number of tries
LD (ARGBLK+1),A ;Set data length to zero
LD C,A ;Make C zero
LD A,(CZSEEN) ;Check the flag
IFZ RDAT15 ;If nothing, then skip
LD C,A ;Get the character typed
LD A,1 ;One data character
LD (ARGBLK+1),A ;Set the length
LD A,C ;Get the data character
LD (DATA),A ;Store the character
RDAT15 LD A,'Y' ;Send an ACK (Possibly with data)
CALL SPACK ;Send the packet
JP RECABORT ;Send failed, abort
LD A,(NUMPKT) ;Time to log the progress?
AND 3 ;Only every 4 packets
RET NZ ;Return if not time
LD A,'.' ;Get the character
CALL CONDCHR ;Log it if not doing 'X' packet
RET
RDATA2 IFANOT 'F',RDATA3 ;File header? Jump if not
CALL CHKOLD ;Check against previous retries
CALL CHKBLKDEC ;Check packet number against previous
JP NZ,NAK_RTR ;If not previous, then NAK and try again
CALL UPDRTR ;Update the number of retries
XOR A ;Clear A
LD (NUMTRY),A ;Reset the number of retries
LD (ARGBLK+1),A ;Set the length to zero
LD A,'Y' ;Send an ACK
CALL SPACK ;Send the packet
JP RECABORT ;Send failed, abort
LD A,'%' ;Already saw this one.
CALL CONDCHR ;Tell the user
RET
RDATA3 CP 'Z' ;If not EOF then jump
JP NZ,RDATA4
CALL CONDCHR ;Display the new state
CALL CHKBLK ;Check packet number against current
JP NZ,NAK_RTR ;If not, then NAK and try again
CALL INCPKT ;Increment the packet number
CALL INCDISPKT ;Increment the real packet count
LD A,(ARGBLK+1) ;Get the length of the data
IFANOT 1,RDAT35 ;Jump if packet length not 1
LD A,(DATA) ;Just one, get the data
IFANOT 'D',RDAT36 ;Is it discard? Jump if not
LD A,(TRANLOG) ;Check if loggin active
IFZ RDAT31
LD DE,TRFCB ;Get the log file FCB
TRLOG TRANCANC,RDAT39 ;Print canceled message
RDAT31 LD A,(DISCARD) ;Check users preference for incompletes
IFZ RDAT35 ;Jump if no discard
CALL CHKFCB ;Is this FCB or *SO?
JR NZ,RDAT36 ;Jump if no remove, and don't close either
CALL XREMOVE ;Remove it
JR Z,RDAT32 ;Jump if remove succeeded
CALL XERROR0 ;Print system error message
JR RDAT36 ;Join other code
RDAT32 STROUT RMMES ;Print the message
LD A,(TRANLOG) ;Check if loggin active
IFZ RDAT36
LD DE,TRFCB
TRLOG RMMES,RDAT39
JR RDAT36 ;Join the other code
RDAT35 CALL CHKFCB ;Check for file FCB, don't close *SO
CALL Z,XCLOSE ;Conditionally close the FILE
RDAT36 XOR A ;Reset the EOF seen flag
LD (CZSEEN),A
CALL NUM2OLD ;Reset the number of retries
LD (ARGBLK+1),A ;Set the length to zero
LD A,'Y' ;Send an ACK
CALL SPACK ;Send the packet
JP RECABORT ;Send failed, abort
NSTATE 'f' ;Set state to receive file
LD IX,RTRANS ;Get the receive statistics address
CALL UPDTRANS ;Update the transfer statistics
RET
;
; Close up on a transaction log error
;
RDAT39 XOR A ;Reset the logging flag
LD (TRANLOG),A
LD DE,TRFCB ;Close the file
CALL XCLOSE
JR RDAT36 ;Rejoin code
;
RDATA4 CP 'X' ;Is it End Of Transmission?
JP NZ,BADERROR ;If not, then bad packet
CALL CHKBLKDEC ;Check if previous sequence number
RET NZ ;Return if not
XOR A ;Clear A
LD (ARGBLK+1),A ;Set the length to zero
LD A,'Y' ;Send an ACK
CALL SPACK ;Send the packet
JP RECABORT ;Send failed, abort
RET ;Return to protocol
;
; Check received packet number against previous
;
CHKBLKDEC EQU $
LD A,(PKTNUM) ;Get the current packet number
DEC A ;Minus one for previous
JR CHKBLK_1 ;Join other code
;
; Check the current packet number against that received
;
CHKBLK EQU $
LD A,(PKTNUM) ;Get the current number
CHKBLK_1 LD B,A ;Copy it to B
LD A,(ARGBLK) ;Get the received packet number
CP B ;Are they the same
RET ;Return the condition codes
;
; Check for too many retries based on previous knowledge
;
CHKOLD EQU $
LD A,(MAXTRY) ;Get the max number of tries
LD B,A ;Save it
LD A,(OLDTRY) ;Check against old max
CP B ;Set the condition bits
JR C,CHKOLD1 ;Jump if less than
POP DE ;Remove the return address
LD DE,ERMS10 ;Get the message
CALL ERROR3 ;Display the error message
JP RECABORT ;Change the state to abort
CHKOLD1 INC A ;Increment the number of tries
LD (OLDTRY),A ;Save the updated number of tries.
RET ;Return normally
;
; Set up for a REMOTE command. The RFILE FCB is pointed at
; the *SO device, so that data received goes to the screen,
; rather than to a file.
;
SETUPDIS EQU $
LD DE,(TMODCB) ;Get the current output DCB address
LD (RFIDCB),DE ;Make it the current received file output
XOR A ;Reset the 'display' flag
LD (DISFLG),A
CALL NEWLIN ;Get a fresh line
RET ;Return to caller
;
; Conditionally display the string pointed to by DE based on the
; DISFLG which is active only during non REMOTE transactions. This
; makes REMOTE command pleasingly silent so that only the output
; of the requested operation is seen.
;
CONDIS EQU $
PUSH AF ;Save A and the flags
LD A,(DISFLG) ;Get the 'display' flag
OR A ;Is it set?
CALL NZ,PRTSTR ;If so, then print the string
POP AF ;Restore the flags and A
RET ;Return to caller
;
; Print the contents of the PACKET data area to the
; screen.
;
PRTPKTOUT EQU $
LD HL,DATA ;Get the start of the string
LD A,(ARGBLK+1) ;Get the length
OR A
RET Z ;Return if no data
LD C,A ;Get the LSB into C
LD B,0 ;Make BC a 16 bit offset
ADD HL,BC ;HL is now the address past the end
LD (HL),EOS ;Terminator for printing
STROUT DATA
JP NEWLIN ;Print a new line and return
;
; Update byte counters, IX MUST point to send or receive
; counter. We mod HL with 1K to get the remainder, and use
; the rest to sum into the current total. The remainder of
; HL mod 1024 is tucked away, but not forgotten.
;
UPDTRANS EQU $
LD HL,(KTRANS) ;Calculate new total transfered
LD C,(IX+2) ;Get the overflow counter
LD B,(IX+3)
ADD HL,BC ;Compute the total
XOR A ;Reset the falg
CALL C,ADD64K ;Add 64k if addition overflows
LD A,H ;Get the high byte
AND 3 ;Save the 2 lower order bits for mod 1024
LD B,A ;Put them in B
LD C,L ;Put the other 8 bits into C
LD (IX+2),C ;Store the new overflow (HL mod 1024)
LD (IX+3),B
LD A,H ;Trim to 1K multiple
AND 0FCH ;A is now 4 times the number of Kbytes
LD L,A ;Put it into L
LD H,0 ;Make H zero
SRL L ;Divide by 4 to align
SRL L
LD C,(IX) ;Get the total so far
LD B,(IX+1)
ADD HL,BC ;Compute the new total Kbyte
LD (IX),L ;Put it back
LD (IX+1),H ;ignoring any overflow
CALL TRANSCNT ;Log the transaction size if logging
LD HL,0 ;Set the counter to zero
LD (KTRANS),HL
LD (CURTRANS),HL ;Reset current counters
LD (CURTRANS+2),HL
RET ;Return to the caller
;
; Log the size of the last transaction to the logfile
;
TRANSCNT EQU $
PUSH AF ;Save A and the FLAGS
LD A,(TRANLOG) ;Is tranaction logging in progress?
IFZ TRANSC_10 ;Jump if not active
PUSH HL
PUSH DE
PUSH BC
LD HL,(CURTRANS+2) ;Get the number of K transfered
LD A,H
OR L ;Is it zero?
JR Z,TRANSC_3 ;Jump if it is
CALL NUM2BUFF ;Put the number in the buffer
LD DE,TRFCB ;Get the FCB address
CALL OUTLOG ;Log the number of K transfered
JP TRANSC_20 ;Close up on an error
TRLOG KPLUS,TRANSC_20 ;Log the 'K + ' string
TRANSC_3 EQU $
LD HL,(CURTRANS) ;Get the value
CALL NUM2BUFF ;Make it printable
LD DE,TRFCB ;Get the output FCB
CALL OUTLOG ;Log the number of left over bytes
JP TRANSC_20 ;Close up on an error
TRLOG BYTESMES,TRANSC_20;Log the 'bytes transferred' message
TRLOG TIMEMES,TRANSC_20; Log the time message
CALL PRTTIME ;Print the current time
TRANSC_9 EQU $
POP BC ;Restore the registers
POP DE
POP HL
TRANSC_10 EQU $
POP AF ;Restore A and flags
RET ;Return to caller
TRANSC_20 EQU $
LD DE,TRFCB
CALL XCLOSE
XOR A
LD (TRANLOG),A
JP TRANSC_9
;
; Convert binary to ascii, NO leading spaces
;
NUM2BUFF EQU $
PUSH DE ;Save DE
PUSH BC ;and BC
LD DE,NBUFF ;Get the data buffer
PUSH DE ;Save it for later
CALL XHEXDEC
EX DE,HL
LD (HL),EOS ;Terminate the buffer
POP HL ;Get the start back
LD A,' ' ;Character to skip over
N2B_1 EQU $
IFANOT (HL),N2B_2 ;Jump if passed last
INC HL ;Point to next
JR N2B_1 ;Back to test
N2B_2 EQU $
POP BC ;Restore the registers
POP DE
RET ;Return to caller
;end of file
<<< m4h191.asm >>>
; M4H191/ASM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Heath 19 terminal emulation filter
;
; Written By: Gregg Wonderly
;
; This program functions as a TRSDOS 6.2 device filter to emulate
; the h19 terminal. It recognizes most of the features of the
; H19 that are reasonable to implement on the Model 4. The items
; missing are ALT character set, and some of the <ESC>[xy]n
; sequences.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; This filter relocates itself to HIGH memory.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
ORG 3000H
TAB EQU 9 ;Tab character code
ESC EQU 27 ;Tab character code
S_OUT EQU 1 ;Screen on mask
S_IN EQU 0FEH ;Screen off mask
R_ON EQU 8 ;Reverse video on mask
R_OFF EQU 0F7H ;Reverse video off mask
FLAGVAL EQU 17 ;Flags offset from MODDCB
SCR_MASK EQU 14 ;Offset of screen mask in flags
WRINTMASK EQU 22 ;Interrupts mask in FLAGS
BITOFFSET EQU 29
;
*GET M4H19/EQU ;Get the SVC equates
*GET M4H19/MAC ;Get the macros
;
; The system enters the driver here with each character
;
FILTER JR H19EMULATOR ;Go to the start of the driver
DW 0 ;End of module address goes here
DB 6 ;Length of the module name
DB '$HEATH' ;The name
MODDCB DW 0 ;To be filled in later
DW 0 ;Filler
VSCUR DB 95 ;Block cursor character
VECUR DB 95 ;Underscore cursor character
DEF_LEN DB 20 ;Default duration for the bell
BELLFLAG DB 0 ;Visual or audible bell
DEF_FREQ DW 125 ;Default frequency for bell tone
OLDLOW DW 0 ;The address to restore if we
; remove ourselves
OLDHIGH DW 0 ;This is where we are loaded at
WHERE_AT DB 0 ;Flag for high or low mem load
OFFSET DW 0 ;Offset from load to destination
FVAL DB 0 ;No flags to start with
BITVAL DW BITMASK ;Offset to 7-bit mask
;
; Start of actual Filter
;
H19EMULATOR JR Z,ISPUT ;Go to process @PUT requests
JP CHAIN_2 ;Ignore other options
R002 EQU $-2
;
; Do only @PUT requests
;
ISPUT EQU $
LD A,@FLAGS ;Get the flags address into IY
RST 28H
LD A,C ;Character is in A and C now
AND 07FH ;Strip any 8th bit if STRIP8 set
BITMASK EQU $-FILTER-1
LD C,A
LD (NEWCHAR),A ;Save the character to display
R003 EQU $-2
LD HL,(OLDSTATE) ;Get any preexisting state
R004 EQU $-2
LD A,H ;Check for on, NZ means yes
OR L
JR Z,NOSTATE ;Go if no state
PUSH HL ;Put the address on the stack
LD HL,0 ;Wipe out the state value
LD (OLDSTATE),HL ;by storing zero in it
R005 EQU $-2
RET ;Go to the address on the stack
;
; Look for what we should do with the character...
;
NOSTATE LD A,C ;Get the character
CP ESC ;Is it the escape character?
JP Z,DOESCAPE ;Go do it if so
R006 EQU $-2
CP ' ' ;Check for a Control Character
JP C,DOCONTROL ;Go do it if so
R007 EQU $-2
CALL INSERT_A ;Put the character on the screen
R008 EQU $-2
JP RETOUT ;Return to caller
R009 EQU $-2
;
; Process all of the control characters between 0-31 inclusive
;
DOCONTROL EQU $
LD A,(NEWCHAR) ;Get the character
R010 EQU $-2
ADD A,A ;Times 2 for word offset
LD C,A ;Get a copy of A for the offset
LD B,0 ;Make BC a 16 bit offset
LD HL,CTL_JMP_TBL ;Get the jump table
R011 EQU $-2
ADD HL,BC ;Get the address in the table
LD E,(HL) ;Get LSB of the address
INC HL ;Point at next byte of address
LD D,(HL) ;Get the MSB
EX DE,HL ;Swap the jump address into HL
LD A,H ;Is there a special routine?
OR L ;Set the flags
LD A,(NEWCHAR) ;Get the character back
R012 EQU $-2
JP Z,RETOUT ;If not recognized, throw it out.
R013 EQU $-2
JP (HL) ;Go to the special routine
;
; Control character jump table. Each word is the address of a
; routine that processes the specfic character.
;
CTL_JMP_TBL DW 0,0,0,0,0,0,0 ;Throw these out.
DW SET_BELL ;Start the buzzer.
R014 EQU $-2
DW BACK_SPACE ;Backup a character NON-destruct.
R015 EQU $-2
DW SHOW_TAB ;Skip a physical tab.
R016 EQU $-2
DW LINE_FEED ;Down one line.
R017 EQU $-2
DW 0 ;Throw this one out.
DW FORM_FEED ;Clear the screen on FF.
R018 EQU $-2
DW CARRIAGE ;Carriage return.
R019 EQU $-2
DW 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;Not used.
;
SET_BELL LD A,(BELLFLAG) ;Is the bell function valid?
R020 EQU $-2
OR A
JP Z,FLASH_SCREEN ;Flash if signaled
R021 EQU $-2
LD A,(DEF_LEN) ;This is the timer value.
R022 EQU $-2
LD L,A
LD DE,(DEF_FREQ)
R023 EQU $-2
BELL01 EQU $
LD A,1
OUT (90H),A
LD B,D
LD C,E
BELL02 EQU $
DEC BC
LD A,B
OR C
JR NZ,BELL02
XOR A
OUT (90H),A
LD B,D
LD C,E
BELL03 EQU $
DEC BC
LD A,B
OR C
JR NZ,BELL03
DEC L
JR NZ,BELL01
JP RETOUT ;Exit without chaining
R024 EQU $-2
;
BACK_SPACE EQU $
LD A,24 ;Non-destructive backspace
JP STORE_CHAIN ;Chain into any filters
R025 EQU $-2
;
SHOW_TAB EQU $
GET_CURSOR ;Get the cursor position
LD A,79 ;Last column to display in
SUB L ;Compute the difference
CP 8 ;Do we have enough?
JP NC,TABOK ;If at least 8 then go do it
R026 EQU $-2
LD A,29 ;Send simulated <CR><LF> to *DO
CALL CHAIN_IN
R028 EQU $-2
LD A,26
JP CHAIN_IN ;No return
R029 EQU $-2
TABOK EQU $
LD A,L ;Must truncate to even 8 chars
ADD A,8
AND 0F8H
LD L,A ;Get the column back into L
NOSCROLL EQU $
PUT_CURSOR ;Set the cursor to what is in HL
JP RETOUT ;Return
R030 EQU $-2
;
LINE_FEED EQU $
LD A,26 ;Non-destructive LF
CALL STORE_CHAIN ;Chain into any filters
R031 EQU $-2
LD A,(FVAL)
R131 EQU $-2
AND 2 ;Check for auto CR
LD A,29 ;Get a CR
CALL NZ,STORE_CHAIN
R177 EQU $-2
JP RETOUT ;Return
R178 EQU $-2
;
FORM_FEED EQU $
LD HL,0 ;Set the cursor to 0,0
PUT_CURSOR
JP CLEAR_TO_EOS ;Do a clear to end of screen
R032 EQU $-2
;
MOVE_HOME EQU $
LD HL,0 ;Get Row=0, Column=0
STORE_ROW_COL EQU $
PUT_CURSOR ;Move the cursor to the pos in HL
JP RETOUT ;Return
R033 EQU $-2
;
CARRIAGE EQU $
LD A,29 ;True carriage return
CALL STORE_CHAIN
R034 EQU $-2
LD A,(FVAL)
R174 EQU $-2
AND 1
LD A,26 ;Get a line_feed
CALL NZ,STORE_CHAIN ;Display it conditionally
R175 EQU $-2
JP RETOUT
R176 EQU $-2
;
; Process the ESCAPE character sequences
;
DOESCAPE EQU $
LD HL,ESCAPE_1 ;Set the next state to go to
R035 EQU $-2
LD (OLDSTATE),HL
R036 EQU $-2
JP RETOUT ;Leave with no chain
R037 EQU $-2
;
; Escape has been seen, now check for a special character
;
ESCAPE_CHARS DB 'ABCDEFGHIJKLMNOY@fqpxyjkbol'
ESC_LEN EQU $-ESCAPE_CHARS
;
ESCAPE_1 EQU $
LD A,(NEWCHAR) ;Get the character sent
R038 EQU $-2
LD HL,ESCAPE_CHARS ;Get the list of valid ones
R039 EQU $-2
LD B,ESC_LEN ;Get how many
LD DE,ESC_1_JMPS ;Get the vector table
R040 EQU $-2
ESC_1_LOOP LD C,(HL) ;Get a character
CP C ;Is it a match?
JR Z,ESC_1_FND ;Found it, so go
INC HL ;Next character
INC DE ;next jump table entry
INC DE
DJNZ ESC_1_LOOP ;Loop while still more
LD HL,0
LD (OLDSTATE),HL
R041 EQU $-2
JP RETOUT ;Ignore unimplemented or invalid codes
R042 EQU $-2
;
ESC_1_FND EQU $
EX DE,HL ;Get the vector's address
LD E,(HL) ;Get the table value
INC HL
LD D,(HL)
LD HL,0 ;Reset the state
LD (OLDSTATE),HL
R043 EQU $-2
EX DE,HL ;Get the vector in HL
LD A,(NEWCHAR)
R044 EQU $-2
JP (HL) ;Go do the right thing.
;
; Level 1 escape vector table
;
ESC_1_JMPS DW CURSOR_UP
R045 EQU $-2
DW LINE_FEED
R046 EQU $-2
DW CURSOR_RIGHT
R047 EQU $-2
DW BACK_SPACE
R048 EQU $-2
DW FORM_FEED
R049 EQU $-2
DW START_ALT_SET
R050 EQU $-2
DW END_ALT_SET
R051 EQU $-2
DW MOVE_HOME
R052 EQU $-2
DW REV_INDEX
R053 EQU $-2
DW CLEAR_TO_EOS
R054 EQU $-2
DW CLEAR_TO_EOL
R055 EQU $-2
DW ADD_LINE
R056 EQU $-2
DW DEL_LINE
R057 EQU $-2
DW DEL_CHAR
R058 EQU $-2
DW END_INSERT
R059 EQU $-2
DW SET_ESC_2
R060 EQU $-2
DW BEGIN_INSERT
R061 EQU $-2
DW FLASH_SCREEN
R062 EQU $-2
DW STAND_END
R063 EQU $-2
DW STAND_OUT
R064 EQU $-2
DW SET_ESC_2
R065 EQU $-2
DW SET_ESC_2
R066 EQU $-2
DW SAVE_CURSOR
R001 EQU $-2
DW RESTORE_CURSOR
R027 EQU $-2
DW ERA_BEG_SCR
R141 EQU $-2
DW ERA_BEG_LIN
R142 EQU $-2
DW ERASE_LINE
R143 EQU $-2
;
; Move the cursor up one line if possible, stopping at the top
; of the screen.
;
CURSOR_UP EQU $
LD A,27 ;Non-destructive cursor up
STORE_CHAIN EQU $
LD (NEWCHAR),A ;Store it
R067 EQU $-2
JP CHAIN ;Let *DO do the dirty work
R068 EQU $-2
;
CURSOR_RIGHT EQU $
LD A,25 ;Non-destructive cursor right
JP STORE_CHAIN ;Let *DO do it for us
R069 EQU $-2
;
START_ALT_SET JP RETOUT ;No defined action
R070 EQU $-2
;
END_ALT_SET JP RETOUT ;No defined action
R071 EQU $-2
;
; This is the reverse scroll. We use direct screen access to
; move one line. Interrupts are off during the move, but are
; restored between each line. There seems to be quite reasonable
; behavior at 9600 baud with this strategy.
;
REV_INDEX EQU $
GET_CURSOR ;Make sure we are at the top
LD A,H ;Get the cursor row
OR A ;Is it row zero?
JP NZ,CURSOR_UP ;Go if not, to Cursor up routine
R072 EQU $-2
LD A,15 ;Remove the cursor
CALL CHAIN_IN
R127 EQU $-2
LD A,23 ;Move 23 lines down
LD HL,23*80+0F7FFH ;Get the next to last line, last byte
LD DE,24*80+0F7FFH ;Get the last byte on the screen
REV_LOOP LD BC,80 ;Get the byte count
PUSH AF ;Save the line count
SWAP_IN ;Screen in, interrupts off
LDDR ;Move a line
SWAP_OUT ;Screen out, interrupts on
POP AF ;Get line count
DEC A ;One less to move
JR NZ,REV_LOOP ;Loop if not done
REV_DONE EQU $
LD DE,SCR_BUFF ;Get the buffer address
R073 EQU $-2
PUSH DE ;Save it
PUSH DE ;Copy it into HL
POP HL
INC DE ;Point one ahead for the copy
LD (HL),' ' ;Store one blank
LD BC,79 ;Copy it into the remaining 79
LDIR ;Do the copy
LD H,0 ;Get the top row
POP DE ;Get the buffer address back
PUT_LINE ;Put a blank line there
LD A,14 ;Turn the cursor back on
JP CHAIN_IN
R074 EQU $-2
;
; Flash the screen, by inverting all of the msb's of the characters
; twice. The result is a fair approximation to a flash.
;
FLASH_SCREEN EQU $
LD A,16 ;Turn reverse video on
CALL CHAIN_IN
R128 EQU $-2
LD C,0 ;Get the loop counter
FLASH_LOOP_1 EQU $
PUSH BC ;Save it
LD H,0 ;Get the first line
FLASH_LOOP_2 EQU $
LD DE,SCR_BUFF ;Get the buffer to put it in
R075 EQU $-2
GET_LINE ;Get the line from @VDCTL
PUSH HL ;Save the line number for PUT_LINE
LD H,D ;Copy DE into HL
LD L,E
LD B,80 ;Get the BYTE count
FLASH_LOOP_3 EQU $
LD A,(HL) ;Get a BYTE
XOR 080H ;Invert the HIGH BIT
LD (HL),A ;Put it back
INC HL ;Point to the next
DJNZ FLASH_LOOP_3 ;Loop until line is done
POP HL ;Restore the Line number
PUT_LINE ;Put the line back
INC H ;Point to next line
LD A,H ;Test for last
CP 24 ;END?
JR NZ,FLASH_LOOP_2 ;Loop if not done
EI ;Make sure interrupts are back on
POP BC ;Restore the FLASH counter
LD A,C ;Get the original value
INC C ;Increment the counter
OR A ;Test OLD value
JR Z,FLASH_LOOP_1 ;Loop if just finished first time
LD A,17 ;Set reverse video OFF
JP STORE_CHAIN ;Chain to *DO
R076 EQU $-2
;
; Save the current cursor position
;
SAVE_CURSOR EQU $
LD DE,(LASTPUSH) ;Get the nextplace available
R132 EQU $-2
GET_CURSOR ;Get the cursor
EX DE,HL ;Swap push address for screen pos
PUSH HL ;Save push address
LD BC,ENDPUSH ;Get the first illeagal address
R133 EQU $-2
OR A ;Reset the carry
SBC HL,BC ;Compute difference
POP HL ;Restore real address
JR Z,NO_SAVE ;Jump if can't save
LD (HL),E ;Put in column
INC HL ;Point to next pos
LD (HL),D ;Put in the row
INC HL ;Point past it to next position
LD (LASTPUSH),HL ;Save the new address
R134 EQU $-2
NO_SAVE EQU $
JP RETOUT
R135 EQU $-2
;
; Restore the previously pushed cursor position.
;
RESTORE_CURSOR EQU $
LD HL,(LASTPUSH) ;Get the next store position
R136 EQU $-2
LD BC,PUSHAREA ;Get the start of the area
R137 EQU $-2
OR A ;Reset carry
PUSH HL ;Save the address
SBC HL,BC ;See if anything to pop
POP HL
JR Z,NO_RESTORE ;Jump if not
DEC HL ;Point back to row
LD D,(HL) ;Get it
DEC HL ;Point back to column
LD E,(HL) ;Get it
LD (LASTPUSH),HL ;Save the next position
R138 EQU $-2
EX DE,HL ;Put the Row/Column into HL
PUT_CURSOR ;Set the cursor position
NO_RESTORE EQU $
JP RETOUT ;Return without calling *DO
R139 EQU $-2
;
; Erase the current line
;
ERASE_LINE EQU $
GET_CURSOR ;Get the current position
PUSH HL ;Save it
LD L,0 ;Move to beginning of line
PUT_CURSOR ;Store the new cursor position
CALL CLEAR_TO_EOL
R144 EQU $-2
POP HL
PUT_CURSOR
JP RETOUT
R145 EQU $-2
;
; Erase to beginning of screen
;
ERA_BEG_SCR EQU $
GET_CURSOR ;Get the current screen position
CALL GET_RC_ADDR ;Convert it to a memory address
R146 EQU $-2
LD DE,0F800H ;Get the start of the screen
OR A ;Reset the carry
SBC HL,DE ;Compute number to blank
LD B,H ;Put the count into BC
LD C,L
LD A,B ;See if at start of screen
OR C
JR Z,NO_ERA_SCR ;Jump if so, nothing to erase
LD HL,0F800H ;Get the start
LD DE,0F801H ;Get the start + 1
SWAP_IN ;Make the screen visible
LD (HL),20H ;Blank one position
SWAP_OUT ;Swap the screen back out
DEC BC ;Decrement remaining places
LD A,B ;See if only one needed blanking
OR C
JR Z,NO_ERA_SCR ;Jump it that was all
SWAP_IN ;Swap the screen back in
LDIR ;Blank the characters
SWAP_OUT ;Swap the screen back out
NO_ERA_SCR EQU $
JP RETOUT ;Return without chaining
R147 EQU $-2
;
; Clear to the beginning of the line
;
ERA_BEG_LIN EQU $
GET_CURSOR ;Get current position
PUSH HL ;Save it
CALL GET_RC_ADDR ;Convert to memory address
R148 EQU $-2
EX DE,HL ;Swap current to DE
POP HL ;Get the row/column back
LD L,0 ;Set row to start of screen
CALL GET_RC_ADDR ;Get the address there
R149 EQU $-2
EX DE,HL ;Swap it back
OR A ;Reset the carry
PUSH DE ;Save starting address
SBC HL,DE ;Compute length
LD B,H ;Put it into BC
LD C,L
LD A,B ;Check if no characters
OR C
JR Z,NO_ERA_LIN ;Jump if at start of line
POP HL ;Get start of line address back
LD D,H ;Make DE=HL+1
LD E,L
INC DE
SWAP_IN ;Swap the screen in
LD (HL),20H ;Store a space
SWAP_OUT ;Swap the screen out
DEC BC ;Decrement the count for prev inst
LD A,B ;Check for zero
OR C ;Set the flags
JR Z,NO_ERA_LIN
SWAP_IN ;Fold the screen into memory
LDIR ;Blank the screen
SWAP_OUT ;Swap the screen back out
NO_ERA_LIN EQU $
JP RETOUT ;Return to caller
R150 EQU $-2
*GET M4H192/ASM
END LOAD
<<< m4h192.asm >>>
; M4H192/ASM
CLEAR_TO_EOS EQU $
GET_CURSOR ;Get the cursor position
CALL GET_RC_ADDR ;Get the real address
R077 EQU $-2
PUSH HL ;Save the start for LDIR
PUSH HL ;Copy it to BC
POP BC
LD HL,24*80+0F7FFH ;Get the last place to blank
CLEAR_SPACE EQU $
OR A ;Reset the carry
SBC HL,BC ;HL is now length of area
PUSH HL ;Put it into BC and clear stack
POP BC
POP HL ;Get the starting address
JR Z,NO_CLEAR ;Jump if no count
PUSH HL ;Copy to DE
POP DE
INC DE ;Point DE one ahead
PUSH BC ;Hide the cursor before
PUSH DE
PUSH HL
LD A,15 ;Use *DO for this
CALL CHAIN_IN
R190 EQU $-2
POP HL ;Restore the stack
POP DE
POP BC
SWAP_IN ;Swap screen into RAM
LD (HL),' ' ;Store one blank
SWAP_OUT
CLR_LOOP LD A,30 ;One line max
SWAP_IN ;Screen in
LINE_LOOP PUSH AF ;Save the max counter
LD A,B ;Check if done with all bytes
OR C
JR Z,END_CLEAR ;If done, exit
POP AF ;Get the max count back
LDI ;Blank one byte
DEC A ;Decrement the max count
JR NZ,LINE_LOOP ;If not done, do it again
SWAP_OUT ;Swap the video out, and enable
JR CLR_LOOP ;interrupts again, and loop.
;
END_CLEAR POP AF ;Fix the stack
SWAP_OUT ;Swap the video back out
LD A,14 ;Turn the cursor back on
JP CHAIN_IN
R078 EQU $-2
NO_CLEAR EQU $
JP RETOUT
R191 EQU $-2
;
CLEAR_TO_EOL EQU $
GET_CURSOR ;Get the cursor ROW/COL
PUSH HL ;Save it
CALL GET_RC_ADDR ;Get the ADDRESS equivilent
R188 EQU $-2
EX (SP),HL ;Exchange for ROW/COL
LD L,79 ;Point to end of this line
CALL GET_RC_ADDR ;Get the RAM address
R189 EQU $-2
POP BC ;Restore the beginning
PUSH BC ;Save it
LD A,C ;If C = L then at EOL
CP L
JR Z,NO_CLEAR ;So skip rest of operations
JR CLEAR_SPACE
;
DEL_CHAR EQU $
LD DE,SCR_BUFF ;Get the buffer address
R079 EQU $-2
PUSH DE ;Save it for the store
GET_CURSOR ;Get the row to retrieve
PUSH HL ;Save the column for later store
GET_LINE ;Get the line into the buffer
LD A,79 ;Maximum characters to move
SUB L ;Subtract the current position
LD H,0 ;Set the column to zero
ADD HL,DE ;HL is now the place to start at
PUSH HL ;Get a copy in de
POP DE
OR A
JR Z,NO_D_CHAR
LD C,A ;Get the count in BC as 16 bits
LD B,0
INC HL ;Move the source one forward
LDIR ;Skoot it all backwards
NO_D_CHAR EQU $
LD A,' ' ;Get a space character
LD (DE),A ;Blank the last space on the line
POP HL ;Get the row to store at
POP DE ;Get the buffer address back
PUT_LINE ;Put the line back on the screen
JP RETOUT
R080 EQU $-2
;
END_INSERT EQU $
XOR A
LD (INSERT_FLAG),A ;End insert mode
R081 EQU $-2
JP RETOUT
R082 EQU $-2
;
BEGIN_INSERT LD A,1
LD (INSERT_FLAG),A ;Begin insert mode
R083 EQU $-2
JP RETOUT
R084 EQU $-2
;
STAND_END EQU $
LD A,17 ;End standout mode
JP STORE_CHAIN
R085 EQU $-2
;
STAND_OUT EQU $
LD A,16
JP STORE_CHAIN ;Begin standout mode
R086 EQU $-2
;
; At this point, there are still more characters to distinguish
; between sequences. So we set the next state to go to
;
SET_ESC_2 EQU $
LD HL,ESCAPE_2 ;Get address of the next state
R087 EQU $-2
LD (OLDSTATE),HL ;Save it
R088 EQU $-2
LD A,(NEWCHAR) ;Get the character sent this time
R089 EQU $-2
LD (CHAR_2),A ;Save the character
R090 EQU $-2
JP RETOUT ;Skip the *do device and return
R091 EQU $-2
;
; Jump table for processing ESC-y-[123456789] and ESC-x-[123456789]
; sequences
;
MODE_TABLE EQU $
DW ENABLE_25TH
R153 EQU $-2
DW NO_KEY_CLICK
R154 EQU $-2
DW HOLD_SCREEN
R155 EQU $-2
DW BLOCK_CURSOR
R156 EQU $-2
DW CURSOR_OFF
R157 EQU $-2
DW KEYPAD_SHIFTED
R158 EQU $-2
DW ALT_KEY_MODE
R159 EQU $-2
DW AUTO_LF
R160 EQU $-2
DW AUTO_CR
R161 EQU $-2
DW DISABLE_25TH
R162 EQU $-2
DW KEY_CLICK
R163 EQU $-2
DW NO_HOLD_SCREEN
R164 EQU $-2
DW LINE_CURSOR
R165 EQU $-2
DW CURSOR_ON
R166 EQU $-2
DW KEY_UNSHIFT
R167 EQU $-2
DW EXIT_ALT_KEY
R168 EQU $-2
DW NO_AUTO_LF
R169 EQU $-2
DW NO_AUTO_CR
R170 EQU $-2
;
; Process third character in 3 character or more sequence
;
ESCAPE_2 EQU $
LD A,(CHAR_2) ;Get the previous character
R092 EQU $-2
CP 'x' ;Was it options on
JR Z,OPTION_X ;Yep, go do it
CP 'y' ;Was it options off?
JR NZ,MOVE_CURSOR ;Jump if not
LD C,18 ;Get the offset
JR OPTIONS ;Join other code
OPTION_X EQU $
LD C,0 ;Get offset at zero
OPTIONS EQU $
LD A,(NEWCHAR) ;Get the character
R130 EQU $-2
SUB '1' ;Zero base it
CP 9 ;Check for too big
JP NC,RETOUT ;Can't do this one
R187 EQU $-2
CP 0
JP C,RETOUT
R171 EQU $-2
SLA A ;Multiply by 2
ADD A,C ;Tack on offset
LD C,A ;Make BC a 16 bit offset
LD B,0
LD HL,MODE_TABLE ;Get the table
R172 EQU $-2
ADD HL,BC
LD E,(HL) ;Get the low order byte
INC HL ;Point to MSB
LD D,(HL) ;Get the MSB
PUSH DE ;Put it on the stack
RET ;Jump to it
;
; All of the following options are not implemented, so they are
; ignored
;
ENABLE_25TH:
NO_KEY_CLICK:
HOLD_SCREEN:
KEYPAD_SHIFTED:
ALT_KEY_MODE:
DISABLE_25TH:
KEY_CLICK:
NO_HOLD_SCREEN:
EXIT_ALT_KEY:
KEY_UNSHIFT:
GOOUT EQU $
JP RETOUT
R173 EQU $-2
;
AUTO_LF EQU $
LD A,(FVAL)
R179 EQU $-2
OR 1
LD (FVAL),A
R180 EQU $-2
JR GOOUT
;
AUTO_CR EQU $
LD A,(FVAL)
R181 EQU $-2
OR 2
LD (FVAL),A
R182 EQU $-2
JR GOOUT
;
NO_AUTO_LF EQU $
LD A,(FVAL)
R183 EQU $-2
AND 0FEH
LD (FVAL),A
R184 EQU $-2
JR GOOUT
;
NO_AUTO_CR EQU $
LD A,(FVAL)
R185 EQU $-2
AND 0FDH
LD (FVAL),A
R186 EQU $-2
JR GOOUT
;
BLOCK_CURSOR EQU $
LD HL,(VIDEO_START);Get the call out vector
R093 EQU $-2
CHECK_JUMP LD A,H ;Check for valid
OR L
JP Z,RETOUT ;Jump if no address specified
R094 EQU $-2
LD DE,RETOUT ;Push the return address
R095 EQU $-2
PUSH DE
JP (HL) ;Call the users routine
CURSOR_ON EQU $
LD A,15 ;Cursor on to *DO
JP STORE_CHAIN
R151 EQU $-2
;
LINE_CURSOR EQU $
LD HL,(VIDEO_END) ;Get the vector
R096 EQU $-2
JR CHECK_JUMP
;
CURSOR_OFF EQU $
LD A,14
JP STORE_CHAIN
R152 EQU $-2
;
MOVE_CURSOR EQU $
LD A,(NEWCHAR)
R097 EQU $-2
SUB ' ' ;This should be the row
JP C,RETOUT ;Abort if bad row
R098 EQU $-2
CP 24 ;check for too big
JP NC,RETOUT ;Abort on bad here too
R099 EQU $-2
LD (GOTO_ROW),A ;Save the row
R100 EQU $-2
;
; Now we must wait for the column to get here, so set the state,
;
LD HL,ESCAPE_3 ;Set the state for column
R101 EQU $-2
LD (OLDSTATE),HL ;Store it
R102 EQU $-2
CONTINUE EQU $
JP RETOUT ;Chain into any filters
R103 EQU $-2
;
; At this point, we are looking for the column of a cursor
; motion sequence. This is the longest sequence
;
ESCAPE_3 LD A,(NEWCHAR) ;Get the character
R104 EQU $-2
SUB ' ' ;Get rid of the bias
JP C,RETOUT ;Abort if bad column
R105 EQU $-2
CP 80 ;Check for too high
JP NC,RETOUT ;Exit if over
R106 EQU $-2
LD L,A ;Get the column in L
LD A,(GOTO_ROW) ;Get the ROW from the save area
R107 EQU $-2
LD H,A ;Put it in HL for PUT_CURSOR
PUT_CURSOR ;Set the new cursor position
JP RETOUT ;Return
R108 EQU $-2
;
DEL_LINE LD A,1 ;Set the delete line flag
JR LINE_OPS
;
ADD_LINE XOR A ;Clear the flag
;
; The following code is somewhat shared by the INSERT and DELETE
; line code. This code accesses the video memory directly to get
; the fastest possible movement. Interrupts must be off while
; the screen is swapped in, so a compromise was made so that the
; interrupts were not off for too long. The movement of the
; screen is done one line at a time. Interrupts are turned back
; on in between lines, so that the UART can generate RECEIVED
; CHARACTER AVAILABLE interrupts. I have had reasonable behavior
; at 9600 BAUD with this idea...
;
LINE_OPS LD (DEL_FLAG),A ;Store the flag value
R109 EQU $-2
GET_CURSOR ;Get the current row and column
LD A,23 ;Get the maximum possible
SUB H ;Get the difference in rows
JR Z,CLEAR_LINE ;Go clear the line if on the last
PUSH IY
PUSH HL ;Save HL from the call to *DO
PUSH BC
PUSH DE
PUSH AF
LD A,15 ;Turn the cursor off
CALL CHAIN_IN ;Call *DO to do the work
R129 EQU $-2
POP AF
POP DE
POP BC
POP HL ;Restore the ROW/COL
POP IY
LD A,(DEL_FLAG) ;Get the flag
R110 EQU $-2
OR A
JR Z,INS_MODE
;
; Delete the line that the cursor is on
;
PUSH HL ;Save the row and column
LD L,0 ;Go to the first col of the line
CALL GET_RC_ADDR ;Get the effective address in mem
R111 EQU $-2
POP AF ;Get the row in A, ignoring F
PUSH HL ;Move the address to DE
POP DE
LD BC,80 ;One row is this many characters
ADD HL,BC ;Add one row to HL for the source
DEL_LOOP EQU $
SWAP_IN ;Swap the screen into view
PUSH BC
LDIR ;Move one rows worth
POP BC
SWAP_OUT ;Swap the screen back out
INC A ;Add one to the row
CP 23 ;Are we at the end?
JR NZ,DEL_LOOP ;Loop if not
LD H,A ;Load H with the last row
JR LINE_OPS_1 ;Join the other code
;
INS_MODE EQU $
LD A,23 ;Max lines on a screen
SUB H ;Minus current line = remaining
LD HL,23*80+0F7FFH ;Source address for LDDR
LD DE,24*80+0F7FFH ;Destination address for LDDR
LD BC,80 ;Number of bytes to move
INS_LOOP EQU $
SWAP_IN ;Swap the screen in
PUSH BC
LDDR ;Move one line
POP BC
SWAP_OUT ;Swap the screen out
DEC A ;Decrement the line count
JR NZ,INS_LOOP ;Loop until done
CLEAR_LINE EQU $
GET_CURSOR ;Get the current row
LINE_OPS_1 EQU $
PUSH HL ;Save the row
LD DE,SCR_BUFF ;Get the buffer address
R112 EQU $-2
PUSH DE ;Save the buffer address
PUSH DE ;Copy the address into hl
POP HL
INC DE ;Plus one for the copy
LD BC,79 ;Copy 79 times
LD (HL),' ' ;Store one blank
LDIR ;Copy in the rest
POP DE ;Restore the buffer address
POP HL ;Restore the row
PUT_LINE ;Put the line back
LD A,14 ;Turn the cursor back on
JP CHAIN_IN
R113 EQU $-2
;
; Chain into any filters
;
CHAIN EQU $
LD A,(NEWCHAR) ;Get the character sent to us
R114 EQU $-2
CHAIN_IN EQU $
LD C,A ;Move the character to C for @PUT
LD B,2 ;Signal @PUT for others in chain
OR A ;Reset the carry
CP A ;Set Z flag
CHAIN_2 EQU $
PUSH IX ;Save the old DCB address
LD IX,(MODDCB) ;Get the next in chain
R115 EQU $-2
LD A,@CHNIO
RST 28H
POP IX ;Restore the old
;
; Return without knowldege of the call to *DO
;
RETOUT EQU $
LD A,(NEWCHAR) ;Get the character sent
R125 EQU $-2
CP A ;Set the Z flag
RET
;
; Clear the screen
;
CLEAR_SCREEN EQU $
LD HL,0 ;Put the cursor at the top
PUT_CURSOR
JP CLEAR_TO_EOS
R126 EQU $-2
;
; Put the character in A on the screen at the current screen
; position. If insert mode is active, then perform the shift
; of the line before chaining to *DO which will do the actual
; displaying for us.
;
INSERT_A EQU $
PUSH AF ;Save the character
GET_CURSOR ;Get the cursor position
PUSH HL ;Save the cursor position
LD A,(INSERT_FLAG) ;Get the insert mode flag
R116 EQU $-2
OR A ;Is insert character mode on?
JR Z,NO_MOVE ;Jump if no insert character mode
LD DE,SCR_BUFF ;Get the buffer's address
R117 EQU $-2
GET_LINE ;Get the line from the screen
LD A,79 ;Get the maximum to move
SUB L ;Compute the number to move
LD C,A ;Make the byte, 16 bits in BC
LD B,0 ;Zero the high byte for 16 bits
OR A ;Check if count is already zero
JR Z,NO_MOVE ;Skip if it is
LD L,79 ;Get the end of the buffer
LD H,0 ; by adding 79 to the address
ADD HL,DE ;HL is now the end of the buffer
PUSH DE ;Save the buffer address
LD E,L ;Copy HL to DE
LD D,H
DEC HL ;Decrement the source address
LDDR ;Skoot the line over
POP DE ;Restore the buffer address
POP HL ;Restore the row to restore
PUT_LINE ;Put it on the screen
PUSH HL ;Push something for the POP
NO_MOVE EQU $
POP HL ;Restore the current row/col
POP AF ;Restore the character to insert
JP CHAIN ;Use *DO to display it
R118 EQU $-2
;
; The default visual begin command is to change the cursor
; to a block character
;
VSTART EQU $
LD B,8 ;Change cursor character
LD A,(VSCUR) ;Get the video start cursor
R119 EQU $-2
LD C,A ;Special graphics block
LD A,@VDCTL
RST 28H
RET
;
; This is the default call out for visual end.
;
VEND EQU $
LD B,8 ;Set the normal cursor character
LD A,(VECUR) ;Get the video end cursor
R120 EQU $-2
LD C,A
LD A,@VDCTL
RST 28H
RET ;Return
;
;
; Calculate address of Row and Column in HL
;
GET_RC_ADDR PUSH BC
PUSH AF
PUSH DE
PUSH HL ;Copy the Row and Column to DE
POP DE
LD HL,0F800H ;Get the start of the screen
LD BC,80 ;One row is this long
ADD_LOOP DEC D ;Decrement the row count
JP M,NO_MORE ;If less than zero, no more rows
R121 EQU $-2
ADD HL,BC ;Add one more Row's worth
JR ADD_LOOP ;Go to the top of the loop
NO_MORE LD D,0 ;Make it a 16 bit value
ADD HL,DE ;Add it into the total
POP DE
POP AF
POP BC
RET ;Return to caller
;
; Calculate Row and Column based on address in HL
;
GET_ADDR_RC PUSH BC ;Save the registers
PUSH AF
PUSH DE
LD BC,0F800H ;Get the start of the screen
OR A ;Reset the carry flag
SBC HL,BC ;HL now is the offset into screen
LD D,0 ;This is the counter
LD BC,80 ;Get one rows worth
SUB_LOOP OR A ;Reset the carry
SBC HL,BC ;Subtract one rows worth
JP C,NO_MORE_2 ;There are no more so leave
R122 EQU $-2
INC D ;Add one to the row count
JR SUB_LOOP ;Go to the top of the loop
NO_MORE_2 ADD HL,BC ;Correct for the subtract
LD H,D ;Get the row count, L has the
;Column already in it
POP DE ;Restore the registers
POP AF
POP BC
RET ;Return to the caller
;
; Data storage area
;
LASTPUSH DW PUSHAREA ;Next place to push pos into
R140 EQU $-2
PUSHAREA DS 20 ;Storage area
ENDPUSH EQU $ ;End of storage
OLDSTATE DW 0 ;Any preexisting state for
;special character sequences,
;actually, the address of the
;routine to execute the next time
;that a @PUT request is made.
INSERT_FLAG DB 0 ;Insert character mode flag
DEL_FLAG DB 0 ;Delete or Insert line direction
CHAR_2 DB 0 ;Second character in a multiple
; ;character sequence.
VIDEO_START DW VSTART ;Call out address for visual begin
R123 EQU $-2
VIDEO_END DW VEND ;Call out address for visual end
R124 EQU $-2
FLAG_ADDR DW 0 ;Address of flags area
GOTO_ROW DB 0 ;Saved row for cursor motion
SCR_BUFF DS 81 ;Space for put_line and get_line
NEWCHAR DB 0 ;Character sent to @PUT request
MODEND EQU $ ;End of the routine
FLTR_LEN EQU MODEND-FILTER ;This is the length
INTRO EQU $
DB 'H19 Emulator-filter for TRSDOS 6.2. '
DB 'Written by: Gregg Wonderly',29,26
DB 'Load address: ',3
INTRO2 DB ' Ending address: ',3
STRING DS 80
FIRST DW 0
;
; Entry point of load routine.
;
LOAD EQU $
LD (MODDCB),DE ;Save the DCB address
LD A,@FLAGS ;Get the Flags area address
RST 28H
LD (FLAG_ADDR),IY ;Save it away
LD HL,INTRO ;Print the intro message
LD A,@DSPLY
RST 28H
LD HL,0 ;Get HIGH MEMORY pointer from DOS
LD B,0 ;B=0 selects HIGH$
LD A,@HIGH$
RST 28H
LD (OLDLOW),HL ;Save it for later restoral
LD (FILTER+2),HL
PUSH HL
;
; Since this filter accesses the video directly, we can not reside
; up where it does. Here we determine if there is suffient space
; used to put us below the screen, or that we must waist memory,
; and relocate to just below 0F400H.
;
LD HL,0F3FEH ;Get the highest usable address
POP BC ;Get the old HIGH memory
OR A ;Reset the carry bit
PUSH HL ;Save HL
SBC HL,BC ;See if hl is less than bc
POP HL ;Get HL back
JR C,USE_HL ;If C, then use HL's address
PUSH BC ;Move BC into HL
POP HL
USE_HL EQU $
INC HL ;Must increment for true value
LD BC,FLTR_LEN ;Get the length of the filter
OR A ;Reset the carry
SBC HL,BC ;Compute the new high
PUSH HL ;Save where to load at
DEC HL ;One below that is new high
LD (OLDHIGH),HL ;Save it for restore when removed
LD B,0 ;Select HIGH$
LD A,@HIGH$
RST 28H
RELOCATE EQU $
;
; THIS ROUTINE WILL MOVE THE FILTER, UP INTO HIGH MEMORY AND
; RESET THE POINTER TO HIGH$
;
POP DE ;Get the load address
LD (FIRST),DE ;Save it for later
LD HL,STRING ;Get the scratch area
PUSH HL ;Save the address for @DSPLY
LD A,@HEX16 ;Convert DE to 4 HEX digits (HL)
RST 28H
LD (HL),3 ;Terminate with ETX
POP HL ;Get the start
LD A,@DSPLY ;Display it
RST 28H
LD HL,(FIRST) ;Get the starting reloc address
LD BC,FILTER ;Calculate offset from source
OR A ;Reset the carry
PUSH HL ;Save it
SBC HL,BC ;Offset now in HL
LD (OFFSET),HL ;Save it for later reference
POP HL ;Get the load address into hl
LD BC,FLTR_LEN ;Calculate the end
ADD HL,BC ;HL now has the ending address
PUSH HL ;Save it for transfer to DE
LD HL,INTRO2 ;Get the message string
LD A,@DSPLY ;Display it
RST 28H
POP DE ;Get the ending address
LD HL,STRING ;Get the string buffer
PUSH HL ;Save the address for later
LD A,@HEX16 ;Convert DE to 4 HEX digits (HL)
RST 28H
LD (HL),13 ;Put a carriage return on the end
POP HL ;Get the starting address back
LD A,@DSPLY ;Display the VALUE
RST 28H
LD IX,OFFTBL ;Get start of offset table
;
; LOOP TO ADD OFFSET TO ALL ADDRESSES NECESSARY
;
MOVNXT EQU $
LD BC,(OFFSET) ;Put the offset into BC
LD L,(IX) ;Get LSB of address to change
INC IX ;POINT TO MSB
LD H,(IX) ;GET IT
INC IX ;POINT TO LSB OF NEXT, OR END
PUSH IX ;Save pointer to table
PUSH HL ;Put the address into IX
POP IX
LD L,(IX) ;Get the LSB for relocation
LD H,(IX+1) ;Get the MSB
ADD HL,BC ;Relocate it
LD (IX),L ;Put it back
LD (IX+1),H
POP BC ;Get the table address in BC
PUSH BC ;Copy it back into IX
POP IX ;Restore the table address
LD HL,OFFEND ;Get the end of the offset table
OR A ;Reset the carry
SBC HL,BC ;Compute the difference
JR NZ,MOVNXT ;Loop, if not done
;
LD BC,FLTR_LEN ;MOVE MODULE INTO HIGH MEMORY.
LD DE,(FIRST)
LD HL,FILTER ;Get the load address
LDIR ;Move it into place
LD IX,(MODDCB) ;Get the dcb address back
LD DE,(FIRST)
LD (IX),47H ;Say we are a filter
LD (IX+1),E ;Tell where the filter starts
LD (IX+2),D
LD HL,0
CP A
RET
;
OFFTBL EQU $
DW R001
DW R002
DW R003
DW R004
DW R005
DW R006
DW R007
DW R008
DW R009
DW R010
DW R011
DW R012
DW R013
DW R014
DW R015
DW R016
DW R017
DW R018
DW R019
DW R020
DW R021
DW R022
DW R023
DW R024
DW R025
DW R026
DW R027
DW R028
DW R029
DW R030
DW R031
DW R032
DW R033
DW R034
DW R035
DW R036
DW R037
DW R038
DW R039
DW R040
DW R041
DW R042
DW R043
DW R044
DW R045
DW R046
DW R047
DW R048
DW R049
DW R050
DW R051
DW R052
DW R053
DW R054
DW R055
DW R056
DW R057
DW R058
DW R059
DW R060
DW R061
DW R062
DW R063
DW R064
DW R065
DW R066
DW R067
DW R068
DW R069
DW R070
DW R071
DW R072
DW R073
DW R074
DW R075
DW R076
DW R077
DW R078
DW R079
DW R080
DW R081
DW R082
DW R083
DW R084
DW R085
DW R086
DW R087
DW R088
DW R089
DW R090
DW R091
DW R092
DW R093
DW R094
DW R095
DW R096
DW R097
DW R098
DW R099
DW R100
DW R101
DW R102
DW R103
DW R104
DW R105
DW R106
DW R107
DW R108
DW R109
DW R110
DW R111
DW R112
DW R113
DW R114
DW R115
DW R116
DW R117
DW R118
DW R119
DW R120
DW R121
DW R122
DW R123
DW R124
DW R125
DW R126
DW R127
DW R128
DW R129
DW R130
DW R131
DW R132
DW R133
DW R134
DW R135
DW R136
DW R137
DW R138
DW R139
DW R140
DW R141
DW R142
DW R143
DW R144
DW R145
DW R146
DW R147
DW R148
DW R149
DW R150
DW R151
DW R152
DW R153
DW R154
DW R155
DW R156
DW R157
DW R158
DW R159
DW R160
DW R161
DW R162
DW R163
DW R164
DW R165
DW R166
DW R167
DW R168
DW R169
DW R170
DW R171
DW R172
DW R173
DW R174
DW R175
DW R176
DW R177
DW R178
DW R179
DW R180
DW R181
DW R182
DW R183
DW R184
DW R185
DW R186
DW R187
DW R188
DW R189
DW R190
DW R191
OFFEND EQU $
<<< m4h19s.asm >>>
; M4H19S/ASM
*GET M4H19/EQU
*GET M4H19/MAC
VS EQU 15 ;Offset in header for visual cursor
VE EQU 16 ;Offset in header for line mode cursor
DEF_LEN EQU 17 ;Default length of audible bell
BELLFLAG EQU 18 ;Audible or visual bell flag
DEF_FREQ EQU 19 ;Frequency value for bell tone
OLDLOW EQU 21 ;Set up address used for removing *HP
OLDHIGH EQU 23 ;Ditto
BIT_MASK EQU 29 ;Offset to bit mask
;
; Load in low memory to avoid user programs, and KERMIT in
; particular
;
ORG 2500H
START:
LD DE,ARGBUFF+1 ;Copy the arguments
LD BC,255 ;Pick a number suffiently large
LD (PARMS),DE ;Save the dest for later use
LDIR ;Move the command line
GETH19:
LD DE,H19_NAME ;Check to see if $HEATH is there
SSVC @GTMOD ;Try to find it
JP NZ,NOH19 ;Not there, so go put it in
PUSH HL ;Put the header address into IX
POP IX
LD DE,PARAM_TABLE ;Get the parameter table
LD HL,(PARMS) ;Get the command line
;
; We look for a '(' to know whether or not to display the usage
; message. If we do not find one, then we give the user help.
;
LOOP1:
LD A,(HL) ;See if there is anything there
CP 13 ;End of command line
JP Z,SHOW_VALS ;If so, then give help
CP '(' ;Start of argument list?
JR Z,LOOP2 ;Jump if it is
INC HL ;Point to next
JR LOOP1 ;Loop on
LOOP2:
DEC HL ;Back up before the '('
SSVC @PARAM ;Parse the parameter list
JP NZ,SHOW_VALS ;On failure, give help
LD A,(RESP_VS) ;Was a BLOCK cursor value given?
OR A
JR Z,CHK_VE ;Jump if not
AND 60H ;Verify only numeric.
JP NZ,BAD_PARAM ;Jump if not
LD HL,(VS_VAL) ;Get the value given
LD A,H ;Make sure it is only a byte
OR A
JP NZ,TOO_BIG ;Print a message if too big
LD A,L ;Get the byte value from L
LD (IX+VS),A ;Save it into the $HEATH header
CHK_VE:
LD A,(RESP_VE) ;Was there a line mode cursor
OR A ;Jump if not
JR Z,CHK_REM
AND 60H ;Verify it is only numeric
JP NZ,BAD_PARAM ;Jump if bad
LD HL,(VE_VAL) ;Get the value
LD A,H ;Make sure it is a byte value
OR A
JP NZ,TOO_BIG ;Jump if too big.
LD A,L ;Get the byte value from L
LD (IX+VE),A ;Store it
CHK_REM:
LD A,(RESP_REMOVE) ;Is this a remove request?
OR A
JR Z,CHK_FREQ ;If not go check bell frequency
AND 0A0H ;Must be boolean
JP NZ,BAD_PARAM
LD B,0 ;Get the current HIGH$ value
LD HL,0
SSVC @HIGH$
JP NZ,ERROR
LD A,(IX+OLDHIGH) ;Get the OLD HIGH$ from header
LD C,A
LD A,(IX+OLDHIGH+1)
LD B,A ;See if they are still the same
OR A ;Reset the carry
SBC HL,BC ;Compute the difference
JP NZ,CANT_REMOVE ;If not equal, then can't remove
LD A,(IX+OLDLOW) ;Get the previous HIGH$ that was
LD L,A ;in effect before $HEATH was
LD A,(IX+OLDLOW+1) ;installed
LD H,A
LD B,0 ;removing the module
SSVC @HIGH$
JP NZ,ERROR
;
; The code here make several RASH assumptions about what devices
; $HEATH is mated to. It assumes that the following commands were
; used to install the $HEATH module:
;
; set *hp h19
; filter *so *hp
;
; With these in mind, it does the following commands
;
; reset *so
; reset *hp
; remove *hp
; route *so *do
;
; This should restore the system to a reasonable state, given the
; fact that the filter should be in by itself anyway.
;
REMOVE_FILTER:
LD HL,CMD1 ;Do "reset *so" command
SSVC @CMNDR
LD HL,CMD2 ;Do "reset *hp" command
SSVC @CMNDR
LD HL,CMD3 ;Do "remove *hp" command
SSVC @CMNDR
LD HL,CMD4 ;Do "route *so *do" command
SSVC @CMNDR
JP SET_EXIT ;Nothing else is reasonable, quit
CHK_FREQ:
LD A,(RESP_FREQ) ;Check for a frequency given
OR A
JR Z,CHK_DUR ;Jump if none there
AND 60H ;Verify that it is numeric
JP NZ,BAD_PARAM ;Jump if not just numeric
LD HL,(FREQ_VAL) ;Get the value
LD (IX+DEF_FREQ),L ;Use all 16 bits worth
LD (IX+DEF_FREQ+1),H
CHK_DUR:
LD A,(RESP_DURA) ;Is there a duration given?
OR A
JR Z,CHK_BELL ;Jump if there is isn't
AND 60H ;Verify that it is numeric
JP NZ,BAD_PARAM ;Jump if it is not
LD HL,(DUR_VAL) ;Get the value
LD A,H ;Make sure there is only a byte
OR A
JP NZ,TOO_BIG ;Jump if MSB not zero
LD A,L ;Get the byte value from L
LD (IX+DEF_LEN),A ;Save the tone length
CHK_BELL:
LD A,(RESP_BELL) ;Are they setting bell flag?
OR A
JP Z,CHK_STRIP8 ;Check if strip8 parameter given
AND 0A0H ;Is it boolean?
JP NZ,BAD_PARAM ;Jump if not
LD A,(BELL_VAL) ;Get the value
LD (IX+BELLFLAG),A ;Save it
CHK_STRIP8:
LD A,(RESP_STRIP8) ;Get the parameter present flag
OR A
JP Z,CHK_SHOW ;Go check show parameter
AND 0A0H ;Check if boolean
JP NZ,BAD_PARAM
LD C,(IX+BIT_MASK)
LD B,(IX+BIT_MASK+1)
PUSH IX
POP HL
ADD HL,BC ;Compute the offset
LD C,0FFH ;Get the off mask
LD A,(STRIP8_VAL)
OR A
JR Z,STRIP8_OFF ;Option is off so jump
LD C,07FH ;Load on mask
STRIP8_OFF:
LD (HL),C ;Patch AND instruction
CHK_SHOW:
LD A,(RESP_SHOW) ;Check if show given
OR A
JR Z,CHK_HELP ;Check for help
AND 0A0H ;Is it boolean
JP NZ,BAD_PARAM ;Error if not
LD A,(SHOW_VAL) ;Get the value
OR A ;Make sure not (SHOW=NO)
CALL NZ,SHOW_VALS
CHK_HELP:
LD A,(RESP_HELP) ;Check if HELP given
OR A
JR Z,SET_EXIT
AND 0A0H ;Is it boolean?
JP NZ,BAD_PARAM
LD A,(HELP_VAL) ;Get the value
OR A ;Make sure not (HELP=NO)
JP Z,SET_EXIT
LD HL,HELP_STR
SSVC @DSPLY
SET_EXIT:
LD HL,0 ;Set normal exit code
RET ;Return, DON'T @EXIT HERE
;
; Show the values of the currently set options
;
SHOW_VALS:
LD HL,LINE_STR ;Get the line mode cursor descr
SSVC @DSPLY ;Display it
LD L,(IX+VE) ;Get the value
LD H,0 ;Make it only a byte
CALL NUMOUT ;Print it on the screen
LD HL,BLK_STR ;Print the block mode descr
SSVC @DSPLY
LD L,(IX+VS) ;Get the value
LD H,0 ;Make it a byte
CALL NUMOUT ;Print the number on the display
LD C,13 ;Get a new line
SSVC @DSP
LD HL,BELL_STR ;Print the BELL descr
SSVC @DSPLY
LD HL,ON_STR ;Get the ON string
LD A,(IX+BELLFLAG) ;Get the value
OR A ;Check if it is on
JR NZ,SHOW_1 ;Jump if it is
LD HL,OFF_STR ;Get the off string
SHOW_1 SSVC @DSPLY ;Display ON or OFF
LD HL,DURA_STR ;Get the duration descr
SSVC @DSPLY
LD L,(IX+DEF_LEN) ;Get the duration
LD H,0 ;Make it a byte in HL
CALL NUMOUT ;Print the number on the screen
LD HL,FREQ_STR ;Print the frequency descr
SSVC @DSPLY
LD L,(IX+DEF_FREQ) ;Get the LSB of FREQ
LD H,(IX+DEF_FREQ+1);Get the MSB
CALL NUMOUT ;Print the number out
LD HL,STRIP_STR ;Get the STRIP8 message
SSVC @DSPLY
LD C,(IX+BIT_MASK)
LD B,(IX+BIT_MASK+1)
PUSH IX
POP HL
ADD HL,BC ;Compute the offset
LD A,(HL)
LD HL,ONSTR
CP 0FFH ;Check for off
JR NZ,ISON
LD HL,OFFSTR
ISON:
SSVC @DSPLY
RET ;Return to caller
;
NUMOUT LD DE,STRBUF
PUSH DE
SSVC @HEXDEC
EX DE,HL
LD (HL),3
POP HL
LD A,' '
NUM_1 CP (HL)
JR NZ,NUM_2
INC HL
JR NUM_1
NUM_2 SSVC @DSPLY
RET
;
CANT_REMOVE:
LD HL,NO_REMOVE ;Print the Can't remove message
SSVC @DSPLY
JP REMOVE_FILTER ;Finish unlinking the devices
;
TOO_BIG:
LD HL,TOO_BIG_STR ;Get the TOO BIG message
DB 0DDH ;Hide LD HL instruction
;
NOH19MESS:
LD HL,NOFLT_STR ;Print error message, No H19/FLT
DB 0DDH ;Hide LD HL
;
BAD_PARAM LD HL,BAD_PARAM_STR;Print Bad paramter message
;
PRINT_EXIT:
SSVC @DSPLY ;Print it
EXIT:
LD HL,-1 ;Get error exit code
RET ;Return from caller
;
ERROR:
OR 0C0H
LD C,A
SSVC @ERROR
JR EXIT
;
NOH19:
LD A,(ONCE) ;Check if we have been here once
OR A
JR NZ,NOH19MESS ;If so, then issue a message
INC A ;Set the flag
LD (ONCE),A
LD HL,SETH19 ;Do the "set *hp h19" command
SSVC @CMNDR
LD HL,FILTER ;Do the "filter *so *hp" command
SSVC @CMNDR
JP GETH19 ;Try to load it again
;
H19_NAME DB '$HEATH',0
NO_REMOVE DB 'Can not reclaim used memory!',13
STRIP_STR DB 10,'Strip 8th bit: ',3
ONSTR DB 'YES',13
OFFSTR DB 'NO',13
NOFLT_STR DB 'Can not find H19 filter',13
BAD_PARAM_STR DB 'Bad parameter value',13
TOO_BIG_STR DB 'Value too large',13
LINE_STR DB 'Normal cursor: ',3
BLK_STR DB ', Block cursor: ',3
DURA_STR DB ', Duration: ',3
FREQ_STR DB ', Frequency: ',3
BELL_STR DB 'Bell: ',3
ON_STR DB 'ON',3
OFF_STR DB 'OFF',3
;
HELP_STR DB 'Recognized parameters:',10
DB 'CURSOR - Normal cursor character',10
DB 'BLOCK - Block cursor character',10
DB 'BELL - Turn bell ON or OFF',10
DB 'FREQUENCY - Frequency of bell (inverse of '
DB 'real freq)',10
DB 'DURATION - Length of tone (255 MAX)',10
DB 'STRIP8 - Remove 8th bit from characters '
DB '(default=ON)',10
DB 'REMOVE - Remove the filter from memory'
DB 10,'SHOW - Show all values',10
DB 'HELP - This message',10,13
;
VE_VAL DW 0
VS_VAL DW 0
RM_FLAG DW 0
DUR_VAL DW 0
FREQ_VAL DW 0
BELL_VAL DW 0
SHOW_VAL DW 0
HELP_VAL DW 0
STRIP8_VAL DW 0
;
CMD1 DB 'reset *so',13
CMD2 DB 'reset *hp',13
CMD3 DB 'remove *hp',13
CMD4 DB 'route *so *do',13
SETH19 DB 'set *hp h19',13
FILTER DB 'filter *so *hp'
PARMS DW 0
ONCE DB 0
ARGBUFF DB ' '
DS 255
STRBUF DS 20
;
PARAM_TABLE:
DB 80H
;
DB 80H+5
DB 'BLOCK'
RESP_VS DB 0
DW VS_VAL
;
DB 80H+6
DB 'CURSOR'
RESP_VE DB 0
DW VE_VAL
;
DB 40H+6
DB 'REMOVE'
RESP_REMOVE DB 0
DW RM_FLAG
;
DB 90H+9
DB 'FREQUENCY'
RESP_FREQ DB 0
DW FREQ_VAL
;
DB 90H+8
DB 'DURATION'
RESP_DURA DB 0
DW DUR_VAL
;
DB 40H+4
DB 'BELL'
RESP_BELL DB 0
DW BELL_VAL
;
DB 40H+4
DB 'SHOW'
RESP_SHOW DB 0
DW SHOW_VAL
;
DB 40H+4
DB 'HELP'
RESP_HELP DB 0
DW HELP_VAL
;
DB 46H
DB 'STRIP8'
RESP_STRIP8 DB 0
DW STRIP8_VAL
;
TABLE_END DB 0
END START
<<< m4key.asm >>>
; m4key/asm
;
GETKEY EQU $
LD HL,(KEYPOS) ;Get the buffered keys address
GETKEY_0 EQU $
LD A,(HL) ;Get the key there
IFZ GETKEY_1 ;Jump if no key available
INC HL ;Point to next
LD (KEYPOS),HL ;Save the new pointer
CP A ;Set Z status
RET ;Return the key
;
; Here, we must change the current string pointer back to a KNOWN
; zero byte. Otherwise the next defintion may move non-zero data
; underneath the pointer and result in garbage being retrieved on
; the next call to GETKEY.
;
GETKEY_1 EQU $
LD HL,ATNULL ;Replace current string pointer
LD (KEYPOS),HL
CALL TRMIN ;Get a key from *SI
RET NZ ;Return if nothing there
LD (SAVEDKEY),A ;Save it for later use
CALL KEYTRANS ;Get the address from the table
OR H ;A holds L, OR in H to check
JR NZ,GETKEY_0 ;Jump if string is present
LD A,(SAVEDKEY) ;Get the real key back
CP A ;Set Z status
RET ;Return the key
;
; Store a key definition into the table
;
DEFKEY EQU $
LD (KEYSTRING),HL ;Save the pointer to the data
LD (KEYNUMBER),A ;Save the key to be replaced
PUSH AF
LD A,B ;Get the number of bytes in (HL)
LD (STRINGLEN),A ;Store it
POP AF
CALL KEYTRANS ;Get the address of the current
OR H ;definition and see if one exists
CALL NZ,DELETEKEY ;If so, then remove it
LD A,(STRINGLEN) ;Get the length
OR A ;Is there a string there?
RET Z ;Return if none. Old was deleted
LD HL,DEFTABLE+DEFTLEN-1;Get the top of the table
LD DE,(TOPADDR) ;Get the start of available
OR A ;Reset carry
SBC HL,DE ;Compute available number bytes
LD C,A ;Get the request size as 16 bits
LD B,0
OR A ;Reset the carry
SBC HL,BC ;Compute the remaining after use
JR NC,DEFKEY_1 ;Jump if there is room for it
LD DE,NOSPACE ;Print the error message
CALL PRTSTR
RET ;Return without defining it
DEFKEY_1 EQU $
LD HL,(KEYSTRING) ;Get the new definition
PUSH DE ;Save the address to store at
LDIR ;Move the string
EX DE,HL ;Get the ending address
LD (HL),0 ;Put a NULL in
INC HL ;Point to next available
LD (TOPADDR),HL ;Save the new available address
POP DE ;Restore the definition address
LD HL,(TABLEADDR) ;Get the address in the table
LD (HL),E ;Store the LSB
INC HL ;Point to the MSB
LD (HL),D ;Save the MSB
RET ;Return to the caller
;
; Get the address of the string corresponding to the key number
; in A. A holds the value of H on return. HL is zero if no
; definition exists. HL is the address of the string that is
; defined for the key if it is non-zero. The last byte in the
; string is followed by a zero byte.
;
KEYTRANS EQU $
LD HL,KEYTABLE ;Get the pointer table
LD C,A ;Put it into C
LD B,0 ;Set B to zero initially
RLC C ;C = C * 2
JR NC,KEYTRANS_1 ;If carry on shift then c > 127,
INC B ;so increment B to recover bit 7
KEYTRANS_1 EQU $
RES 0,C ;Reset the LSB of C.
ADD HL,BC ;Compute the table address
LD (TABLEADDR),HL ;Save the address of the key def
LD A,(HL) ;Get the LSB
INC HL ;Point to the MSB
LD H,(HL) ;Get it
LD L,A ;Get the LSB
RET ;Return to caller
;
; Delete a key definition from the table. No parameters are
; needed. The key to undefine is pointed to by (TABLEADDR).
; Thus, you must call KEYTRANS with the key number in A and then
; call DELETEKEY to delete the key.
;
DELETEKEY EQU $
LD HL,(TABLEADDR) ;Get the addr of the definition
LD E,(HL) ;Get the LSB of the string
XOR A ;Clear A
LD (HL),A ;Zap the LSB
INC HL ;Point to the MSB
LD D,(HL) ;Get the MSB
LD (HL),A ;Zap the MSB
LD (CMPADDR),DE ;Save the address for compares
LD H,D ;Copy DE to HL
LD L,E
; XOR A ;A is already zero (what we seek)
CPIR ;Look for it
PUSH HL ;Save the ending address
OR A ;Reset the carry
SBC HL,DE ;Compute the difference
LD (MOVEDIFF),HL ;Save the difference
LD HL,(TOPADDR) ;Get the end of the table
POP BC ;Get the end of string to delete
OR A ;reset the carry
SBC HL,BC ;Calculate number bytes to move
PUSH BC ;Exchange HL and BC
PUSH HL
POP BC
POP HL
LD A,B ;Check for zero length
OR C
JR Z,DELETEKEY_1 ;Don't move 65536 bytes
LDIR ;Adjust the strings down
DELETEKEY_1 EQU $
LD (TOPADDR),DE ;Set the new top address
LD HL,KEYTABLE ;Get start of table
LD B,0 ;Check 256 entrys
DELETEKEY_2 EQU $
PUSH BC ;Save the counter
LD C,(HL) ;Get the table value LSB
INC HL ;Point to MSB
LD B,(HL) ;Get the MSB
DEC HL ;Back to original address
LD A,B ;Check for any definition
OR C ;Set the flags
JR Z,DELETEKEY_4 ;Skip this entry
PUSH HL ;Save the table address
LD HL,(CMPADDR) ;Get the address to check against
OR A ;Reset the carry
SBC HL,BC ;Compute the difference
JP P,DELETEKEY_3 ;Jump if no adjust needed
LD H,B ;Copy BC to HL
LD L,C
LD BC,(MOVEDIFF) ;Get the difference
OR A ;Reset the carry
SBC HL,BC ;Adjust the pointer
LD C,L ;Copy HL to BC
LD B,H ;Get the MSB
POP HL ;Get the destination address
LD (HL),C ;Store the LSB back
INC HL ;Point to MSB
LD (HL),B ;Store the MSB
JR DELETEKEY_5 ;Join other code
DELETEKEY_3 EQU $
POP HL ;Get the table address back
DELETEKEY_4 EQU $
INC HL ;Point to next table pos
DELETEKEY_5 EQU $
INC HL ;One more increment
POP BC ;Get the counter back
DJNZ DELETEKEY_2 ;Loop until done
RET
;end of file
<<< m4log.asm >>>
; 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<CR><ESC><CR> 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 <ENTER>, <BREAK>, and <PAUSE>
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 <CR> 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 <CR>, <LF>, <FF>, 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
<<< m4mac.asm >>>
; m4mac/asm
*LIST OFF
PUTHL MACRO #P1
LD (HL),#P1
INC HL
ENDM
;
; Protocol switch macro
;
; Expansion is something like:
;
; CP 'D'
; JR NZ,SWAA
; CALL SDATA
; JP PROTO
;SWAA
;
SWITCH MACRO #P1,#P2
CP #P1
JR NZ,SW?
CALL #P2
JP PROTO
SW?
ENDM
;
TOCHAR MACRO
ADD A,32
ENDM
;
STROUT MACRO #P1
LD DE,#P1
CALL PRTSTR
ENDM
;
SPACKET MACRO #P1
LD A,#P1
CALL SPACK
JP ABORT
ENDM
;
RPACKET MACRO
CALL RPACK
JP QUIT
ENDM
;
NSTATE MACRO #P1
LD A,#P1
LD (STATE),A
ENDM
;
IFANOT MACRO #P1,#P2
CP #P1
JR NZ,#P2
ENDM
;
IFALT MACRO #P1,#P2
CP #P1
JR C,#P2
ENDM
;
IFAGE MACRO #P1,#P2
CP #P1
JR NC,#P2
ENDM
;
IFA MACRO #P1,#P2
CP #P1
JR Z,#P2
ENDM
;
IFZ MACRO #P1
OR A
JR Z,#P1
ENDM
;
GENCASE MACRO #P1,#P2
LD A,#P2
LD (FLDLEN),A
LD A,#P1
JP GENCMD
ENDM
;
GETHL MACRO #P1
INC HL
LD #P1,(HL)
ENDM
;
ADDPUT MACRO #P1
LD A,(#P1)
CALL TCHPUT
ENDM
;
SRPACK MACRO #P1
LD A,#P1
CALL SPACK
JP ABORT
RPACKET
ENDM
;
GETCRCTAB MACRO
LD C,A
LD HL,CRCTAB
ADD HL,BC
ADD HL,BC
ENDM
;
XORATHL MACRO #P1
LD A,#P1
XOR (HL)
LD #P1,A
ENDM
;
CHKWKEY MACRO #P1
IFA #P1,INCHR5
ENDM
;
IFNZ MACRO #P1
OR A
JR NZ,#P1
ENDM
;
SETFLG MACRO #P1
CALL ONOFF
LD (#P1),A
JP KERMIT
ENDM
;
SHOFFON MACRO #P1
LD A,(#P1)
CALL COFFON
JP NEWLIN
ENDM
;
FOFFON MACRO #P1
LD A,(#P1)
CALL COFFON
CALL NEWLIN
ENDM
;
SHRSTAT MACRO #P1,#P2
FORMAT #P1,SRSTRLEN
LD A,(#P2)
CALL ANOUT
CALL NEWLIN
ENDM
;
SHSSTAT MACRO #P1,#P2
FORMAT #P1,SRSTRLEN
LD A,(#P2)
CALL ANOUT
CALL NEWLIN
ENDM
;
DOSVC MACRO #P1
LD A,#P1
RST 28H
LD (XERRNO),A
RET
ENDM
;
FORMAT MACRO #P1,#P2
LD HL,#P2
LD DE,#P1
CALL LEFTPAD
ENDM
;
TRLOG MACRO #P1,#P2
LD HL,#P1
CALL OUTLOG
JP #P2
ENDM
*LIST ON
<<< m4mit.asm >>>
; M4MIT/ASM
;
ORG 6000H
;
; Model 4(p) KERMIT by Gregg Wonderly
;
; Version 5.2
;
; Version 5.2 adds wild card send capabilities as well as fixes
; to bugs. M4CHGS/ASM contains a list of the changes made between
; version 5.0, and 5.2.
;
; This version is a radically modified and rewritten version
; of the original TRS-80 KERMIT done by Stan Barber. It has
; numerous features and capabilities beyond that version due
; to differences between the Model 3 and 4.
;
; Get the macro definitions first
;
*GET M4EQU
*GET M4MAC
;
; Entry point for execution
;
START LD (OLDSP),SP ;Save the current stack pointer for later
LD SP,STACK ;Set up the stack to our area
CALL XFLAGS ;Get the flags address in IY
LD (FLAGS),IY ;Save the flags for later
LD HL,SWTBUF ;Clear initial connect screen buffer
LD DE,SWTBUF+1
LD BC,1920 ;Byte counter
LD (HL),' ' ;Clear the first character
LDIR ;Copy it to the next
LD B,1 ;Move low memory up above our code.
LD HL,0 ;Select GET option of @HIGH$
CALL XHIGH ;Get the current LOW$
JP NZ,BADMEM ;Quit on an error
LD (OLDLOW),HL ;Save for restore on exit
LD HL,TOPMEM ;Get the last address used
CALL XHIGH ;Store it as the new LOW$
JP NZ,BADMEM ;Quit on an error
LD E,'C' ;Look for the *CL DCB
LD D,'L'
CALL XGTDCB ;The address comes back in HL
LD (CLDCB),HL ;Save the address (May be wrong)
JR NZ,NOCL ;Now check for error...
LD E,'S' ;Look for the *SI DCB
LD D,'I'
CALL XGTDCB ;The address comes back in HL
LD (TMIDCB),HL ;Store the result
JR NZ,NOSI ;Skip if NOT found or other error
LD E,'S' ;Look for the *SO DCB
LD D,'O'
CALL XGTDCB ;The address comes back in HL
LD (TMODCB),HL ;Save the address
JR NZ,NOSO ;Jump if NOT found or other error
CALL SETINT ;Set up interupt receiver etc
XOR A ;ZERO A
LD (FCB),A ;SET FILE CLOSED FLAG
CALL CMBLNK ;CLEAR THE SCREEN
STROUT INTRO ;Print the intro message
CALL CHKTAK ;Check if there is a KERMIT/INI file
CALL KERMIT ;Start accepting commands.
JP EXIT1 ;If control returns, then exit
;
; Error messages printed when devices can not be found or allocated
;
NOCL LD DE,CFCL ;Error message (Can't find *CL DCB)
PRTOOPS CALL PRTSTR ;Print an OOPS message, and quit
JP EXIT2 ;Finish cleaning up
;
; No DCB for the SI device was found
;
NOSI LD DE,CFSI ;Get the message
JR PRTOOPS ;Go print it
;
; No DCB for the SO device was found
;
NOSO LD DE,CFSO ;Get the message
JR PRTOOPS ;Go print it
;
; Bad return code from @HIGH$ call
;
BADMEM CALL XERROR0 ;Print a system error message
STROUT NOMEM ;Print the message
JP XEXIT ;Exit to TRSDOS
;
; CLEAR THE SCREEN, SAVING DE
;
CMBLNK PUSH DE ;Save DE
STROUT CLRTOP ;Clear the screen
POP DE ;Restore DE
QUIT RET ;Just a simple return for QUIT
;
; KERMIT command processor
; This is where each command originates.
;
KERMIT LD SP,STACK ;Set the stack back
LD DE,FCB ;Always close an open file
LD A,(DE) ;Get the flags byte
BIT 7,A ;Is the file still open?
CALL NZ,XCLOSE ;Close it if it is
LD DE,KERM ;Get the prompt
CALL PROMPT ;Display it, and set up the parser
LD DE,COMTAB ;Get the primary command table
LD A,CMKEY ;Parse a keyword
CALL COMND ;Get a command or ERROR
JP KERMT2 ;Abort on ERROR
LD HL,KERMIT ;Put on a return address for the
PUSH HL ;FINISH, LOGOUT, and BYE commands.
PUSH HL
LD HL,KERMTB ;Get the JUMP table for these commands
LD C,A ;Make BC = A extended to 16 bits
LD B,0 ;high byte is zero, (unsigned)
ADD HL,BC ;Calculate the effective address
JP (HL) ;Jump into the jump table
;
; Jump table for primary commands
;
KERMTB JP REMOTE ;REMOTE
JP EXIT ;EXIT
JP CONNECT ;CONNECT
JP LOG ;LOG
JP READ ;RECEIVE
JP SEND ;SEND
JP SETCOM ;SET
JP SHOW ;SHOW
JP STATUS ;STATUS
JP FINISH ;FINISH
JP LOGOUT ;LOGOUT
JP BYE ;BYE
JP DIR ;DIRECTORY
JP ERA ;KILL
JP LOCCOM ;LOCAL
JP SETCL ;SETCOM
JP TAKE ;TAKE
JP INPUT ;INPUT
JP OUTPUT ;OUTPUT
JP PAUSE ;PAUSE
JP PULSE ;PULSE
JP CLEARC ;CLEAR
JP CLSFLS ;CLOSE
JP ECHO ;Type text to screen
;
; Echo text to screen
;
ECHO EQU $
LD A,CMTXT ;Get some text
LD DE,DATA ;Where to put it
PUSH DE ;Save for printing
CALL COMND ;Parse it
JP KERMT3 ;Jump on error
POP HL ;Get the start
LD C,A ;Make BC the length that is in A
LD B,0
ADD HL,BC ;Move to EOS position
LD (HL),EOS ;Put it in place
CALL NEWLIN ;Get a new line
STROUT DATA ;Print the string
JP KERMIT ;Get a new command
;
; CLEAR command. Services CLEAR INPUT-PORT, and CLEAR SCREEN
;
CLEARC LD A,CMKEY ;GET A KEYWORD
LD DE,CLRTAB ;FROM THIS TABLE
CALL COMND
JP KERMT2 ;SAY UNRECOGNIZED COMMAND ON AN ERROR
LD (TEMP1),A ;SAVE THE RETURNED VALUE
LD A,CMCFM
CALL COMND
JP KERMT3
LD A,(TEMP1)
LD C,A
IFNZ CLR010
CALL CLRPRT ;DO "CLEAR INPUT-PORT"
JP KERMIT ;GET A NEW COMMAND
CLR010 CP 3 ;IS IT CLEAR SCREEN?
JP NZ,KERMT2 ;SAY UNRECOGNIZED COMMAND IT NOT
CALL CMBLNK ;CLEAR THE SCREEN
JP KERMIT ;GET A NEW COMMAND
;
; TAKE commands from a file. This is basically a HACK that
; initializes some values so that GETSTR reads from the file,
; instead of the keyboard, until EOF is found.
;
TAKE LD DE,TFCB ;WHERE TO PUT THE FILENAME
LD A,CMIFI ;GET A FILE NAME
CALL COMND ;GET USER INPUT
JP KERMT3 ;ABORT ON AN ERROR
OR A
JP Z,KERMT3 ;Abort if no name given
LD IY,(FLAGS) ;GET THE SYSTEM FLAGS
SET 0,(IY+18) ;SET UP FOR NO FILE OPEN BIT
LD HL,TBUF ;THIS IS THE DATA BUFFER
LD DE,TFCB ;GET THE FILE FCB
LD B,0 ;256 BYTE LRL
CALL XOPEN ;TRY TO OPEN THE FILE
JR NZ,TERROR ;GO REPORT AN ERROR
LD A,1
LD (TAKFLG),A ;SET THE FLAG
JP KERMIT
TERROR CALL XERROR0 ;PRINT THE MESSAGE
XOR A ;RESET THE TAKE FLAG
LD (TAKFLG),A
JP KERMIT ;GET A NEW COMMAND
;
; SETCOM command. We use the TRSDOS SETCOM command here, as it
; saves lots of time and trouble.
;
SETCL LD A,CMTXT ;GET ARBITRARY TEXT
LD DE,CLBUF ;BUFFER TO PUT DATA INTO
CALL COMND ;GET THE INPUT
JP KERMT3 ;ABORT ON ERROR
CALL NEWLIN ;NEED A NEW LINE TO PRINT ON
LD A,CR ;Get the EOL character
LD (DE),A ;Put in the terminator
LD HL,CLBUF-7 ;Get the 'SETCOM ' prefix
CALL XCMNDR ;Let TRSDOS do it for us
JP KERMIT ;Get a new command, ignoring any errors
;
; LOCAL command. Use @CMNDR to execute a TRSDOS command
;
LOCCOM LD HL,(CMDPTR) ;GET THE ADDRESS OF THE START
SYST1 LD A,(HL) ;GET A CHARACTER
INC HL ;POINT TO THE NEXT
IFA ' ',SYST1 ;Loop if just a blank
IFA CR,SYST2 ;Do a LIB command if no text given
IFANOT '?',SYST4 ;Go if user not asking for HELP
SYST2 PUSH HL ;SAVE THE ADDRESS TO PASS
POP IY ;GET A THE ADDRESS IN AN INDEX
LD (IY-1),'L' ;HL GO INCREMENTED UP THERE
LD (IY),'I' ;SPELLING OUT LIB
LD (IY+1),'B'
LD (IY+2),CR ;ADD THE TERMINATOR
SYST4 DEC HL ;POINT TO THE ACTUAL ADDRESS
CALL NEWLIN ;NEED A NEW LINE
;
; Remove the comments below to force LOCAL to process only library
; commands
;
; LD IY,(FLAGS) ;Get the Flags pointer
; SET 4,(IY+2) ;Only library commands are allowed
CALL XCMNDR ;Do a system command
SYST5 JP KERMIT ;IGNORE ANY ERRORS
;
; Print UNRECOGNIZED COMMAND message
;
KERMT2 STROUT ERMES1 ;Issue the message
JP KERMIT
;
; Print NOT CONFIRMED message
;
KERMT3 STROUT ERMES3 ;Issue the message
JP KERMIT
;
; Exit to TRSDOS
;
EXIT LD A,CMCFM ;Get a confirmation of the EXIT
CALL COMND
JP KERMT3
EXIT1 LD DE,FCB ;Check the file FCB, and close if needed
LD A,(DE) ;Get the info byte
BIT 7,A ;Check the file open BIT
CALL NZ,XCLOSE ;Close it if needed
;
; Check the log files to make sure they are closed
;
LD DE,LFCB ;Get the file FCB
LD A,(LOGFLG) ;Check if logging active
OR A ;Check the flags
CALL NZ,XCLOSE ;Close the file if open
LD DE,DFCB ;Check debugging
LD A,(DEBLOG) ;Get the flag
OR A
CALL NZ,XCLOSE ;Close it if open
LD DE,TFCB ;Get the FCB
LD A,(TRANLOG) ;Get the flag
OR A
CALL NZ,XCLOSE ;Close it if open
;
; Now reset the interrupt vector for *CL.
;
LD C,4 ;Interrupts option of the @CTL SVC
LD IY,0 ;Reset the INTERRUPT vector of *CL
LD DE,(CLDCB) ;Get the *CL DCB address
CALL XCTL ;Use @CTL to do it
CALL CMBLNK ;Clear the screen
EXIT2 LD HL,(OLDLOW) ;Get the old low memory pointer
LD B,1 ;Set B to indicate LOW$
CALL XHIGH ;Move the value back
;
; Now fill the *FO, and *FI devices DCB's with zeros. This
; will make the devices no longer available.
;
LD HL,(FINDCB) ;Get the *FI DCB address
CALL ZERO8 ;Fill it with zeroes
LD HL,(FOTDCB) ;Do the same for *FO
CALL ZERO8 ;Fill DCB with zeroes
CALL STOPTIMER ;Stop the timer if still running
LD SP,(OLDSP) ;Restore the old STACK pointer
LD HL,0 ;Set OK exit
LD IY,(FLAGS) ;If JCL active, then just return
BIT 5,(IY+18) ;Check the BIT
RET NZ ;Return if BIT is set
JP XEXIT ;Exit via @EXIT
;
; Zero 8 bytes pointed to by HL
;
ZERO8 LD B,8 ;Get the byte count
ZERO8_1 LD (HL),0 ;Zap one byte
INC HL ;Point to next
DJNZ ZERO8_1 ;Loop until done
RET
;
; CALL ERROR Prints the DATA area on a new line, and sets
; the state to ABORT.
; CALL ERROR1 Prints the DATA area on a new line.
; CALL ERROR2 Prints the DATA area on the same line
; CALL ERROR3 Prints the string pointed to by DE on a new line
; CALL ERRORD Prints a system error message corresponding to
; A, providing A is none zero.
;
ERROR NSTATE 'A' ;Set the state to abort
;
ERROR1 CALL NEWLIN ;Get a new line
;
ERROR2 LD A,(ARGBLK+1) ;Get the length of the data
LD C,A ;Put the length into BC
LD B,0
LD HL,DATA ;Get the start of the DATA area
PUSH HL ;Save it
LD A,EOS ;Add EOS for printing
CALL PUTTRN
POP DE ;Get start back
JP PRTSTR ;Print the string, and return
;
ERROR3 PUSH DE ;Save the message
CALL NEWLIN ;Get a new line
POP DE ;Restore the message
JP PRTSTR ;Print error message
;
ERRORD OR A ;Display system error message
RET Z ;IFF an error has occured
JP XERROR0 ;Do system error
;
; Print the string in DE, followed by a new line
;
FINMES CALL PRTSTR ;Print the message
JP NEWLIN ;Get a newline and return
;
; The FINISH, BYE, and LOGOUT commands all need a return address
; on the stack. This is because the CHKTRYS routine will use it
; to abort the packet operations when MAXTRY retries are reached.
;
; This is the FINISH command.
;
FINISH LD A,CMCFM
CALL COMND ;GET A CONFIRM.
JP KERMT3
CALL NEWLIN
CALL CLRPRT ;CLEAR ANY STACKED NAKS
XOR A ;DIDN'T GET A CONFIRM.
LD (NUMTRY),A ;INITITIALIZE COUNT.
LD A,'1' ;Set block check to single char
LD (CURCHK),A ;. . .
FINSH1 CALL CHKTRYS ;Check the retry threshold
XOR A
LD (ARGBLK),A ;MAKE IT PACKET NUMBER ZERO.
LD A,1
LD (ARGBLK+1),A ;ONE PIECE OF DATA.
LD HL,DATA
LD (HL),'F' ;FINISH RUNNING KERMIT.
LD A,'G' ;GENERIC COMMAND PACKET.
CALL SPACK ;Send the packet
JP FINSH1 ;On fail, try again
CALL RPACK ;GET AN ACKNOWLEDGEMENT.
JP FINSH1 ;On fail, try again
CP 'Y' ;ACK?
JP Z,KERMIT ;YES, WE ARE DONE.
IFANOT 'E',FINSH2 ;Jump if not error packet
CALL ERROR1 ;PRINT THE ERROR MESSAGE.
JP KERMIT
FINSH2 CP 'N' ;Is this a NAK?
CALL NZ,CONOUT ;Output the packet type to term
JR FINSH1 ;Resend the packet
;
; This is the LOGOUT command.
;
LOGOUT LD A,CMCFM
CALL COMND ;GET A CONFIRM.
JP KERMT3
CALL NEWLIN
CALL LOGO ;SEND THE LOGOUT PACKET.
JP LOG111 ;GO GET ANOTHER COMMAND
JP KERMIT ;WHETHER WE SUCCEED OR NOT.
LOGO XOR A
LD (NUMTRY),A ;INITITIALIZE COUNT.
CALL CLRPRT ;CLEAR ANY STACKED NAKS
LD A,'1' ;Block check type to single
LD (CURCHK),A ;. . .
LOGO1 CALL CHKTRYS ;Check retry threshold
XOR A
LD (ARGBLK),A ;MAKE IT PACKET NUMBER ZERO.
LD A,1
LD (ARGBLK+1),A ;ONE PIECE OF DATA.
LD HL,DATA
LD (HL),'L' ;LOGOUT THE REMOTE HOST.
LD A,'G' ;GENERIC COMMAND PACKET.
CALL SPACK
JP LOGO3
CALL RPACK ;GET AN ACKNOWLEDGEMENT
JP LOGO1
CP 'Y' ;ACK?
JP Z,RSKP ;YES, WE ARE DONE.
CP 'E' ;IS IT AN ERROR PACKET?
JP Z,ERROR1 ;Print the error message
LOGO2 CP 'N'
CALL NZ,CONOUT
JR LOGO1
;
LOGO3 LD DE,ERMS19 ;Get the message
JP PRTSTR ;Print it
;
; This is the BYE command
;
BYE EQU $
LD A,CMCFM
CALL COMND ;GET A CONFIRM.
JP KERMT3
CALL NEWLIN
CALL LOGO ;TELL THE MAIN FRAME TO LOGOUT.
JP LOG111 ;IF IT FAILS, DON'T EXIT.
JP EXIT1 ;EXIT KERMIT.
LOG111 CALL NEWLIN ;GET A NEW LINE
JP KERMIT
;
; Get the rest of the modules
;
*GET M4FILE/ASM ;Log file code
*GET M4CMD/ASM ;Command parser
*GET M4SET/ASM ;Set command processing
*GET M4TERM/ASM ;Terminal emulation
*GET M4SHOW/ASM ;Show command processing
*GET M4PKT/ASM ;Additional packet stuff
*GET M4GET/ASM ;Receive protocol
*GET M4SEND/ASM ;Send protocol
*GET M4XFER/ASM ;Protocol common code
*GET M4ADD/ASM ;TRSDOS SVC's and other system dependent stuff
*GET M4RMT/ASM ;Remote commands
*GET M4KEY/ASM ;Set key code
*GET M4LOG/ASM ;Input, Output, Pause, Pulse commands
*GET M4WILD/ASM ;Wild carding
*GET M4STR/ASM ;Strings and storage
TOPMEM EQU $+10 ;A little padding
END START
;end of file
<<< m4pkt.asm >>>
; m4pkt/asm
;
; Most of the code in this file was derived directly from
; the C-KERMIT program. The code here represents a line by
; line translation of the C-KERMIT code.
;
MEMSTR DW 0
MAXSIZE DB 0
;
; Encode a packet from memory contents instead of from a file
;
ENCSTR EQU $
PUSH HL ;Save the registers
PUSH BC
PUSH DE
LD (MEMSTR),HL ;Store the passed pointer
CALL RSETPKT ;Reinitiaize GETPKT() parameters
CALL GETPKT ;Get a packet
LD HL,0 ;Reset the memory pointer
LD (MEMSTR),HL
POP DE ;Restore the registers
POP BC
POP HL
RET ;Return to the caller
;
; Get a packet worth of data from the FILE indicated by the global
; FCB. Eighth bit quoting, and Repeat count prefixing are done
; as indicated by the status of EBQFLAG, and RPTFLG respectively.
;
GETPKT EQU $
PUSH BC ;Save the registers
PUSH DE
PUSH HL
LD A,(CURCHK) ;Calculate the size of a packet
SUB '1'
LD B,A
LD A,(SPSIZ) ;Get the user specified size
SUB 5 ;Minus the overhead
SUB B
LD (MAXSIZE),A ;Save it for later use
LD HL,(NEXT) ;Get the next character, 16 bits
LD BC,0 ;Subtract zero to set flags
OR A ;Reset the carry flag
SBC HL,BC ;Set the flags
JP P,GETPKT1
CALL GETCH ;Get a character if no previous exists
LD (CH),HL ;Save it
GETPKT1 EQU $
LD BC,0 ;Copy leftovers from previous call
GETPKT2 EQU $
LD HL,LEFTOVER ;Get the start
ADD HL,BC ;Index by BC
LD A,(HL) ;Get a byte
LD HL,FILBUF ;Get the destination
ADD HL,BC ;Index by BC
LD (HL),A ;Put a byte
IFZ GETPKT3 ;Exit loop if zero byte found
INC C ;Point to next
JR GETPKT2 ;Loop on
GETPKT3 EQU $
LD A,C ;Save the initial size of leftovers
LD (SIZE),A
XOR A ;Nullify the string for next time
LD (LEFTOVER),A
GETPKT4 EQU $
LD HL,(CH) ;Get the character
LD BC,0 ;Subtract zero to set the flags
OR A
SBC HL,BC
JP M,GETPKT20 ;Jump at end of file
CALL GETCH ;Get the next character
LD (NEXT),HL ;Save it
LD A,(SIZE) ;Get the current size
LD (OSIZE),A ;Save it in case we overflow the packet
LD C,A ;Make BC a 16 bit value of C
LD B,0
LD HL,FILBUF ;Get the desination buffer
ADD HL,BC ;Index by BC
LD (CBFPTR),HL ;Save the buffer pointer
LD HL,(CH) ;Get the character
LD A,L ;Keep only 8 bits
CALL ENCODE ;Encode it and store the result
LD HL,(CBFPTR) ;Compute the new size
LD BC,FILBUF ;Get the start
OR A ;Reset carry
SBC HL,BC ;Compute lenght
LD A,L ;Keep only 8 bits
LD (SIZE),A ;Store the result
LD HL,(NEXT) ;Get the next character
LD (CH),HL ;Store it as the current character
LD A,(SIZE) ;Get the size and check the size
LD C,A
LD A,(MAXSIZE) ;Get the maximum length
CP C ;Are they equal?
JP Z,GETPKT20 ;Go return SIZE if equal
JP P,GETPKT13 ;Jump if maxsize still bigger
LD BC,0 ;Start from the beginning
GETPKT11 EQU $
LD A,(OSIZE) ;Get the oldsize index
PUSH BC ;Save the value of i
ADD A,C ;Compute osize+i
LD C,A ;Save the result
LD HL,FILBUF ;Get the start of the buffer
ADD HL,BC ;Compute &filbuf[osize+i]
LD A,(HL) ;Get the character stored there
POP BC ;Restore i
LD HL,LEFTOVER ;Get the address of the leftover buffer
ADD HL,BC ;Compute the absolute address
LD (HL),A ;Store the byte
OR A ;Check the value for zero
JR Z,GETPKT12 ;Jump if end of string
INC C ;Compute i++
JR GETPKT11 ;Go to the top of the loop
GETPKT12 EQU $
LD A,(OSIZE) ;Store the new pointer
LD (SIZE),A
LD C,A ;Terminate the string with a NULL
LD B,0 ;Get a 16 bit offset
LD HL,FILBUF ;Get the starting address
ADD HL,BC ;Compute the address
LD (HL),0 ;Put in the NULL
JP GETPKT20 ;Go to the return code
GETPKT13 EQU $
JP GETPKT4
GETPKT20 EQU $
LD A,(SIZE) ;Get the size to return
POP HL ;Restore the registers
POP DE
POP BC
RET
;
; Encode the character in the Accumlator and put it into
; the packet buffer at CBFPTR.
;
ENCODE EQU $
PUSH BC ;Save the regs
PUSH DE
PUSH HL
LD C,A ;Save the character to encode
LD A,(RPTFLG) ;Is repeat quoting in effect?
OR A
JP Z,ENCODE30
LD HL,(NEXT) ;Get the last character
LD A,L
IFANOT C,ENCODE3
LD A,(RPTCNT) ;Get the current repeat count
INC A ;Add one to it
LD (RPTCNT),A ;Store it back
CP 94 ;Too many characters?
JP M,ENCODE50
LD A,(RPTQ)
CALL PUTCBF
LD A,(RPTCNT)
TOCHAR
CALL PUTCBF
XOR A
LD (RPTCNT),A
JP ENCODE30
ENCODE3 EQU $
LD A,(RPTCNT)
IFANOT 1,ENCODE7
XOR A
LD (RPTCNT),A
LD A,C ;Get the character back
CALL ENCODE ;Encode it again
LD HL,(CBFPTR) ;Get the buffer pointer
LD DE,FILBUF ;Get the start of the buffer
OR A ;Reset the carry
SBC HL,DE ;Compute the difference in L
LD A,(MAXSIZE) ;Get MAXSIZE
CP L ;Is L <= A?
JP M,ENCODE6
LD A,L ;Get SIZE
LD (OSIZE),A ;Store it in the old size
ENCODE6 EQU $
XOR A
LD (RPTCNT),A
LD A,C ;Get the character back
CALL ENCODE ;Encode it
JP ENCODE50
ENCODE7 EQU $
LD A,(RPTCNT)
CP 2
JP M,ENCODE10
LD A,(RPTQ)
CALL PUTCBF
LD A,(RPTCNT) ;Get the count
ADD A,' '+1 ;Uncontrolify it
CALL PUTCBF
XOR A
LD (RPTCNT),A
ENCODE10 EQU $
ENCODE30 EQU $
LD A,C ;Get the character
AND 127 ;Turn off high bit
LD B,A ;Save it
LD A,C ;Get the character
AND 128 ;Leave only high bit
LD D,A ;Save it
IFZ ENCODE32
LD A,(EBQFLG)
IFZ ENCODE32
LD A,(EBQ)
CALL PUTCBF
LD C,B ;Save only 7 bit version
ENCODE32 EQU $
LD A,C ;Get all bits for check
IFA 127,ENCODE33
IFAGE ' ',ENCODE34
ENCODE33 EQU $
LD A,(MYCTLQ)
CALL PUTCBF
LD A,C ;Get the character
ADD A,64 ;Uncontrolify it
AND 127 ;Keep only 7 bits
LD C,A ;Save the new value
ENCODE34 EQU $
LD HL,(CBFPTR) ;Do this ahead to save overhead
LD A,(MYCTLQ)
IFANOT B,ENCODE35
PUTHL A ;Store the byte
ENCODE35 EQU $
LD A,(RPTFLG)
IFZ ENCODE36
LD A,(RPTQ)
IFANOT B,ENCODE36
LD A,(MYCTLQ)
PUTHL A
ENCODE36 EQU $
LD A,(EBQFLG)
IFZ ENCODE37
LD A,(EBQ)
IFANOT B,ENCODE37
LD A,(MYCTLQ)
PUTHL A
ENCODE37 EQU $
PUTHL C
LD (CBFPTR),HL
LD (HL),0
ENCODE50 EQU $
POP HL ;Restore the stack
POP DE
POP BC
RET
;
; Decode the contents of the packet, and output them using
; the function whose address is passed in HL
;
DECODE LD (OUTADDR),HL ;Save the output function
PUSH BC ;Save the registers that we use
PUSH DE
PUSH HL
LD HL,DATA ;Get the buffer address
LD (DATPTR),HL ;Set the address
LD C,A ;Get the length
LD B,0 ;Make it 16 bits
PUSH HL ;Save DATPTR
ADD HL,BC ;Compute the end of the packet
LD (HL),0 ;Put in the NULL byte
POP HL ;Get DATPTR back
DECODE0 LD A,1 ;Set the repeat count
LD (RPTCNT),A
LD A,(HL) ;Get a character
INC HL ;Point to the next
LD C,A ;Store the value
OR A ;Is it NULL?
JP Z,DECODE40 ;Quit the loop if it is
LD A,(RPTFLG) ;Is repeat prefixing on?
IFZ DECODE1
LD A,(RPTQ) ;Get the quote character
IFANOT C,DECODE1
LD A,(HL) ;Get the count + 32
SUB ' ' ;Make it the real count
INC HL ;Point to next character
LD (RPTCNT),A ;Save the repeat count
LD A,(HL) ;Get a character
INC HL ;Point to the next
LD C,A ;Save the character
DECODE1 XOR A ;Set the initial eighth bit as ZERO
LD D,A
LD A,(EBQFLG) ;Is eighth bit quoting on?
IFZ DECODE2
LD A,(EBQ) ;Get the eighth bit quote character
IFANOT C,DECODE2
LD D,128 ;Get an eighth bit
LD A,(HL) ;Get a character
INC HL ;Point to the next
LD C,A ;Save the character
DECODE2 LD A,(MYCTLQ) ;Get the control character quote
IFANOT C,DECODE5
LD A,(HL) ;Get a character
INC HL ;Point to the next
LD C,A ;Save the character
AND 127 ;Keep 7 bits
LD E,A ;Save only 7 bits worth
LD A,E ;Check lower bound of controls
CP '@'
JP M,DECODE3 ;Jump if less than
CP 96 ;Check upper bound of controls
JP M,DECODE4
DECODE3 IFANOT '?',DECODE5
DECODE4 LD A,C ;Get the character
SUB 64 ;Subtract 64 to uncontrolify it
AND 127
LD C,A ;Save the new value
DECODE5 LD A,D ;Get the eighth bit
OR C ;Or in the character
LD C,A ;Save the new value
LD A,(RPTCNT) ;Get the repeat count
LD B,A ;Get it into the counter
DECODE8 LD IX,RTRANS ;Get the pointer
CALL INCKTRANS ;Increment character counts
LD A,C ;Get the character
CALL PUTCH
JR NZ,DECODE50
DJNZ DECODE8 ;Loop until done
JP DECODE0
DECODE40 EQU $
POP HL ;Restore the stack
POP DE
POP BC
RET
DECODE50 EQU $
CALL XERROR0 ;Print a system error message
LD A,1 ;Set NZ status for return
OR A
JR DECODE40 ;Join the exit code
;
; Get the next character from the input file. We translate CR to
; CRLF, for ASCII files. Returns with (EOFLAG) set to 0FFH at end
; of file. The character retrieved is in HL. HL will be 16bits
; of -1 and EOF, but will otherwise only be 8bits wide. H in this
; case will always be 0, and L will hold the character.
;
GETCH LD A,(FILTYPE) ;Check for binary mode
OR A ;Set the flags
JR NZ,GETCH1 ;Jump if it is binary
LD A,(PREVCH) ;Get the previous character
IFANOT CR,GETCH1
LD A,10 ;Get a LF character
LD (PREVCH),A ;Reset the previous character
LD L,A ;Put it into HL
LD H,0
RET ;Return to the caller
GETCH1 EQU $
LD HL,(MEMSTR)
LD A,H
OR L
JR Z,GETCH2
LD A,(HL)
INC HL
LD (MEMSTR),HL
IFZ GETCH4
JR GETCH3
GETCH2 EQU $
LD DE,FCB ;Get the File Control Block
CALL XGET ;Get a character into A
JR NZ,GETCH4 ;Jump to EOF on error
LD IX,STRANS ;Get the pointer
CALL INCKTRANS ;Increment the character count
GETCH3 EQU $
LD (PREVCH),A ;Set the previous character
LD L,A ;Put it into HL
LD H,0
RET ;Return
GETCH4 EQU $
LD A,0FFH ;Set the EOF flag
LD (EOFLAG),A
LD (PREVCH),A ;Reset the previous character flag
LD L,A ;Make HL 16bits wide -1
LD H,A
RET ;Return to caller
;
; Put the next character to the output file. We convert CRLF to CR
; IFF X packets are not active, and binary mode is not active
;
PUTCH PUSH HL
PUSH BC ;Save the register
LD C,A ;Save the character to output
LD A,(PREVCH) ;Get the previous character
IFANOT CR,PUTCH1
LD A,(DISFLG) ;Check if we are doing X packets
IFZ PUTCH1
LD A,(FILTYPE) ;Doing D packets, so check file mode
OR A
JR NZ,PUTCH1
LD A,C
IFA 10,PUTCH2
PUTCH1 LD A,C ;Get the character to output
LD (PREVCH),A ;Make it the new previous
LD HL,(OUTADDR) ;Get the output routines address
CALL CALLHL ;Call the output routine
PUTCH2 POP BC ;Restore the stack
POP HL
RET ;Return to caller
;
; Put A into the location pointed to by CBFPTR, and increment the
; pointer to point to the next location
;
PUTCBF LD HL,(CBFPTR) ;Get the pointer
PUTHL A
LD (CBFPTR),HL ;Store the new pointer value
RET ;Return
;end of file
<<< m4rmt.asm >>>
; M4RMT/ASM
; REMOTE KERMIT COMMAND
REMOTE LD A,CMKEY
LD DE,RMTTAB
CALL COMND
JP KERMT2
LD C,A ;SAVE THE TYPE
CALL NEWLIN
LD B,0
LD HL,RMTJTB ;GET THE JUMP TABLE
ADD HL,BC ;COMPUTE THE ADDRESS
LD A,'G'
LD (PKTTYPE),A ;Set to generic packet
JP (HL)
; REMOTE COMMAND JUMP TABLE
RMTJTB JP RMTCWD ;CHANGE WORKING DIRECTORIES
JP RMTDEL ;DELETE A FILE
JP RMTDIR ;DISPLAY A DIRECTORY
JP RMTDSK ;DO A REMOTE DISK ALLOCATION
JP RMTHLP ;GET REMOTE HELP
JP RMTHST ;DO REMOTE HOST COMMAND
JP RMTKER ;DO REMOTE KERMIT COMMAND
JP RMTWHO ;RUN A REMOTE PROGRAM
JP RMTREN ;SEND DATA TO A REMOTE PROGRAM
JP RMTTYPE ;DISPLAY A REMOTE FILE
JP RMTCOPY ;Copy a file
JP RMTMSG ;Send a message
JP RMTSET ;Set a variable
JP RMTQUERY ;Query a variable
JP RMTCLOSE ;Close the log
JP RMTSEND ;Send the log
JP RMTSTART ;Start logging
JP RMTSTOP ;Stop logging
JP RMTLOGIN ;Login to dedicated server
JP RMTPRG ;Remote program manipulation
JP RMTSRV ;Remote server status query
;
; DO A GENERIC REMOTE COMMAND
;
GENCMD LD DE,RMTDATA ;Set the initial destination
LD B,0 ;Set the initial counters
LD (GENTYPE),A ;Save the type
IFA 'J',GENCMD1 ;Jump if journaling
IFANOT 'V',GENCMD2 ;Jump if not variable
GENCMD1 LD A,C ;Get the second attribute
LD (DE),A ;Store it
INC DE ;Point ahead
INC B ;Plus one for the extra attribute
GENCMD2 LD C,0 ;Reset the beginning field length
GENCMD3 LD (INITRMT),DE ;Save the values
LD (INITCNT),BC
CALL ENCFLDS ;Get the input fields
GENCMD5 LD A,'1' ;SET CURRENT CHECK SUM
LD (CURCHK),A
XOR A ;Set the packet number to zero
LD (ARGBLK),A
NSTATE 'I' ;Set the state to I-initiate
CALL INIT ;Initialize buffers
LD HL,0 ;Set packet count to zero
LD (NUMPKT),HL
LD (NUMRTR),HL ;Reset number of retries
XOR A ;Set mode to display on screen
LD (DISFLG),A
LD (PKTNUM),A ;Zero current packet number
LD (NUMTRY),A ;Zero retries for current packet
LD (CZSEEN),A
CALL CLRPRT
CALL PROTO
JP KERMIT
;
; State G of the protocol. Build a G or C packet, and send it
;
DOGEN EQU $
CALL CHKTRYS ;Check the retry count
LD A,(PKTNUM) ;Set the packet number to current
LD (ARGBLK),A
LD HL,FILBUF ;Transfer data to the buffer
LD DE,DATA ;Get the DATA area
LD A,(PKTTYPE) ;Get the requested type, 'G' or 'C'
IFA 'C',DOGEN6 ;If COMMAND then jump
INC DE ;Point to data+1 if not remote host
DOGEN6 LD A,(GENLEN) ;Get the length
IFZ DOGEN1 ;Jump if no length
LD C,A ;Make BC the count
LD B,0
LDIR ;Move the bytes
DOGEN1 LD C,A ;Store the length
LD A,(PKTTYPE) ;Check the type again
IFA 'C',DOGEN7 ;If COMMAND then jump
LD A,(GENTYPE) ;Get the GENERIC type
LD (DATA),A ;Store it
INC C ;Add one to DATA length
LD A,'G' ;Send a generic packet
DOGEN7 PUSH AF ;Save the packet type
LD A,C ;Get the length of DATA
LD (ARGBLK+1),A ;Store it
LD A,'1' ;Always 1 character checksum
LD (CURCHK),A
LD A,(CHKTYP) ;Get the desired checksum type
LD (INICHK),A ;Save it for later
POP AF ;Get the packet type back
CALL SPACK ;Send the packet
JP ABORT ;Abort on an error
RPACKET ;Receive a packet
IFANOT 'S',DOGEN2 ;Skip if not send_init
LD A,(ARGBLK+1) ;Get the length
LD HL,DATA ;Get the DATA area
CALL SPAR ;Get parameters from packet
LD HL,DATA ;Get the DATA area
CALL RPAR ;Put our capabilities in
LD (ARGBLK+1),A ;Store the length that is returned
SPACKET 'Y' ;Send ACK with parameters
LD A,(INICHK) ;Get the requested checksum type
LD (CURCHK),A ;Store it as current
NSTATE 'f' ;Set state to file receive
RET ;Return to protocol switch
DOGEN2 IFANOT 'X',DOGEN3 ;X packet? Jump if not
CALL SETUPDIS ;Set up for terminal display
CALL PRTPKTOUT ;Print the packet contents
CALL DOINC ;Increment everything
LD (ARGBLK+1),A ;A is zero, so use for zero length
SPACKET 'Y' ;Send ACK
NSTATE 'd' ;Set state to receive DATA
RET
;
DOGEN3 IFANOT 'Y',DOGEN4 ;Jump if not ACK
CALL NEWLIN ;Get a new line for data
CALL PRTPKTOUT ;Print the packets contents on screen
NSTATE 'C' ;Set state to complete
RET ;Return to proto switch
;
DOGEN4 CP 'N' ;Was it NAK?
RET Z ;If so, stay in this state
IFANOT 'E',DOGEN5 ;If not Error packet, then go
CALL ERROR ;Print error message
CALL NEWLIN ;Get a new line
JP KERMIT ;Get a new command
;
DOGEN5 STROUT UNKNOWN ;Print unknown packet type message
XOR A
LD (ARGBLK+1),A ;Set DATA length to zero
SPACKET 'E' ;Send an error packet
JP KERMIT ;Get a new command
;
; Do remote directory
;
RMTDIR EQU $
GENCASE 'D',1
;
; Remote delete file
;
RMTDEL EQU $
GENCASE 'E',1
;
; Remote disk utilization
;
RMTDSK EQU $
GENCASE 'U',1
;
; Remote Help
;
RMTHLP EQU $
GENCASE 'H',1
;
; Remote Program control
;
RMTPRG EQU $
GENCASE 'P',2
;
; Remote Kermit Command
;
RMTKER EQU $
GENCASE 'P',1
;
; Remote type command
;
RMTTYPE EQU $
GENCASE 'T',1
;
; Remote who command
;
RMTWHO EQU $
GENCASE 'W',2
;
; Remote change directory
;
RMTCWD EQU $
GENCASE 'C',2
;
; Remote rename a file
;
RMTREN EQU $
GENCASE 'R',2
;
; Remote copy a file
;
RMTCOPY EQU $
GENCASE 'K',2
;
; Remote send a message
;
RMTMSG EQU $
GENCASE 'M',2
;
; Remote set a variable
;
RMTSET EQU $
LD C,'S'
GENCASE 'V',2
;
; Remote query a variable
;
RMTQUERY EQU $
LD C,'Q'
GENCASE 'V',2
;
; Remote close the log file
;
RMTCLOSE EQU $
LD C,'c'
GENCASE 'J',1
;
; Remote send log file
;
RMTSEND EQU $
LD C,'s'
GENCASE 'J',1
;
; Remote start logging
;
RMTSTART EQU $
LD C,'+'
GENCASE 'J',1
;
; Remote stop logging
;
RMTSTOP EQU $
LD C,'-'
GENCASE 'J',1
;
; Remote login
;
RMTLOGIN EQU $
GENCASE 'l',3
;
; Remote server status query
;
RMTSRV EQU $
GENCASE 'Q',1
;
; Remote host command
;
RMTHST EQU $
LD DE,FILBUF
LD A,CMTXT
CALL COMND
JP KERMT2
LD (TEMP4),A
LD A,CMCFM
CALL COMND
JP KERMT3
LD A,(TEMP4)
LD (GENLEN),A
LD C,A
LD B,0
LD HL,FILBUF
ADD HL,BC
LD (HL),0
LD A,1
LD (FLDLEN),A
LD A,'C'
LD (PKTTYPE),A
JP GENCMD5
;
; Get users response, and put it into the buffer
;
ENCFLDS LD A,CMTXT
LD DE,DATA ;Get the text
CALL COMND
JP KERMT2
CALL ENCOLEN ;Length encode each argument
JP GETFIELD1 ;On error jump
LD HL,RMTDATA ;Get the input buffer
CALL ENCSTR ;Encode the contents
LD A,(SIZE) ;Get the length
LD (GENLEN),A ;Save it for later
RET ;Return
;
GETFIELD1 EQU $ ;Bad string found in encodelen
STROUT TOOLONG ;Print string too long message
JP KERMIT ;Abort completely
;
; Protocol switch code
;
PROTO EQU $
LD A,(STATE)
SWITCH 'D',SDATA ;Send data
SWITCH 'F',SFILE ;Send file
SWITCH 'T',SNDTRAN ;Transition from 'F' to 'D'
SWITCH 'Z',SEOF ;Send EOF
SWITCH 'S',SINIT ;Send init
SWITCH 'B',SEOT ;End of transmittion
SWITCH 'C',COMP ;Completed
SWITCH 'A',SABORT ;Abort
SWITCH 'd',RDATA ;Receive data
SWITCH 'f',RFILE ;Receive file
SWITCH 't',RECTRAN ;Transition from 'f' to 'd'
SWITCH 'R',RINIT ;Receive init
SWITCH 'r',RINITF ;Receive init with filename (GET command)
SWITCH 'G',DOGEN ;Generic server command
SWITCH 'I',IINIT ;Generic init packet
CALL SABORT ;Bad protocol state
JP KERMIT ;Abort
;
; SEND I-INITIATE
;
IINIT CALL CHKTRYS ;Check retry threshold
LD A,'1' ;RESET TO USE SINGLE CHARACTER CHECKSUM
LD (CURCHK),A ;FOR STARTUP
LD A,(CHKTYP) ;GET OUR DESIRED BLOCK CHECK TYPE
LD (INICHK),A ;Store it as the initial value
LD HL,DATA ;GET A POINTER TO OUR DATA BLOCK.
CALL RPAR ;SET UP THE PARAMETER INFORMATION.
LD (ARGBLK+1),A ;SAVE THE NUMBER OF ARGUMENTS.
LD A,(PKTNUM) ;GET THE PACKET NUMBER.
LD (ARGBLK),A
SPACKET 'I' ;Send the I packet
RPACKET ;Get the answer packet
CP 'Y' ;Is it an ACK?
JP NZ,IINIT3 ;IF NOT TRY NEXT.
CALL CHKBLK
RET NZ ;IF NOT TRY AGAIN.
CALL DOINC
LD A,(ARGBLK+1) ;GET THE NUMBER OF PIECES OF DATA.
LD HL,DATA ;POINTER TO THE DATA.
CALL SPAR ;READ IN THE DATA.
LD A,(INICHK) ;GET THE AGREED UPON BLOCK-CHECK-TYPE
LD (CURCHK),A ;STORE AS TYPE TO USE FOR PACKETS NOW
NSTATE 'G'
RET
IINIT3 IFANOT 'N',IINIT4 ;NAK?
CALL UPDRTR ;UPDATE THE NUMBER OF RETRIES.
RET
IINIT4 CP 'E' ;IS IT AN ERROR PACKET.
JP NZ,ABORT ;JUMP IF NOT
LD A,80 ;SET UP ALL DEFAULT PARAMETERS
LD (SPSIZ),A
XOR A
LD (SPAD),A
LD (SPADCH),A
LD A,13
LD (SEOL),A
LD A,'1'
LD (CURCHK),A
LD A,'#'
LD (SQUOTE),A
NSTATE 'G'
RET
;
; This routine encodes the length of the blank separated fields
; into a packet for the generic routines. If there are more
; blank separated fields than FLDLEN says there should be, the
; remaining fields are added to the end of the last field,
; separated by blanks.
;
ENCOLEN LD HL,DATA ;Get the source
LD DE,(INITRMT) ;Get the initial location
LD BC,(INITCNT) ;Get the initial counters
PUSH DE ;Save the store address for length
PUSH BC
INC DE ;Point to where the data goes
LD A,(FLDLEN) ;Get the number of fields
LD B,A ;Put it into the counter
POP AF ;Get the initial length
LD (FLDLEN),A ;Set the length to zero initially
ENCLEN1 LD A,(HL) ;Get a character
IFANOT 20H,ENCLEN4 ;Jump if not space
ENCLEN2 INC HL ;Point to next character
IFA (HL),ENCLEN2 ;Loop while we are looking at a space
DJNZ ENCLEN3 ;See if we have done all fields
INC B ;Reset the counter back to one if so
LD (DE),A ;Store a space
INC DE ;Point to next place to store at
INC C ;Increment the field length
JR ENCLEN1 ;Process next character
ENCLEN3 LD A,C ;Get the field length
TOCHAR ;Make it printable
EX (SP),HL ;Get the store address for the length
LD (HL),A ;Store the length byte
POP HL ;Restore the old HL
PUSH DE ;Save the new length byte address
INC DE ;Point to the data store address
LD C,0 ;Reset the count of characters
LD A,(FLDLEN) ;Get the total length
INC A ;Add one to the length
LD (FLDLEN),A ;Store the new length
JR NZ,ENCLEN1 ;Continue if OK
POP DE ;Restore the stack
RET ;Return error
ENCLEN4 JR C,ENCLEN5 ;If this is a control character then stop
INC C ;Correct for the comming decrement
LDI ;Move one char, and increment counter
INC C ;Plus one more for the length
LD A,(FLDLEN) ;Get the length
INC A ;Add one for current character
LD (FLDLEN),A ;Store the new length
JR NZ,ENCLEN1 ;Top of the loop if no overflow
POP DE ;Restore the stack
RET ;Return error
ENCLEN5 POP HL ;Get the length address
LD A,C ;Get the length
TOCHAR ;Make it printable
LD (HL),A ;Store this fields length
XOR A ;Terminate the packet
LD (DE),A
LD A,(FLDLEN) ;Get the overall length
LD (GENLEN),A ;Save it for later
OR A ;Is it a null length string?
JP Z,RSKP ;Return if it is
INC A ;Add one to length for field length byte
CP MAXPKT-4 ;Too big for packet?
RET P ;Return error if string too long
LD (GENLEN),A ;Save it
JP RSKP ;Return to the caller
;end of file
<<< m4send.asm >>>
; M4SEND/ASM
;
; SEND COMMAND
;
SEND EQU $
CALL NEWLIN
LD A,CMTXT ;PARSE A TEXT STRING
LD DE,MFNBUF ;GIVE THE ADDRESS FOR THE STRING
PUSH DE ;Save it
CALL COMND ;GET THE INPUT
JP KERMT2 ;GIVE UP ON BAD PARSE.
POP HL ;Get the pointer
LD (MFNPTR),HL ;Save it as the start
LD A,1 ;Set the log names flag
LD (LOGNAMES),A
CALL BUILDF ;Build a list doing wildcarding
LD A,(FILECNT) ;Get the number of files
IFNZ SEND11 ;Jump if some files were found
STROUT NOFILES ;Print the message
JP KERMIT
SEND11 LD (MFNPTR),HL ;Save the start of the found list
CALL MFNAME ;Get the next from the list
JR NC,SEND14 ;Jump if got a name
CALL NEWLIN
LD A,19 ;Issue system error, Illeagal filename
CALL XERROR
JP KERMIT ;GET A NEW COMMAND
SEND14 CALL INIT ;Clear the line and initialize buffers
XOR A
LD (PKTNUM),A
LD (NUMTRY),A ;SET THE NUMBER OF TRIES TO ZERO.
LD HL,0
LD (NUMPKT),HL ;SET THE NUMBER OF PACKETS TO ZERO.
LD (NUMRTR),HL ;SET THE NUMBER OF RETRIES TO ZERO.
LD (KTRANS),HL
LD A,'1' ;RESET TO USE SINGLE CHARACTER CHECKSUM
LD (CURCHK),A ;FOR STARTUP
NSTATE 'S'
LD (DISFLG),A ;Put in something non zero
CALL CONDCHR ;Display starting sendinit character 'S'
CALL CLRPRT ;CLEAR OUT ANY STACKED NAKS
STROUT HELPMSG
CALL PROTO ;Do protocol states
JP KERMIT ;Return to Kermit
;
; SEND ROUTINES
; SEND INITIATE
;
SINIT CALL CHKTRYS ;Check retry threshold
LD A,'1' ;RESET TO USE SINGLE CHARACTER CHECKSUM
LD (CURCHK),A ;FOR STARTUP
LD A,(CHKTYP) ;GET OUR DESIRED BLOCK CHECK TYPE
LD (INICHK),A
LD HL,DATA ;GET A POINTER TO OUR DATA BLOCK.
CALL RPAR ;SET UP THE PARAMETER INFORMATION.
LD (ARGBLK+1),A ;SAVE THE NUMBER OF ARGUMENTS.
LD A,(NUMPKT) ;GET THE PACKET NUMBER.
LD (ARGBLK),A
SRPACK 'S' ;Do send init, and get response
IFANOT 'Y',SINIT3 ;Was it an ACK? Jump if not
CALL CHKBLK
RET NZ ;IF NOT TRY AGAIN.
CALL DOINC ;Increment and reset
LD A,(ARGBLK+1) ;GET THE NUMBER OF PIECES OF DATA.
LD HL,DATA ;POINTER TO THE DATA.
CALL SPAR ;READ IN THE DATA.
LD A,(INICHK) ;GET THE AGREED UPON BLOCK-CHECK-TYPE
LD (CURCHK),A ;STORE AS TYPE TO USE FOR PACKETS NOW
NSTATE 'F' ;Set the state
CALL CONDCHR
CALL GETFIL ;Open the file name given in FCB
JP SNDABORT ;Something is wrong if come to here
RET ;Next state in protocol
;
; Come here on bad answer to S packet
;
SINIT3 CP 'N' ;NAK?
JP NZ,BADERROR ;If not, then it is a fatal error
CALL CONDCHR ;Output N character
RET ;Back to protocol
;
; Terminate a transaction log because of an error
;
;
; SEND FILE HEADER
;
SFILE CALL CHKTRYS ;Check retry threshold
XOR A ;CLEAR A
LD (CZSEEN),A
LD DE,DATA ;GET A POINTER TO OUR DATA BLOCK.
LD HL,MFREQ ;Get filename
LD BC,255 ;B must be zero, C must be big for LDI
SF1 LD A,(HL)
IFA '/',SF2
IFA ':',SF4
IFALT ' ',SF4
LDI
INC B
JR SF1
SF2 LD (HL),'.'
LDI
INC B
SF3 LD A,(HL)
IFALT ' ',SF4
IFA ':',SF4
LDI
INC B
JR SF3
SF4 EQU $
LD (DATPTR),DE
LD (FCBPTR),HL
LD A,B ;NUMBER OF CHAR IN FILE NAME.
LD (ARGBLK+1),A
EX DE,HL
LD (HL),EOS ;Put in the print terminator
LD A,(PKTNUM) ;GET THE PACKET NUMBER.
LD (ARGBLK),A
SRPACK 'F' ;Send file header and get response
IFANOT 'Y',SFILE2 ;Jump if not an ACK
CALL CHKBLK ;Check packet number
RET NZ ;Return if not the right one
SFIL14 CALL DOINC ;Increment packet count
SFIL15 CALL RSETPKT ;Reinitialize GETPKT()
CALL GTCHR
JP SFIL16 ;ERROR GO SEE IF ITS EOF.
JR SFIL17 ;GOT THE CHARS, PROCEED.
SFIL16 CP 0FFH ;IS IT EOF?
JP NZ,SNDABORT ;IF NOT GIVE UP.
NSTATE 'Z' ;Set EOF state
CALL CONDCHR
RET
SFIL17 EQU $
NSTATE 'T' ;Set state to data send
LD (DISFLG),A ;Make sure display is on
RET
SFILE2 CP 'N' ;NAK?
JP NZ,BADERROR ;TRY IF ERROR PACKET.
CALL CONDCHR ;Display the packet character
CALL CHKBLKINC ;Check NAK for packet N+1
RET NZ ;If not, then try to resend
JR SFIL14 ;As good as an ACK, join the ack code
;
; Send transition state from Send file to Send data
;
SNDTRAN EQU $
STROUT KERSND ;Print SENDING message
STROUT TFILNAM ;Print the file name
LD A,(TRANLOG) ;Check if logging active
IFZ SNDTRAN2 ;If not, then jump
LD DE,TRFCB ;Get the log file FCB
TRLOG KERSND,SNDTRAN1 ;Log the SENDING=> message
TRLOG TFILNAM,SNDTRAN1 ;Log the file name
TRLOG TIMEMES,SNDTRAN1;Log the time: message
CALL PRTTIME ;Print the time
JR SNDTRAN2 ;Join other code
;
; Close up on a logging error
;
SNDTRAN1 EQU $
XOR A ;Reset the log open flag
LD (TRANLOG),A
LD DE,TRFCB ;Close the log file
CALL XCLOSE
SNDTRAN2 EQU $
NSTATE 'D' ;Set the state to SEND DATA
RET
;
; SEND DATA
;
SDATA CALL CHKTRYS ;Check the retry threshold
LD DE,DATA ;Get the data area
LD HL,FILBUF ;Get the file buffer
LD A,(SIZE) ;Get the number of bytes encoded
IFZ SDAT11 ;Jump if there are none
LD C,A ;Put LSB into C
LD B,0 ;Zero B
LDIR ;Move the bytes
SDAT11 LD A,(SIZE) ;Get the number of bytes back
LD (ARGBLK+1),A ;Store it as the length
LD A,(PKTNUM) ;Get the current packet number
LD (ARGBLK),A ;Put it in the packet
LD A,'D' ;Get the packet type
CALL SPACK ;Send a data packet
JP SNDABORT ;Abort if send fails
LD A,(NUMPKT) ;See if time to log progress
AND 3 ;Every 4 packets
LD A,'.' ;Get the character
CALL Z,CONDCHR ;Output if it is time
RPACKET ;Get a packet
IFANOT 'Y',SDATA2 ;Jump if not an ACK
CALL CHKBLK ;See if proper packet number
RET NZ ;Wait for more if not right number
CALL DOINC ;Increment and reset
LD A,(ARGBLK+1) ;Get the length of packet
IFANOT 1,SDAT15 ;Jump if not 1 character
LD A,(DATA) ;Get the character sent in ACK
IFANOT 'Z',SDAT14 ;Is it end of file? Jump if not
LD (CZSEEN),A ;Save it
JR SDAT15 ;Continue
SDAT14 IFANOT 'X',SDAT15 ;Was it EOT? Jump if not
LD (CZSEEN),A ;Save it
SDAT15 LD A,(CZSEEN) ;Get the character
IFZ SDAT12 ;Jump if nothing there
CALL CONDCHR ;Display the character
NSTATE 'Z' ;Set the state to EOF
RET ;Return to protocol
;
SDAT12 CALL GTCHR ;Get more data from input file
JP SDAT13 ;Jump if error occurs (might be EOF)
RET ;Continue sending
;
SDAT13 CP 0FFH ;Was the file error EOF?
JP NZ,SNDABORT ;If not, then file error, so abort
NSTATE 'Z' ;Set state to EOF
CALL CONDCHR ;Output the state
RET ;Return to protocol
;
SDATA2 CP 'N' ;Is it a NAK?
JP NZ,BADERROR ;Nope, check next type
CALL CONDCHR ;Display packet type
CALL CHKBLKINC ;NAK this packet plus one?
JR Z,SDAT12 ;Just as good as an ACK, Join ACK code.
CALL UPDRTR
RET
;
; Send the EOF packet
;
SEOF CALL CHKTRYS ;Check the retry threshold
CALL INITBLK ;Initialize ARGBLK
LD A,(CZSEEN) ;Check for ABORT
IFZ SEOF14 ;If not aborted, then keep going
LD A,(TRANLOG) ;Check if logging active
IFZ SEOF10 ;Jump if no logging
LD DE,TRFCB ;Get the log file FCB
TRLOG TRANCANC,SEOF19 ;Log the canceled message
SEOF10 LD A,(DISCARD) ;Should the file be deleted?
IFZ SEOF11 ;Skip delete if user want to keep it
LD A,'D' ;Tell other end to discard packet
LD (DATA),A ;Store the delete character
LD A,1 ;Length is one character
SEOF11 LD (ARGBLK+1),A ;Store the length
SEOF14 SRPACK 'Z' ;Send EOF, and get a response
IFANOT 'Y',SEOF2 ;Jump if not an ACK
CALL CHKBLK ;Check the packet number
RET NZ ;Return if not correct one
SEOF12 CALL DOINC ;Increment and reset
CALL CHKFCB ;Check for file, don't close *SO
CALL Z,XCLOSE ;Conditionally close it
LD A,(CZSEEN) ;Did the user force us to stop?
IFA 'Z',SEOF13 ;Jump if EOF was signaled by user
CALL MFNAME ;Get a new file name
JR C,SEOF13 ;Jump if no more
CALL GETFIL ;AND OPEN IT
JP SNDABORT ;SOMETHING IS WRONG, DIE.
XOR A ;CLEAR A
LD (CZSEEN),A
NSTATE 'F' ;Set state to file send
CALL CONDCHR
LD IX,STRANS ;Update transmission information
CALL UPDTRANS
RET ;Continue protocol
;
SEOF13 NSTATE 'B' ;Set state to EOT
CALL CONDCHR
LD IX,STRANS ;Update the transmission info
CALL UPDTRANS
RET
;
SEOF2 CP 'N' ;NAK?
JP NZ,BADERROR ;TRY AND SEE IF ITS AN ERROR PACKET.
CALL CONDCHR
CALL UPDRTR ;UPDATE THE NUMBER OF RETRIES.
CALL CHKBLKINC
RET NZ ;IF NOT GO TRY AGAIN.
JR SEOF12 ;Just as good as an ACK
;
SEOF19 XOR A ;Reset the log open flag
LD (TRANLOG),A
LD DE,TRFCB ;Close the file
CALL XCLOSE
JP SEOF10 ;Join other code
;
; Send EOT packet
;
SEOT CALL CHKTRYS ;Check the retry threshold
CALL INITBLK ;Initialize ARGBLK
SRPACK 'B' ;Send END of BATCH and get response
IFANOT 'Y',SEOT2 ;Jump if not ACK
CALL CHKBLK ;Check the packet number
RET NZ ;Return if not correct
SEOT12 CALL DOINC ;Increment and reset
NSTATE 'C' ;Set state to complete
RET
SEOT2 CP 'N' ;NAK?
JP NZ,BADERROR ;IS IT ERROR.
CALL CONDCHR
CALL UPDRTR ;UPDATE THE NUMBER OF RETRIES.
CALL CHKBLKINC
JP Z,SEOT12 ;Good as an ACK, so continue
OR A ;Is the other end starting over?
JR Z,SEOT12
RET
;
; Check the retry threshold
;
CHKTRYS EQU $ ;Check retry threshold
LD A,(MAXTRY) ;Get the maximum
LD B,A ;Save
LD A,(NUMTRY)
IFALT B,CHKTRYS1 ;Jump if not at limit
POP DE ;Remove the callers return addr
LD DE,ERMS14 ;Print the error message
CALL ERROR3
JP SNDABORT ;CHANGE THE STATE TO ABORT.
CHKTRYS1 EQU $
IFZ CHKTRYS2 ;Jump if first try
PUSH AF ;Save the count
LD A,'%' ;Print retrying message
CALL CONDCHR
POP AF ;Get the count back
CHKTRYS2 EQU $
INC A ;Increment it
LD (NUMTRY),A ;Save the new count
RET
;
; Increment the packet count modulo 64, A already has the old one.
;
INCPKT INC A
AND 3FH
LD (PKTNUM),A
RET
;
; Move numtry to oldtry and zero numtry
;
NUM2OLD EQU $
LD A,(NUMTRY) ;GET THE NUMBER OF TRIES.
LD (OLDTRY),A ;SAVE IT.
XOR A
LD (NUMTRY),A ;RESET THE NUMBER OF TRIES.
RET
;
; Increment display packet count
;
INCDISPKT EQU $
LD HL,(NUMPKT)
INC HL
LD (NUMPKT),HL
RET
;
; Do several things
;
DOINC CALL INCPKT
CALL INCDISPKT
JP NUM2OLD
;
; Check the packet number 'received plus 1' verses that sent
; return their relation, eg <, >, =, <>. This is used as a
; method to determine that a NAK for packet N+1 is equivelent
; to an ACK for packet N.
;
CHKBLKINC EQU $
LD A,(PKTNUM) ;Get the current packet number
INC A ;Plus one
LD B,A ;Save it
LD A,(ARGBLK) ;Get the packet number returned
CP B ;Are they equal?
RET ;Return the flags setting
;
; Conditionally display the character in A based on the value
; of DISFLG. This is used to print the characters during transfers
; that show the status of the transfer. eg '.', 'Q', 'S', 'Z', etc
;
CONDCHR EQU $
LD C,A ;Save the character
LD A,(DISFLG) ;Check if should display the character
OR A ;Set the flags
RET Z ;Return if flag not set
LD A,C ;Get the character back
JP CONOUT ;Print the terminal on the console
;
RSETPKT EQU $
XOR A ;GET A ZERO.
LD (EOFLAG),A ;INDICATE NOT EOF.
LD (SIZE),A ;Nothing in packet buffer
LD (OSIZE),A ;No old length
LD (LEFTOVER),A ;No leftovers from previous packet
LD (RPTCNT),A ;No repeated characters yet
LD (PREVCH),A ;Reset any previous character knowledge
LD HL,-1 ;Set NO next character
LD (NEXT),HL
LD (CH),HL
RET
;
BADERROR EQU $
CP 'E' ;IS IT AN ERROR PACKET.
JP NZ,SNDABORT
CALL ERROR
JP SNDABORT
;
INITBLK EQU $
LD A,(PKTNUM) ;GET THE PACKET NUMBER.
LD (ARGBLK),A
XOR A
LD (ARGBLK+1),A ;NO DATA.
RET
PRTTIME EQU $
PUSH AF ;Save the regs
PUSH BC
PUSH HL
PUSH DE ;Save the FILE FCB
LD HL,CLBUF ;Get the character buffer
PUSH HL ;Save the address
CALL XTIME ;Get the time
LD (HL),CR ;Get a new line
INC HL ;Point to next pos
LD (HL),EOS ;Terminate the string
POP HL ;Get the string to print back
POP DE ;Get the log file FCB
CALL OUTLOG
CALL TIMCLOSE ;Close up if error occurs
POP HL ;Restore the regs
POP BC
POP AF
RET
;
TIMCLOSE EQU $
XOR A ;Reset the file open flag
LD (LOGTRAN),A
LD DE,TRFCB ;Get the FCB
JP XCLOSE ;Close the file and return.
; end of file
<<< m4set.asm >>>
; m4set/asm
;
;THIS IS THE SET COMMAND.
;
SETCOM LD DE,SETTAB ;Parse a keyword for set table
LD A,SHLEN/3 ;Patch the number in the table
LD (SETTAB),A ;Store the value
LD A,MXSLEN ;Patch the other value
LD (SETTAB+1),A
LD A,CMKEY ;Select keyword parse
CALL COMND ;Parse it
JP KERMT2 ;Quit on an error
LD HL,SETJTB ;Get the jump table address.
LD C,A
LD B,0
ADD HL,BC
JP (HL)
;SET COMMAND JUMP TABLE
SETJTB JP ESCAPE ;SET ESC
JP LOCAL ;SET LOCAL
JP SETEIGHT ;SET EIGHT-BIT-QUOTING
JP SETFILE ;SET FILE
JP SETBLK ;SET BLOCK-CHECK-TYPE
JP SETEMUL ;SET emulation
JP PRINTR ;set printer
JP SETBUG ;SET DEBUG
JP SETDSK ;SET DEFAULT DISK
JP SETBEL ;SET BELL ON OR OFF
JP SETSND ;SET SEND PARAMETERS
JP SETREC ;SET RECEIVE PARAMTERS
JP SETKEY ;SET A KEY FOR TRANSLATION
JP SETFLO ;SET FLOW CONTROL
JP SETINP ;SET INPUT PARAMETERS
JP SETOTP ;SET OUTPUT PARAMETERS
JP SETTAK ;Set take display
SHLEN EQU $-SETJTB ;OFFSET FOR SHOW ALL
;
; Set file dispostion
;
SETDISP LD DE,DISPTAB ;Get the parse table
LD A,CMKEY
CALL COMND ;Parse a keyword
JP KERMT2
LD (TEMP1),A ;Save it
LD A,CMCFM ;Get a confirm
CALL COMND
JP KERMT3
LD A,(TEMP1)
LD (DISCARD),A ;Set the value
JP KERMIT
;
; Set take file display
;
SETTAK SETFLG TAKLOG
;
; Set input options
;
SETINP LD A,CMKEY ;GET A KEYWORD
LD DE,INPTAB ;WHERE ARE THE KEYWORDS AT?
CALL COMND
JP KERMT2 ;QUIT ON AN ERROR
LD C,A
IFANOT 0,STINP1 ;Check for first time
SETFLG CSEFLG
STINP1 CP 3
JP NZ,KERMT3
SETFLG INDSP
;
; Set output option
;
SETOTP LD A,CMKEY
LD DE,OUTTAB
CALL COMND
JP KERMT2
LD C,A
IFANOT 0,STOTP1
SETFLG ECHFLG
STOTP1 CP 3
JP NZ,KERMT3
SETFLG OTDSP
;
; Set flow control option
;
SETFLO LD DE,FLOTAB
LD A,CMKEY
CALL COMND
JP KERMT2
LD (TEMP1),A
LD A,CMCFM
CALL COMND
JP KERMT3
LD A,(TEMP1)
LD (FLOFLG),A ;STORE THE NEW STATUS
JP KERMIT
;
; Set bell on/off
;
SETBEL SETFLG BELFLG ;Set the bell ON or OFF
;
; Set block check type
;
SETBLK LD DE,BLKTAB ;GET THE BLOCK-CHECK TABLE
LD A,CMKEY ;PARSE A KEYWORD
CALL COMND ;GO GET IT
JP KERMT2 ;COULDN'T, COMPLAIN
LD (TEMP1),A ;SAVE THE PARSED ITEM
LD C,A
LD A,CMCFM ;WANT TO END THE COMMAND
CALL COMND ;GO DO IT
JP KERMT3 ;GIVE UP
LD A,(TEMP1) ;GET THE VALUE BACK
LD (CHKTYP),A ;SAVE DESIRED CHECKSUM TYPE
JP KERMIT ;GO GET ANOTHER COMMAND
;
; Set send options
;
SETSND XOR A ;SET SEND/RECEIVE TO SEND
JR SETSOR
;
; Set receive options
;
SETREC LD A,1 ;SET SEND/RECEIVE TO RECEIVE
;
; Common code that uses the contents of A at this point to
; control where the set value is stored. All of the SEND/RECV
; options are set up in memory together, so that to give a
; particular send option a value, it is stored directly. The
; corresponding recv option is one byte in memory beyond the
; send option, so the flag (What is in A) is checked, and the
; destination address is incremented if A is non zero
;
; Memory looks like this
;
; SEOL DB 13
; REOL DB 13
; SSOH DB 1
; RSOH DB 1
;
SETSOR LD (SORFLG),A ;STORE THE FLAG
LD DE,STSNTB ;GET THE PARSE TABLE
LD A,CMKEY
CALL COMND ;PARSE SOMETHING
JP KERMT2 ;ABORT
LD HL,STSJTB ;GET THE JUMP TABLE
LD C,A
LD B,0
ADD HL,BC
JP (HL)
STSJTB JP STPDCH ;SET PAD CHARACTER
JP STPAD ;SET PADDING ON/OFF
JP SSOFP ;SET START OF PACKET
JP STIMEO ;SET TIME OUT
JP SSEOL ;SET END OF LINE
JP SSQUOT ;SET QUOTE CHARACTER
JP SSTURN
;
; Set the padding. Note that it is only done on output, so
; SET RECEIVE PADDING doesn't make sense.
;
STPAD LD A,CMNUM ;GET A LENGTH COUNT
CALL COMND ;PARSE A VALUE
JP KERMT3 ;NOT CONFIRMED ON AN ERROR
OR A ;CHECK FOR NO NUMBER
JP Z,KERMT2 ;SAY AMBIGUOUS
LD A,D ;CHECK FOR OVERFLOW
IFZ STPD10 ;Go if none
LD DE,OUTRNG
CALL PRTSTR
JP KERMIT
STPD10 LD A,E
LD (SPAD),A ;SET THE STATUS
JP KERMIT ;GET A NEW COMMAND
;
; Set the padding character. Also applys to SEND only!
;
STPDCH LD HL,SPADCH ;GET THE ADDRESS TO STORE AT
SOR010 LD (SORLOC),HL ;SAVE IT FOR LATER
LD A,CMNUM ;GET A DECIMAL NUMBER
CALL COMND
JP KERMT3
OR A ;CHECK FOR NO NUMBER
JP Z,KERMT2 ;SAY AMBIGUOUS
LD A,D ;CHECK FOR TOO BIG
IFZ PDCH2 ;Go if ok
LD DE,OUTRNG ;VALUE OUT OF RANGE ERROR
CALL PRTSTR ;PRINT IT
JP KERMIT
PDCH2 LD HL,(SORLOC) ;GET WHERE TO PUT IT
LD A,(SORFLG) ;GET THE MODE, SEND/RECEIVE
OR A ;CHECK FOR SET OR RESET FLAG
CALL Z,SSVAL ;IF ZERO THEN SET RECEIVE VALUE
CALL NZ,SRVAL ;ELSE SET THE SEND VALUE
JP KERMIT ;GET A NEW COMMAND
;
; Set START-OF-PACKET (Start Of Header, SOH)
;
SSOFP LD HL,SSOHCH
JP SOR010
;
; Set turn around character
;
SSTURN LD HL,STURN
JP SOR010
;
; Set time-out value
;
STIMEO LD HL,STIME
JP SOR010
;
; Set End Of Line (or End Of Packet) character
;
SSEOL LD HL,SEOL
JP SOR010
;
; Set eighth bit quote character
;
SSQUOT LD HL,SQUOTE
JP SOR010
;
; Convert ASCII Decimal string to binary in BC, HL is the
; source buffer.
;
DECHEX JP XDECHEX
;
; Store E at HL+1
;
SSVAL INC HL
;
; Store E at HL
;
SRVAL LD (HL),E
RET
;
; Convert contents of A to ASCII string, and display
;
ANOUT PUSH HL
LD L,A
LD H,0
CALL NOUT
POP HL
RET
;
; Set the escape character
;
ESCAPE LD A,CMCFM
CALL COMND ;GET A CONFIRM.
JP KERMT3 ;DIDN'T GET A CONFIRM.
LD DE,ESCMES ;GET THE ADDRESS OF THE ESCAPE MESSAGE.
CALL PRTSTR
CALL XKEY
LD (ESCCHR),A ;STORE THE NEW ESCAPE CHARACTER.
CALL ESCPR ;Print the Verbpse description of it
JP KERMIT
;
; Set local echo status
;
LOCAL SETFLG ECOFLG
;
; Set the emulation type
;
SETEMUL LD DE,EMLTAB
LD A,CMKEY
CALL COMND
JP KERMT2
LD (TEMP1),A
LD A,CMCFM
CALL COMND
JP KERMT3
LD A,(TEMP1)
LD (EMULFLAG),A
JP KERMIT
;
; Set file-warning status
;
SETWARN SETFLG FLWFLG ;Set the file-warning flag
;
; SET FILE parse and jump
;
SETFILE LD DE,FILETAB ;Get the table of choices
LD A,CMKEY ;Select keyword parse
CALL COMND ;Parse the input
JP KERMT2 ;Abort on an error
LD C,A
LD B,0
LD HL,FILJTAB ;Get the jump table
ADD HL,BC
JP (HL) ;Go to the routine
;
; SET FILE jump table
;
FILJTAB JP SETDISP ;SET FILE DISPOSITION
JP SETTYPE ;SET FILE TYPE
JP SETWARN ;SET FILE WARNING
;
; SET FILE TYPE
;
SETTYPE LD DE,TYPETAB ;Get the table
LD A,CMKEY
CALL COMND
JP KERMT2 ;Abort on an error
LD (TEMP1),A ;Save the value
LD A,CMCFM ;Get a confirm
CALL COMND
JP KERMT3 ;Say not confirmed
LD A,(TEMP1) ;Get the value back
LD (FILTYPE),A ;Set the type chosen
JP KERMIT ;Get another command
;
; Set Printer command
;
PRINTR SETFLG PRTFLG
;
; Set status of DEBUG
;
SETBUG SETFLG DBFLG
;
; SET EIGHTH-BIT quoting status
;
SETEIGHT CALL ONOFF
LD (EBQFLG),A
JP KERMIT
;
; Get an ON/OFF value in A, with a confirm
;
ONOFF LD DE,ONTAB
ONOFFA LD A,CMKEY
CALL COMND
JP KERMT2
LD (TEMP1),A
LD A,CMCFM
CALL COMND
JP KERMT3
LD A,(TEMP1)
RET
;
; Set a KEY mapping
;
SETKEY LD A,CMNUM ;Get the key number
CALL COMND
JP KERMT2 ;Abort on error
IFZ SETKEY_5 ;Abort if no number
LD A,D ;Get the MSB must be zero
IFNZ SETKEY_4
LD A,E ;Get the LSB
LD (KEYNUM),A ;This is the key number
LD A,CMTXT ;Get the text definition
LD DE,RMTDATA ;Where to put it
LD (SOUPTR),DE ;Set the starting address
CALL COMND ;Call the parser
JP KERMT3 ;Say not confirmed
LD HL,DATA
LD (KEYPTR),HL
PUSH AF
XOR A
LD (KEYLEN),A
POP AF
IFZ SETKEY_3
SETKEY_1 CALL GETFCH ;GET A CHARACTER
JR NZ,SETKEY_3
CALL GTREAL ;GET THE ACTUAL IF IT IS SPECIAL
JP NZ,KERMIT ;Abort on bad string
LD E,A ;PUT IT IN E FOR OUTCHR
LD A,(DLYFLG) ;WAS IT A DELAY
IFZ SETKEY_2
XOR A
LD (DLYFLG),A ;RESET THE FLAG
JR SETKEY_1 ;GET A NEW CHARACTER
SETKEY_2 LD A,E ;Get the character
CALL PUTDKEY ;Put it into the buffer
JR SETKEY_1
SETKEY_3 LD HL,DATA
LD A,(KEYLEN)
LD B,A
LD A,(KEYNUM)
CALL DEFKEY
JP KERMIT
SETKEY_4 LD DE,OUTRNG
CALL PRTSTR
JP KERMIT
SETKEY_5 LD DE,KEYHELP
CALL PRTSTR
SETKEY_6 CALL CONIN
IFZ SETKEY_6
LD (KEYNUM),A
CALL VERPRT
LD DE,STRHELP
CALL PRTSTR
LD HL,DATA
LD B,0
SETKEY_7 CALL CONIN
IFZ SETKEY_7
IFA 128,SETKEY_10
LD (HL),A
CALL VERPRT
INC B
LD A,255
IFA B,SETKEY_10
INC HL
JR SETKEY_7
SETKEY_10 LD A,B
LD (KEYLEN),A
JR SETKEY_3
;
; Put the decoded value into the buffer pointer to by KEYPTR
;
PUTDKEY PUSH HL
LD HL,(KEYPTR)
LD (HL),A
INC HL
LD (KEYPTR),HL
LD HL,KEYLEN
INC (HL)
POP HL
RET
;end of file
<<< m4show.asm >>>
; m4show/asm
;
;THIS IS THE SHOW COMMAND.
;
SHOW LD A,SHLEN ;GET THE OFFSET TO OVERWRITE WITH
LD (SETTAB),A ;FIX SET TABLE FOR SHOW
LD (SETTAB+1),A
LD A,CMKEY ;Parse a keyword
LD DE,SHOTAB ;From this table
CALL COMND ;Go do it
JP KERMT2 ;Say ambiguous if nothing matches
IFA KYLEN,NOCFM ;If keyword is KEY, then special case
IFA FILLEN,NOCFM ;If keyword is FILE, then special case
LD (TEMP1),A ;SAVE THE JUMP OFFSET
LD A,CMCFM ;Get a confirm
CALL COMND
JP KERMT3 ;SAY NOT CONFIRMED ON AN ERROR
CALL NEWLIN ;Get a new line to print on
LD A,(TEMP1) ;Get the keyword value
NOCFM LD HL,SHOJTB ;Get the start of the jump table
LD C,A ;Make BC a 16-bit copy of A
LD B,0
ADD HL,BC ;HL IS WHERE WE GO
LD BC,KERMIT ;Put a return address on the
PUSH BC ;stack to simulate a call
JP (HL) ;GO DO THE ROUTINE
;
; Show command jump table. The 2 equates embedded in this table
; indicate functions which need furthur parsing. These are checked
; above, and then handled special.
;
SHOJTB JP ESCSTAT ;SHOW ESCAPE
JP ECHSTAT ;SHOW LOCAL ECHO
JP EIGSTAT ;Eight bit quoting status
FILLEN EQU $-SHOJTB
JP FILESTAT ;Show the file parameters
JP CHKSTAT ;SHOW BLOCK-CHECK-TYPE
JP EMULSTAT ;SHOW emulation status
JP PRTSTAT ;SHOW PRINTER
JP DEBSTAT ;SHOW DEBUGGING
JP DSKSTAT ;SHOW DEFAULT DISK
JP BELLSTAT ;BELL STATUS
JP RCVSTAT ;SHOW RECEIVE
JP SENDSTAT ;SHOW SEND
KYLEN EQU $-SHOJTB ;THESE 2 LINES MUST BE TOGETHER
JP KYSTAT ;SHOW A KEY TRANSLATION
JP FLOWSTAT ;SHOW FLOW CONTROL
JP SHOINP ;SHOW INPUT PARAMETERS
JP SHOOUT ;SHOW OUTPUT PARAMETERS
JP TAKESTAT ;SHOW STATUS OF TAKE DISPLAY
JP SHOALL ;SHOW ALL
;
; Show the status of several values. This is the STATUS command
;
STATUS LD A,CMCFM ;GET A CONFIRM
CALL COMND
JP KERMT3 ;QUIT ON AN ERROR
STROUT SPACSTR
LD HL,DEFTABLE+DEFTLEN-1 ;Get the end of table
LD BC,(TOPADDR) ;Get the current top
OR A ;Reset carry
SBC HL,BC ;Compute difference
CALL NOUT ;Print the number
CALL NEWLIN
CALL SHOTRANS
JP KERMIT
;
; Show the values of all setable values other than keystrokes.
; There is a lot of code here to perform the 2 column output.
;
SHOALL EQU $
STROUT SENDRECV ;Send Receive header
FORMAT BELSTR,SHSTRLEN ;Print setting of BELL
FOFFON BELFLG
FORMAT EOLST,SRSTRLEN ;Print send/recv EOL values
LD HL,SEOL
CALL SRSTATS
FORMAT PNTSTR,SHSTRLEN ;Print status of printer
FOFFON PRTFLG
FORMAT RETST,SRSTRLEN ;Print send/recv turn around values
LD HL,STURN
CALL SRSTATS
FORMAT BUGST,SHSTRLEN ;Print setting of debug flag
FOFFON DBFLG
FORMAT PCHST,SRSTRLEN ;Print send/recv padding characters
LD HL,SPADCH
CALL SRSTATS
FORMAT TYPEST,SHSTRLEN ;Print file-type (ASCII or BINARY)
LD A,(FILTYPE)
LD DE,ASCIIST
IFZ SHOA_1
LD DE,BINST
SHOA_1 CALL PRTSTR
CALL NEWLIN
FORMAT QTEST,SRSTRLEN ;Print send/recv eighth bit quotes
LD HL,SQUOTE
CALL SRSTATS
FORMAT LOCST,SHSTRLEN ;Print local echo setting
FOFFON ECOFLG
FORMAT TOST,SRSTRLEN ;Print send/recv time out values
LD HL,STIME
CALL SRSTATS
FORMAT ESCST,SHSTRLEN ;Print escape character
CALL STDOUT
CALL ESCPR
CALL STDEND
CALL NEWLIN
FORMAT PADST,SRSTRLEN ;Print send/recv padding amounts
LD HL,SPAD
CALL SRSTATS
FORMAT FILST,SHSTRLEN ;Print file warning setting
FOFFON FLWFLG
FORMAT SOPST,SRSTRLEN ;Print send/recv SOP characters
LD HL,SSOHCH
CALL SRSTATS
FORMAT FLOWST,SHSTRLEN ;Print flow control setting
LD A,(FLOFLG)
LD DE,XONSTR
IFNZ SHOA_2
LD DE,NONSTR
SHOA_2 CALL PRTSTR
CALL NEWLIN
STROUT INPUTSTR ;Print Input settings message
FORMAT DSKDEF,SHSTRLEN ;Print the default disk drive
CALL STDOUT
LD A,(DEFDSK)
CALL CONOUT
CALL STDEND
CALL NEWLIN
FORMAT IDSPST,SRSTRLEN ;Print INPUT DISPLAY setting
LD A,(INDSP)
CALL JUSONOFF
LD BC,0620H ;Display 6 spaces (B is count, C is char)
CALL MULDIS
CALL DISSEP
FORMAT EMSTR,SHSTRLEN ;Print setting for emulation
LD A,(EMULFLAG)
LD DE,NOESTR
IFZ SHOA_3
LD DE,DMESTR
SHOA_3 CALL PRTSTR
CALL NEWLIN
FORMAT CSEST,SRSTRLEN ;Print INPUT CASE-IGNORE setting
LD A,(CSEFLG)
CALL JUSONOFF
LD BC,0620H
CALL MULDIS
CALL DISSEP
FORMAT DISPST,SHSTRLEN ;Print file dispostion
CALL STDOUT
LD A,(DISCARD)
LD DE,DSCRDST
IFNZ SHOA_4
LD DE,KEEPST
SHOA_4 CALL PRTSTR
CALL STDEND
CALL NEWLIN
STROUT OUTPUTSTR ;Print Output settings message
FORMAT BCKST,SHSTRLEN ;Print block check type
CALL STDOUT
LD A,(CHKTYP)
CALL CONOUT
STROUT BCKST1
CALL STDEND
CALL NEWLIN
FORMAT ODSPST,SRSTRLEN ;Print OUTPUT DISPLAY setting
LD A,(OTDSP)
CALL JUSONOFF
LD BC,0620H
CALL MULDIS
CALL DISSEP
FORMAT TAKST,SHSTRLEN ;Print take file display setting
FOFFON TAKLOG
FORMAT HSTEST,SRSTRLEN ;Print OUTPUT HOST-ECHO setting
LD A,(ECHFLG)
CALL JUSONOFF
LD BC,0620H
CALL MULDIS
CALL DISSEP
FORMAT EIGHTSTR,SHSTRLEN ;Print eight bit quoting status
FOFFON EBQFLG
CALL NEWLIN
JP KERMIT ;Get a new command
;
; Print status of take file display
;
TAKESTAT STROUT TAKST
SHOFFON TAKLOG
;
; Print status of eighth bit quoting
;
EIGSTAT STROUT EIGHTSTR
SHOFFON EBQFLG
;
; Print file disposition
;
DISPSTAT STROUT DISPST
CALL STDOUT
LD A,(DISCARD)
LD DE,DSCRDST
IFNZ DISP_4
LD DE,KEEPST
DISP_4 CALL PRTSTR
CALL STDEND
JP NEWLIN
;
; Show the SET INPUT parameters
;
SHOINP CALL NEWLIN ;GET A NEW LINE
STROUT CSEST
LD A,(CSEFLG)
CALL COFFON
CALL NEWLIN
STROUT IDSPST
SHOFFON INDSP
;
; Print the SET OUTPUT parameters
;
SHOOUT CALL NEWLIN
STROUT HSTEST
LD A,(ECHFLG)
CALL COFFON
CALL NEWLIN
STROUT ODSPST
LD A,(OTDSP)
CALL COFFON
JP NEWLIN
;
; Flow control setting
;
FLOWSTAT STROUT FLOWST
LD DE,XONSTR
LD A,(FLOFLG)
OR A
JP NZ,PRTSTR
LD DE,NONSTR
JP PRTSTR
;
; Show status of all send parameters
;
SENDSTAT LD A,CMCFM
CALL COMND
JP KERMT3
CALL NEWLIN
SHSSTAT EOLST,SEOL
SHSSTAT RETST,STURN
SHSSTAT PCHST,SPADCH
SHSSTAT QTEST,SQUOTE
SHSSTAT TOST,STIME
SHSSTAT PADST,SPAD
SHSSTAT SOPST,SSOHCH
RET
;
; Show status of all receive parameters
;
RCVSTAT LD A,CMCFM
CALL COMND
JP KERMT3
CALL NEWLIN
SHRSTAT EOLST,REOL
SHRSTAT RETST,RTURN
SHRSTAT PCHST,RPADCH
SHRSTAT QTEST,RQUOTE
SHRSTAT TOST,RTIME
SHRSTAT PADST,RPAD
SHRSTAT SOPST,RSOHCH
RET
;
; Show status of bell for KERMIT messages
;
BELLSTAT STROUT BELSTR
SHOFFON BELFLG ;Print the bell status
;
; Show status of local echo
;
ECHSTAT STROUT LOCST ;Local echo is ...
SHOFFON ECOFLG ;Print local echo status
;
; Show the type of emulation
;
EMULSTAT STROUT EMSTR ;Emulation is ...
LD A,(EMULFLAG)
OR A
LD DE,NOESTR
JP Z,PRTSTR
LD DE,DMESTR
JP PRTSTR
;
; Show file parameters
;
FILESTAT LD DE,FILETAB ;Get the options
LD A,CMKEY ;Get a keyword
CALL COMND ;Parse it
JP KERMT2 ;Say ambiguous if error
CALL NEWLIN
LD (TEMP1),A ;Save the value
LD A,CMCFM ;Get a confirm
CALL COMND
JP KERMT3 ;Say not confirmed if it is not
LD A,(TEMP1) ;Get the value back
LD C,A ;Put it into BC as 16 bits
LD B,0
LD HL,SHFLJTAB ;Get the jump table
ADD HL,BC ;Get the destination
JP (HL) ;Jump into the table
;
SHFLJTAB EQU $
JP DISPSTAT ;SHOW FILE DISPOSITION
JP TYPESTAT ;SHOW FILE TYPE
JP WARNSTAT ;SHOW FILE WARNING
;
; Show file-type, ASCII or BINARY
;
TYPESTAT STROUT TYPEST ;File type is ...
LD DE,ASCIIST ;Get ASCII type
LD A,(FILTYPE) ;Check the type
OR A ;Set the flags
JP Z,PRTSTR ;Jump if ASCII
LD DE,BINST ;Get binary type
JP PRTSTR ;Print the string in rev video
;
; Show the default disk-drive
;
DSKSTAT STROUT DSKDEF ;Default disk is ...
CALL STDOUT ;REVERSE VIDEO ON
LD A,(DEFDSK) ;GET THE CHARACTER 0-9
CALL CONOUT
JP STDEND ;REVERSE VIDEO OFF
;
; Show status of file warning
;
WARNSTAT STROUT FILST ;File warning is ...
SHOFFON FLWFLG ;Show the file warning status
;
; Show status of debug setting
;
DEBSTAT STROUT BUGST ;Debugging is ...
SHOFFON DBFLG ;Show the debugging
;
; Show status of logging to the printer.
;
PRTSTAT STROUT PNTSTR ;Printer is ...
SHOFFON PRTFLG ;Show printer status
;
; Show block check type
;
CHKSTAT STROUT BCKST ;Block check type is ...
CALL STDOUT ;REVERSE VIDEO ON
LD A,(CHKTYP) ;GET THE TYPE (CHARACTER 1, 2, OR 3)
CALL CONOUT
CALL STDEND ;REVERSE VIDEO OFF
LD DE,BCKST1 ;GET REST OF TEXT ("-CHARACTER")
JP PRTSTR ;. . .
;
; Show the escape character
;
ESCSTAT STROUT ESCST ;Escape character is ...
CALL STDOUT ;REVERSE VIDEO ON
CALL ESCPR ;PRINT THE ESCAPE CHAR.
JP STDEND ;REVERSE VIDEO OFF
;
; Pick a character up from (HL+BC)
;
GETTRN EQU $
LD C,A
ADD HL,BC
LD A,(HL)
RET
;
; Put a characcter at (HL+BC)
;
PUTTRN EQU $
ADD HL,BC
LD (HL),A
RET
;
; Show the mapping of a keystroke
;
KYSTAT LD A,CMNUM ;GET WHICH KEY
CALL COMND ;GET IT
JP KERMT3 ;SAY NOT CONFIRMED
IFZ KYST_4 ;Say ambiguous if no number given
LD A,D ;CHECK FOR OVERFLOW
IFNZ KYST_3 ;Jump if > 255
CALL NEWLIN
LD A,E ;Get the key number
KYST_0 EQU $
CALL KEYTRANS ;Do the translation
OR H ;Check if there is one
JR Z,KYST_2 ;Jump if not
CALL NEWLIN ;Print a new line
KYST_1 EQU $
LD A,(HL) ;Get a character
OR A ;Is it a null
RET Z ;Return if end of string
CALL VERPRT ;Print verbose description
INC HL ;Point to next
JR KYST_1 ;Loop until done
KYST_2 EQU $
LD DE,NODEF ;Print undefined message
JP PRTSTR
KYST_3 STROUT OUTRNG ;Print bad value message
JP KERMIT
KYST_4 STROUT KEYHELP ;Ask them to press a key
KYST_5 CALL CONIN ;Get the keystroke
IFZ KYST_5 ;If none pressed, then loop
PUSH AF ;Save the key
CALL VERPRT ;Print it out
POP AF ;Restore key
JR KYST_0 ;Go process the key
;
; Print verbose string of A. Control characters appear as
; ^M for <CR>, etc...
;
VERPRT IFAGE ' ',VER_2 ;Jump if character not a control char
VER_1 PUSH AF ;Save the character
LD A,'^' ;Print a carrat first
CALL CONOUT ;Output it
POP AF ;Get the character back
ADD A,64 ;Uncontrolify it
AND 127 ;Remove eighth bit for <DEL>
JP CONOUT ;Output and return
VER_2 IFA 127,VER_1 ;If <DEL> then process as control char
JP C,CONOUT ;If less that 127 then print it
;
; Characters greater than 127 are printed as \nnn, where
; nnn is the 3 digit octal number representing the value
; of the character
;
LD C,A ;Save the character
LD A,'\' ;Get a leading \
CALL CONOUT ;Output it
LD A,C ;Get a copy of the character
AND 0C0H ;Save only 2 higher order bits
RLC A ;Move the 2 bits into the lower
RLC A ;order bits of A
AND 3 ;Make sure nothing else is there
ADD A,'0' ;Make it a printable value
CALL CONOUT ;Output it
LD A,C ;Get another copy
AND 38H ;Save bits 5-3
SRL A ;Align in lower order bits of
SRL A ;the accumulator
SRL A
AND 07H ;Truncate to 3 bits only
ADD A,'0' ;Make it printable
CALL CONOUT ;Output it
LD A,C ;Get the character again
AND 07H ;Save lower 3 bits, 2-0
ADD A,'0' ;Make it printable
JP CONOUT ;Output it, and return
;
; Right justify the string in DE, within a field as wide as
; HL specifies.
;
LEFTPAD PUSH DE ;Save the strings address for printing
CALL STRLEN ;Get the length in BC
OR A ;Reset the carry
SBC HL,BC ;Compute the difference to pad
LD B,L ;Make B the count
LD A,L ;Check for no padding
IFZ LEFTP_2 ;Jump if none needed
LEFTP_1 LD A,' ' ;Get the pad character
CALL CONOUT ;output one
DJNZ LEFTP_1 ;Loop until done
LEFTP_2 POP DE ;Restore the strings address
JP PRTSTR ;Print it, and return
;
;
DISSEP LD DE,SEPAR
JP PRTSTR
;
; Display SEND and RECEIVE status as indicated by values at
; the address pointed to be HL, and HL+1.
;
SRSTATS EQU $
LD A,(HL) ;Get the value
PUSH HL ;Save the address
CALL DISNUM ;Display the value
LD A,' ' ;Put in an extra blank
CALL CONOUT
POP HL ;Get the address back
INC HL ;Point to receive value
LD A,(HL) ;Get the value
CALL DISNUM ;Display the value
CALL DISSEP ;Put in the separator
RET
;
; Display value in A, in a 5 character field
;
DISNUM EQU $
LD DE,DECBUF ;Get the buffer
LD L,A ;Put the value into HL
LD H,0
CALL XHEXDEC ;Convert to printable
EX DE,HL ;Put ending address into HL
LD (HL),EOS ;Put in a terminator
STROUT DECBUF ;Output the string
RET
;
; Display the character in C, B times on the screen
;
MULDIS PUSH AF ;Save AF, don't destroy it
MULDIS1 LD A,C ;Get the character to print
CALL CONOUT ;Output one
DJNZ MULDIS1 ;Loop until all done
POP AF ;Restore AF
RET ;Return
;
; Print the ON string, or the OFF string, based on the value in
; A.
;
JUSONOFF EQU $
LD DE,OFFSTR ;Get the default before test
IFZ JUSON_1 ;Jump if OFF is right
LD DE,ONSTR ;Get ON, since A is non-zero
JUSON_1 LD HL,7 ;Make the field 7 characters wide
JP LEFTPAD ;Go pad it, and return from there
;
; Print ON or OFF based on the status of A. This is different
; from JUSONOFF because here, we do not right justify in a
; fixed length field.
;
COFFON LD DE,OFFSTR ;START WITH OFF AS DEFAULT
OR A ;SET THE FLAGS
JP Z,PRTSTR ;GO PRINT OFF IF A ZERO
LD DE,ONSTR
JP PRTSTR
; end of file
<<< m4str.asm >>>
; M4STR/ASM
;Pure storage.
FLINK DS 256 ;FAILURE LINK STORAGE
STRING DS 256 ;STORAGE FOR THE STRING TO MATCH
LENGTH DB 0 ;LENGTH OF STRING
BUFPTR DW 0 ;POINTER INTO THE BUFFER
MULBUF DS 256 ;THE BUFFER
CTLTBL DB 35
DB 'ACK',6,254,'BEL',7,254,'BS',8,254
DB 'CAN',24,254,'CR',13,254,'DC1',17,254
DB 'DC2',18,254,'DC3',19,254,'DC4',20,254
DLY EQU 250
DB 'DEL',127,254,'DLE',16,254,'DLY*',DLY,254
DB 'EM',25,254,'ENQ',5,254,'EOT',4,254
DB 'ESC',27,254,'ETB',23,254,'ESC',27,254
DB 'FF',12,254,'FS',28,254,'GS',29,254
DB 'HT',9,254,'LF',10,254,'NAK',21,254
DB 'NUL',0,254,'RS',30,254,'SI',15,254
DB 'SO',14,254,'SOH',1,254,'SPA',32,254
DB 'STX',2,254,'SUB',26,254,'SYN',22,254
DB 'VS',31,254,'VT',31,254
DB 0
GTSTRG DS 6 ;String space for storing above ANSI strs
WLDBUF DS 6 ;Save wildcards here
ALRMAD DW ALARM ;Delay TCB
TIMER DW 0 ;Counter
RECTIME DW RECTIMOUT ;Receive timeout TCB
SVTIMER DW 0
TKNAME DB 'KERMIT/INI',13 ;Name of the initialization file
TKLEN EQU $-TKNAME ;Length of the name
; THE FOLLOWING FLAGS ARE STATE FLAGS FOR WHEN EOF OCCURS.
; IF ANY ARE SET WHEN EOF OCCURS THAN AN ERROR HAS OCCURED.
INBUF DS 102H ;FILE INPUT BUFFER
HSTCHR DB 0 ;TERMINATOR FROM THE HOST IN '*'
DLYFLG DB 0 ;WAS A DELAY INVOKED
CHRGOT DB 0 ;ACTUAL CHARACTER FROM THE FILE
; PARSING OPTION FLAGS
CSEFLG DB 0 ;IGNORE CASE FLAG
SPTFLG DB 0 ;ECHOING OF SET OPTIONS IS ON
ECHFLG DB 0 ;IS ECHO OF SENT STRINGS ON
EXTFLG DB 1 ;EXIT AT EOF FLAG
; EARLY EOF STATE FLAGS
ESFLG DB 0 ;ESCAPE CHARACTER SEQUENCE
CTLFLG DB 0 ;CONTROL CHARACTER SEQUENCE
SNDFLG DB 0 ;SEND STATE FLAG
RECFLG DB 0 ;RECEIVE SATE FLAG
MULFLG DB 0 ;MULTI-SEND STATE FLAG
OPTFLG DB 0 ;SET OPTIONS STATE FLAG
BUFFSIZE EQU 2048 ;Size of buffer
SRCPTR DW 0 ;Source string pointer
HASWILD DB 0 ;Wild cards present flag
SPAT DW 0 ;Pattern pointer
SSTR DW 0 ;String pointer
PSAVE DW 0 ;Saved pattern pointer
SSAVE DW 0 ;Saved string pointer
SDIRDRV DB '0' ;Saved current drive
DIRBUFF DS 256 ;Buffer for DIR/SYS record
COMPNAME DS 32 ;Complete file name
FNLEN DB 0 ;Length of pattern
MOREDRV DB 0 ;More drives to check flag
DIRFCB DB 'DIR/SYS:' ;Directory file control block
DIRDRV DB '0',CR ;Where to put the drive number
DC 23,0 ;Remaining, for 33 bytes total
TFBUF DS 256 ;Current pattern storage
FILEBUFF DS BUFFSIZE ;Place for file name list
FBPTR DW FILEBUFF ;Pointer to next available space
FILECNT DB 0 ;Number of file names in FILEBUFF
DIRSPEC DB 'DIR/SYS:' ;DIR/SYS pattern
DLEN EQU $-DIRSPEC ;Length of text to move
PARMS DB 80H ;@PARAM parse table
DB 56H
DB 'SYSTEM'
SYSRESP DB 0
DW SYSFLAG
DB 55H
DB 'INVIS'
INVRESP DB 0
DW INVFLAG
DB 0
SYSFLAG DW 0
INVFLAG DW 0
BADCD DB 13,'Bad code inside of <...>',39,'s',EOS
NOECHO DB 13,'Host did not echo last character sent',13,EOS
QUTMES DB 13,'Ignoring => ',EOS
STOBIG DB 13,'String too big for buffer!',13,EOS
LGFAIL DB 13,'Operation aborted!',13,EOS
PREESC DB 13,'Missing character following \',13,EOS
PRECTL DB 13,'Missing character following ^',13,EOS
PREOPT DB 13,'Missing > in <...> sequence',13,EOS
TXTHLP DB CR,16,'Enter a text string',17,CR,EOS
FILHLP DB CR,16,'Enter a file specification!',17,CR,EOS
NUMHLP DB CR,16,'Enter a Decimal number!',17,CR,EOS
FILESFND DB 'Sending files:',CR,EOS
NOFILES DB 16,'No files found',17,CR,EOS
OUTOFSTR DB 16,'Too many files, out of space',17,CR,EOS
NOTIMER DB CR,16,'No task slots available for timeout',17,CR,EOS
NODELAY DB CR,16,'No task slots available for delay, using 1 second'
DB 17,CR,EOS
NOMEM DB CR,16,'Can',39,'t move LOW$ to new value',17,CR,EOS
BADPARM DB CR,'Bad parameter list',CR,EOS
TRANABRT DB 'Transaction aborted',CR,EOS
TRANCANC DB 'Transaction canceled',CR,EOS
WRTPROT DB CR,'Drive is write protected',EOS
DSKOK DB CR,'Default drive changed',CR,EOS
REMOVSTR DB 'Removing: ',EOS
TIMEMES DB ' Time: ',EOS
LOGERROR DB 'Log file I/O error. '
ERMS20 DB 'Log file CLOSED!',CR,EOS
BLANKS DB ' ',EOS
INTRO DB CR,'TRS-80 Model 4(p) TRSDOS 6.2 - KERMIT - Version'
DB ' 5.2',CR,'By Gregg Wonderly',CR,CR
DB 'Type a ? for help at any time....',CR,EOS
CFCL DB CR,'No *CL DCB!',CR,EOS
CFSO DB CR,'No *SO DCB!',CR,EOS
CFSI DB CR,'No *SI DCB!',CR,EOS
NONDCB DB CR,'Can not find a DCB for the *FI or *FO devices!'
DB CR,EOS
NOSPACE DB CR,'Not enough space left for definition',CR,EOS
KPLUS DB 'K + ',EOS
BYTESMES DB ' bytes transfered.',EOS
KEYHELP DB CR,'Press keystroke you desire: ',EOS
STRHELP DB CR,'Enter definition string, end with <BREAK> '
DB '(255 characters MAX)',CR,EOS
SPACSTR DB CR,'Remaining key definition space: ',EOS
TOOLONG DB CR,'String too long for one packet!',CR,EOS
NPKTSTR DB CR,'Number of packets => ',EOS
NRTRSTR DB CR,'Number of retries => ',EOS
NCHRSTR DB CR,'Bytes transfered => ',EOS
NRECCH DB CR,'Kbytes received => ',EOS
NSNDCH DB CR,'Kbytes transmitted => ',EOS
CBATCH DB 32,16,'[Cancelling batch]',17,32,EOS
CFILE DB 32,16,'[Cancelling file]',17,32,EOS
UNKNOWN DB CR,'Unknown packet type',CR,EOS
HELPMSG DB CR,' CTRL-F => Cancel file '
DB 'CTRL-B => Cancel Batch'
DB CR,' CTRL-C => Quit protocol '
DB 'CTRL-A => Transfer status'
DB CR,' CTRL-D => Toggle debugging '
DB 'CTRL-H => This message'
DB CR,' CTRL-E => Send error, quit '
DB 'ENTER => Resend last packet',CR,EOS
RMMES DB BELL,32,16,'[Discarded]',17,32,EOS
DO62DR DB 'CAT '
DO61DR DB 'DIR '
DIRCMD DS 4
DIRBUF DS 256
DEFTRLOG DB 'TRANS/LOG',CR
DEFSESLOG DB 'SESSION/LOG',CR
DEFDEBLOG DB 'DEBUG/LOG',CR
DECBUF EQU $
NBUFF DS 6
VISIBLE DB 0
THEVAL DW 0
RMTPTR DW 0
OUTADDR DW 0
PREVCH DB 0
CURLEN DB 0
MAXLEN DB 0
CURCOL DB 0
MAXCOL DB 78
RPTFLG DB 0
NEXT DW 0
RPTCNT DB 0
RPTQ DB '~'
EBQFLG DB 1
EBQ DB '&'
MYCTLQ DB '#'
LEFTOVER DS 7
CH DW 0
DISCARD DB 0
LOGNAMES DB 1
INITRMT DW 0
INITCNT DW 0
PKTTYPE DB 0
FLDLEN DW 0
KTRANS DW 0
RTRANS DW 0,0
STRANS DW 0,0
CURTRANS DW 0,0
SOUPTR DW 0
XOFREC DB 0
TAKLOG DB 0
RECTYP DB 0
SNDTYP DB 0
INDSP DB 0
OTDSP DB 0
PREVLCHR DB 0 ;Previous character logged to session log
TRTAB DB 0,1,2,3,4,5,6,7,24,9,26,11,12,29,0,0,16,17,18,19,20
DB 21,22,23,24,25,26,27,28,29,30,31,32,33
KEYTABLE DC 512,0 ;Must be 256 words of zeroes
DW 0 ;A little padding for off by one errors
TOPADDR DW DEFTABLE
DEFTABLE DS 2048 ;Key definition space
DEFTLEN EQU $-DEFTABLE
KEYPOS DW ATNULL ;Initial buffered string pointer
ATNULL DB 0 ;A null byte to signal no characters
DIFFADDR DW 0
STRINGLEN DB 0
SAVEDKEY DB 0
KEYSTRING DW 0
KEYNUMBER DB 0
TABLEADDR DW 0
CMPADDR DW 0
MOVEDIFF DW 0
KEYNUM DB 0
KEYPTR DW 0
KEYLEN DB 0
OUTRNG DB CR,'Value out of range!!',CR,EOS
NODEF DB CR,'No definition exists',EOS
SOUFCB DS 40
TAKFLG DB 0
INCNT DB 0
XFFLG DB 0
FLOFLG DB 1
TFCB DS 32
OLDLOW DW 0
FLAGS DW 0
BEPLEN DB 0
BELFLG DB 1
CLDCB DW 0
TMIDCB DW 0
TMODCB DW 0
RFIDCB DW 0
MAXCNT DB 180
SVMAX DB 80
DISFLG DB 1
HLPMES DB 8,' One of the following...',CR,EOS
SORFLG DB 0
MAXTRY DB 7
GENTYPE DB 0
GENLEN DB 0
SORLOC DW 0
LOGOPN DB CR,16,'Logfile is already OPEN!',17,CR,EOS
NOLOGF DB CR,16,'Logfile is not OPEN!',17,CR,EOS
SNDREC DB EOS
KERREC DB 13,'Receiving => ',EOS
KERSND DB 13,'Sending => ',EOS
DSSOP EQU 1
DRSOP EQU 1
SWTBUF DS 2048
CONCRS DW 0
CMDCRS DW 0
FTIME DB 0
SNDST DB 0
TIME DB 30H
TBUF DS 256 ;TAKE COMMAND INPUT BUFFER.
;
; The next 512 bytes produce a 256 byte circular buffer for
; the communications input routine.
;
DS 256
CHRBUF DS 256
CURCHR DW CHRBUF ;Buffer is initially empty
NXTCHR DW CHRBUF
DB 'SETCOM '
CLBUF DS 256
KERM DB 14,16,17,'KERMIT 4(p)>',EOS ;cursor on at prompt
CRLF DB CR,EOS
ERMES1 DB CR,16,'Unrecognized command',17,CR,EOS
ERMES2 DB CR,16,'Illegal character',17,CR,EOS
ERMES3 DB CR,16,'Not confirmed',17,CR,EOS
ERMES4 DB 'Unable to receive initiate',CR,EOS
ERMES5 DB 'Unable to receive file name',CR,EOS
ERMES6 DB 'Unable to receive end of file',CR,EOS
ERMS10 DB 'Unable to receive data',CR,EOS
ERMS17 DB CR
ERMS11 DB 'System DOS error',CR,EOS
ERMS14 DB 'No acknowledgement from the host',CR,EOS
ERMS15 DB CR,'Unable to find file',CR,EOS
ERMS16 DB 'Unable to rename file',EOS
ERMS18 DB CR,'Unable to tell host that the session is finished',EOS
ERMS19 DB CR,'Unable to tell host to logout',EOS
INFMS3 DB BELL,CR,'Completed',EOS
INFMS4 DB BELL,'Failed',EOS
INFMS5 DB 'Renaming file => ',EOS
INFMS6 DB CR,'<Closing the log file>',EOS
INFMS7 DB CR,'<Connected to remote host, type ',EOS
INFMS8 DB 'C to return>',CR
DB '<CLEAR> is Control-',95,CR,EOS
INFMS9 DB CR,'<Connection closed, back at micro>',EOS
INMS10 DB 'Control-',EOS
INMS13 DB BELL,CR,'Interrupted',EOS
INMS18 DB CR,'File KILLED',EOS
CFRMES DB CR,16,'Confirm with <ENTER>, cancel with <BREAK>',17,CR
DB EOS
CMIN00 EQU CFRMES
ABRTMSG DB 'Transfer aborted...'
ABRTMSGLEN EQU $-ABRTMSG
ESCMES DB CR,'Type the new escape character: ',EOS
INTHLP DB 16,CR,17,CR,CR
DB ' ? = This message',CR
DB ' 0 = (zero) Transmit a NULL',CR
DB ' B = Send modem break',CR
DB ' C = Close the connection',CR
DB ' Q = Quit logging session',CR
DB ' R = Resume logging session',CR,CR
DB 'Type the escape character again to send it to the host.'
DB 16,CR,17,EOS
;
SENDRECV DB ' ',16,'Send',17,' ',16
DB 'Receive',17,' | ',EOS
INPUTSTR DB 16,'Input settings',17,' '
DB '| ',EOS
OUTPUTSTR DB 16,'Output settings',17,' '
DB '| ',EOS
SEPAR DB ' | ',EOS
ONSTR DB 16,'ON',17,EOS
OFFSTR DB 16,'OFF',17,EOS
XONSTR DB 16,'XON-XOFF',17,EOS
NONSTR DB 16,'NONE',17,EOS
NOESTR EQU NONSTR
ASCIIST DB 16,'ASCII',17,EOS
BINST DB 16,'BINARY',17,EOS
DMESTR DB 16,'DUMB',17,EOS
DSCRDST DB 16,'DISCARD',17,EOS
KEEPST DB 16,'KEEP',17,EOS
;
;
; Miscellaneous SET strings
;
BELSTR DB 'Bell: ',EOS
PNTSTR DB 'Printer: ',EOS
BUGST DB 'Debugging: ',EOS
TYPEST DB 'File type: ',EOS
LOCST DB 'Local echo: ',EOS
ESCST DB 'Escape char: ',EOS
FILST DB 'File warning: ',EOS
FLOWST DB 'Flow control: ',EOS
DSKDEF DB 'Default drive: ',EOS
EMSTR DB 'Emulation type: ',EOS
DISPST DB 'File disposition: ',EOS
BCKST DB 'Block check type: ',EOS
TAKST DB 'Display TAKE file: ',EOS
EIGHTSTR DB 'Eight bit quoting: ',EOS
;
; This value must be the length of the longest of the
; above strings (except the ending EOS).
;
SHSTRLEN EQU $-EIGHTSTR-1
;
; Send/Recv strings
;
EOLST DB 'End-of-line: ',EOS
RETST DB 'Turn around: ',EOS
PCHST DB 'Pad character: ',EOS
QTEST DB 'Control quote: ',EOS
TOST DB 'Time out value: ',EOS
PADST DB 'Padding Length: ',EOS
SOPST DB 'Start-of-packet: ',EOS
SRSTRLEN EQU $-SOPST+2
;
; Input strings (Length must fit within SRSTRLEN)
;
IDSPST DB 'Display input: ',EOS
CSEST DB 'Ignore case: ',EOS
;
; Output strings (Length must fit within SRSTRLEN)
;
ODSPST DB 'Display output: ',EOS
HSTEST DB 'Match echo: ',EOS
;
BCKST1 DB '-character',EOS
RPPOS DB 'RPack=>',EOS
SPPOS DB 'SPack=>',EOS
CLRTOP DB 1CH,1FH,EOS ;clear screen
;
; COMND tables
;
; Structure of command table
;
; 1) Number of entries.
; 2) Length of longest keyword + 2
; 3) Each entry is arranged as follows
; a) visibility byte, 1-command is visible, 2-invisible
; b) length of command in bytes.
; c) 'name of command and eos'
; d) offset into command table at KERMTB
; e) offset into command table at KERMTB
;
; ---> Note this command table is in alphabetic order.
;
COMTAB DB 30 ;Number of keywords in table
DB 9 ;LONGEST KEYWORD + 2
DB 1,3,'BYE',EOS,33,33
DB 0,1,'C',EOS,6,6
DB 1,5,'CLEAR',EOS,63,63
DB 1,5,'CLOSE',EOS,66,66
DB 1,7,'CONNECT',EOS,6,6
DB 1,3,'DIR',EOS,36,36
DB 0,1,'E',EOS,3,3
DB 1,4,'ECHO',EOS,69,69
DB 1,4,'EXIT',EOS,3,3
DB 1,6,'FINISH',EOS,27,27
DB 1,3,'GET',EOS,12,12
DB 1,5,'INPUT',EOS,51,51
DB 1,4,'KILL',EOS,39,39
DB 0,1,'L',EOS,42,42
DB 1,5,'LOCAL',EOS,42,42
DB 1,3,'LOG',EOS,9,9
DB 1,6,'LOGOUT',EOS,30,30
DB 1,6,'OUTPUT',EOS,54,54
DB 1,5,'PAUSE',EOS,57,57
DB 1,5,'PULSE',EOS,60,60
DB 0,1,'R',EOS,12,12
DB 1,7,'RECEIVE',EOS,12,12
DB 1,6,'REMOTE',EOS,0,0
DB 0,1,'S',EOS,15,15
DB 1,4,'SEND',EOS,15,15
DB 1,3,'SET',EOS,18,18
DB 1,6,'SETCOM',EOS,45,45
DB 1,4,'SHOW',EOS,21,21
DB 1,6,'STATUS',EOS,24,24
DB 1,4,'TAKE',EOS,48,48
MXSLEN EQU 19
SHOTAB DB SHLEN/3+1
DB MXSLEN ;LONGEST KEYWORD + 2
DB 1,3,'ALL',EOS ;THE OTHER TWO BYTES WILL BE SUBSTITUTED
SETTAB DB SHLEN/3 ;Number of entries in the jump table
DB MXSLEN ;LONGEST KEYWORD + 1
DB 1,4,'BELL',EOS,27,27
DB 1,16,'BLOCK-CHECK-TYPE',EOS,12,12
DB 1,9,'DEBUGGING',EOS,21,21
DB 1,12,'DEFAULT-DISK',EOS,24,24
DB 1,17,'EIGHT-BIT-QUOTING',EOS,6,6
DB 1,9,'EMULATION',EOS,15,15
DB 1,6,'ESCAPE',EOS,0,0
DB 1,4,'FILE',EOS,9,9
DB 1,12,'FLOW-CONTROL',EOS,39,39
DB 1,5,'INPUT',EOS,41,41
DB 1,3,'KEY',EOS,36,36
DB 1,10,'LOCAL-ECHO',EOS,3,3
DB 1,6,'OUTPUT',EOS,45,45
DB 1,7,'PRINTER',EOS,18,18
DB 1,7,'RECEIVE',EOS,30,30
DB 1,4,'SEND',EOS,33,33
DB 1,12,'TAKE-DISPLAY',EOS,48,48
;
; File options
;
FILETAB DB 3
DB 13
DB 1,11,'DISPOSITION',EOS,0,0
DB 1,4,'TYPE',EOS,3,3
DB 1,7,'WARNING',EOS,6,6
;
; File disposition options
;
DISPTAB DB 2
DB 9
DB 1,7,'DISCARD',EOS,1,1
DB 1,4,'KEEP',EOS,0,0
;
; Remote commands parse table
;
RMTTAB DB 21
DB 16
DB 1,9,'CLOSE-LOG',EOS,42,42
DB 1,4,'COPY',EOS,30,30
DB 1,3,'CWD',EOS,0,0
DB 1,6,'DELETE',EOS,3,3
DB 1,3,'DIR',EOS,6,6
DB 1,4,'DISK',EOS,9,9
DB 1,4,'HELP',EOS,12,12
DB 1,4,'HOST',EOS,15,15
DB 1,6,'KERMIT',EOS,18,18
DB 1,5,'LOGIN',EOS,54,54
DB 1,7,'MESSAGE',EOS,33,33
DB 1,7,'PROGRAM',EOS,57,57
DB 1,14,'QUERY-VARIABLE',EOS,39,39
DB 1,6,'RENAME',EOS,24,24
DB 1,8,'SEND-LOG',EOS,45,45
DB 1,13,'SERVER-STATUS',EOS,60,60
DB 1,12,'SET-VARIABLE',EOS,36,36
DB 1,9,'START-LOG',EOS,48,48
DB 1,8,'STOP-LOG',EOS,51,51
DB 1,4,'TYPE',EOS,27,27
DB 1,3,'WHO',EOS,21,21
;
; Emulation type parse table
;
EMLTAB DB 2
DB 6
DB 1,4,'DUMB',EOS,3,3
DB 1,4,'NONE',EOS,0,0
;
; Close options parse table
;
CLSTAB DB 3
DB 13
DB 1,5,'DEBUG',EOS,1,1
DB 1,7,'SESSION',EOS,0,0
DB 1,11,'TRANSACTION',EOS,2,2
;
; Clear command options parse table
;
CLRTAB DB 2
DB 12
DB 1,10,'INPUT-PORT',EOS,0,0
DB 1,6,'SCREEN',EOS,3,3
;
; Flow control options parse table
;
FLOTAB DB 2
DB 10
DB 1,4,'NONE',EOS,0,0
DB 1,8,'XON-XOFF',EOS,1,1
;
; SET SEND/RECEIVE options parse table
;
STSNTB DB 7
DB 17
DB 1,11,'END-OF-LINE',EOS,12,12
DB 1,8,'PAD-CHAR',EOS,0,0
DB 1,7,'PADDING',EOS,3,3
DB 1,15,'QUOTE-CHARACTER',EOS,15,15
DB 1,15,'START-OF-PACKET',EOS,6,6
DB 1,8,'TIME-OUT',EOS,9,9
DB 1,9,'TURN-CHAR',EOS,18,18
;
; SET OUTPUT options parse table
;
OUTTAB DB 2
DB 11
DB 1,9,'HOST-ECHO',EOS,0,0
DB 1,7,'DISPLAY',EOS,3,3
;
; SET INPUT options parse table
;
INPTAB DB 2
DB 13
DB 1,11,'CASE-IGNORE',EOS,0,0
DB 1,7,'DISPLAY',EOS,3,3
;
; SET FILE TYPE options parse table
;
TYPETAB DB 2
DB 8
DB 1,6,'BINARY',EOS,1,1
DB 1,5,'ASCII',EOS,0,0
;
; SET BLOCK-CHECK-TYPE options parse table
;
BLKTAB DB 3
DB 8
DB 1,1,'1',EOS,'11'
DB 1,1,'2',EOS,'22'
DB 1,1,'3',EOS,'33'
;
; OFF/ON parse table
;
ONTAB DB 4 ;Number of entries
DB 5 ;Max length + 2
DB 0,2,'NO',EOS,0,0 ;YES and NO are invisible
DB 1,2,'ON',EOS,1,1
DB 1,3,'OFF',EOS,0,0
DB 0,3,'YES',EOS,1,1
;
; Assorted error/informational messages
;
CMER00 DB CR,'Program error, Invalid COMND call',EOS
CMER01 DB CR,'Ambiguous',EOS
CMER02 DB CR,'Illegal input filespec',EOS
CMCRLF DB CR,EOS
;
; Storage for the parser, etc.
;
CMSTAT DB 0 ;What is presently being parsed.
CMAFLG DB 0 ;Non-zero when an action char has been found.
CMCCNT DB 0 ;Non-zero if a significant char is found.
CMSFLG DB 0 ;Non-zero when the last char was a space.
CMOSTP DW 0 ;Old stack pointer for reparse.
CMRPRS DW 0 ;Address to go to on reparse.
CMPRMP DW 0 ;Address of prompt.
CMPTAB DW 0 ;Address of present keyword table.
CMDBUF DS 100H ;Buffer for command parsing.
CMFCB DW 0 ;Pointer to FCB.
CMCPTR DW 0 ;Pointer for next char input.
CMDPTR DW 0 ;Pointer into the command buffer.
CMKPTR DW 0 ;Pointer to keyword.
CMSPTR DW 0 ;Place to save a pointer.
OLDSP DW 0 ;Room for old system stack.
DS 200H ;Room for lots of calls
STACK DW 0
EOFLAG DB 0 ;EOF flag; non-zero on EOF.
FILFLG DB 0 ;NON-ZERO WHEN FILE NOT OPEN
LSTCHR DB 0 ;Last character in disk i/o
DEFDSK DB '0' ;Default disk drive number
LOGFLG DB 0 ;Flag for session logging
DEBLOG DB 0 ;Flag for debug logging
TRANLOG DB 0 ;Flag for transaction logging
ECOFLG DB 0 ;Local echo flag (default off).
ESCFLG DB 0 ;Escape flag (start off).
EMULFLAG DB 0 ;Emulation flag, NONE is default
FLWFLG DB 0 ;file warning flag (default on)
FILTYPE DB 0 ;File type, default is ASCII
DBFLG DB 0 ;debugging flag (default off)
PRTFLG DB 0 ;printer flag (default off)
ESCCHR DB DEFESC ;Storage for the escape character.
CHRCNT DB 0 ;Number of chars in the file buffer.
FILCNT DB 0 ;Number of chars left to fill.
OUTPNT DW 0 ;Position in packet.
BUFPNT DW 0 ;Position in file buffer.
FCBPTR DW 0 ;Position in FCB.
FCBEXT DW 0
DATPTR DW 0 ;Position in packet data buffer.
LOGPTR DW LBUFF ;pointer into log file buffer
CBFPTR DW 0 ;Position in character buffer.
PKTPTR DW 0 ;Poistion in receive packet.
OSIZE DB 0 ;Old size of packet before overflow
SIZE DB 0 ;Size of data from gtchr.
SPSIZ DB DSPSIZ ;Send packet size.
RPSIZ DB DRPSIZ ;Receive packet size.
STIME DB DSTIME ;Send time out.
RTIME DB DRTIME ;Receive time out.
SPAD DB DSPAD ;Send padding.
RPAD DB DRPAD ;Receive padding.
SPADCH DB DSPADC ;Send padding char.
RPADCH DB DRPADC ;Receive padding char.
SEOL DB DSEOL ;Send EOL char.
REOL DB DREOL ;Receive EOL char.
SSOHCH DB DSSOP ;SEND START OF PACKET
RSOHCH DB DRSOP ;RECEIVE START OF PACKET
SQUOTE DB DSQUOT ;Send quote char.
RQUOTE DB DRQUOT ;Receive quote char.
STURN DB 0 ;Send turn around character
RTURN DB 0 ;Receive turn around character
CHKTYP DB DSCHKT ;Checksum type desired
CURCHK DB DSCHKT ;Current checksum type
INICHK DB DSCHKT ;Agreed upon checksum type
CZSEEN DB 0 ;Flag that control-Z was typed
MFNPTR DW MFNBUF ;multiple file processing buffer
PKTNUM DB 0 ;Packet number.
NUMPKT DW 0 ;Total number of packets sent.
NUMRTR DW 0 ;Total number of retries.
NUMTRY DB 0 ;Number of tries on this packet.
OLDTRY DB 0 ;Number of tries on previous packet.
TFILNAM DS 33 ;Space for saved file name printed during GETs
RMTDATA DS 101H ;Data for remote commands
STATE DB 0 ;Present state of the automaton.
PACKET DS 4 ;Packet (data is part of it).
DATA DS 101H ;Data and checksum field of packet.
RECPKT DS 70H ;Receive packet storage (use the following).
FILBUF DS 70H ;Character buffer.
;
;** Temp 1 & 2 must be in order
;
TEMP1 DB 0 ;Temporary storage.
TEMP2 DB 0
TEMP3 DB 0
TEMP4 DB 0
;
; Data storage for MFNAME (multi-file access)
;
MFREQ DS 40 ;Requested name
MFNBUF DS 100H ;filename buffer
;
FCB DS 40 ;file control block
LFCB DS 40 ;log file fcb
TRFCB DS 40 ;Transaction file fcb
DFCB DS 40 ;Debug fcb
KFCB DS 40 ;kill file fcb
BUFF DS 256 ;file buffer
LBUFF DS 256 ;log file buffer
TBUFF DS 256 ;Transaction log buffer
DBUFF DS 256 ;Debug log buffer
ARGBLK DS 20H ;Used
; end of file
<<< m4term.asm >>>
; m4term/asm
;
; This is the connect command
;
CONNECT EQU $
LD A,CMCFM ;Get a confirmation
CALL COMND
JP KERMT3 ;Abort if no <ENTER> pressed
CALL SCRCON ;Swap in the proper screen
LD A,(MAXCNT) ;Select the proper buffer size
LD (SVMAX),A
LD A,80 ;80 characters max are buffered
LD (MAXCNT),A
LD A,(FTIME) ;Is this the VERY FIRST connect?
IFNZ CON_2
STROUT CLRTOP ;Clear the screen
CON_1 STROUT INFMS7 ;Display the message
CALL ESCPR
STROUT INFMS8
LD A,1 ;Set the first time done flag
LD (FTIME),A
CON_2 LD A,14
CALL CONOUT
;
; While in connect mode, at most, 30 characters may be processed
; from the input port, before the keyboard is scaned. We try not
; to scan the keyboard too much, as that will kill screen I/O. This
; is especially true at higher baud rates, where the user might
; not get to type a key because the flow of characters into the
; port is continuous.
;
CHRLUP LD A,30 ;Set the maximum character count
LD (CHCNT),A ;Save it
CALL PRTCHR ;Do input characters
CALL CONCHR ;Get a keyboard character
JP KERMIT ;IF we return here, then abort
JR CHRLUP ;Loop on
;
; Look at the input buffer for a character, and return it, or
; return no input.
;
INPORT PUSH HL ;SAVE HL
LD HL,(NXTCHR) ;Get address of next input char
LD A,(CURCHR) ;Get the LSB of the queue start
IFA L,INOUT ;If A=L, then there is no input.
DI ;Interrupts off, CRITICAL section
LD A,(HL) ;Get the character back
LD (SVCHAR),A ;Save the input character
INC L ;Delete the character
LD (NXTCHR),HL ;Set the new pointer
LD HL,INCNT ;Decrement the count
DEC (HL)
EI ;Interrupts back on
LD A,(FLOFLG) ;Is XON/XOFF in effect?
IFZ INP11 ;Go if not doing flow control
PUSH BC ;Save BC
LD C,(HL) ;Get a copy of the count
LD A,(XFFLG) ;Check if XOFF sent out
IFZ INP10 ;Jump if not
LD A,(MAXCNT) ;It was, so check if time for XON
SRL A ;Use 1/2 of the max as the restart count
IFALT C,INP10 ;If A >= count it is not time yet
PUSH DE ;Save DE
LD E,XON ;Get an XON character
CALL OUTCHR ;Out the port it goes
XOR A ;Reset the XOFF sent flag
LD (XFFLG),A
POP DE ;Restore E
INP10 POP BC ;Restore C
INP11 LD A,0 ;Get the next character
SVCHAR EQU $-1
CP A ;Set Z status for normal return
INOUT1 POP HL ;Restore HL
RET ;Back to caller
;
; No input exit from INPORT
;
INOUT EQU $
XOR A ;Reset the count
LD (INCNT),A ;Zeroed
INC A ;Set NZ (We know A was zero, now it is 1)
POP HL ;Restore HL
RET ;Back to the caller
;
; Input a character, and display it based on the current value
; of EMULATION.
;
PRTCHR CALL INPORT ;Try to get an input character.
RET NZ ;Return if none there
LD E,A ;Get the input character
CALL LOGONE ;Maybe do logging
LD A,(PRTFLG) ;CHECK FOR PRINTER OUTPUT
OR A ;SET THE FLAGS
CALL NZ,PRTIT ;GO PRINT IT
LD A,E ;GET THE CHARACTER AND DISPLAY
CALL TRMOUT ;Send it to the *SO device
LD B,0 ;Get the current count
CHCNT EQU $-1
DJNZ PRTCHR5 ;SKIP RETURN IF NOT LIMIT
RET ;RETURN AFTER LIMIT IS UP
PRTCHR5 LD A,B ;GET THE NEW COUNT
LD (CHCNT),A ;SAVE IT
JP PRTCHR ;LOOP ON
;
; Input a character from the keyboard.
;
CONCHR CALL GETKEY ;Get a keyboard character without
JP NZ,RSKP ;Return if not one
LD E,A ;Is it CONNECT escape character?
LD A,(ESCCHR)
CP E
JP Z,INTCHR ;Go process the next key pressed
CONCHR2 IFANOT 128,CONCHR3 ;BREAK?
CALL DOBRK ;Generate real BREAK
JP RSKP
CONCHR3 LD A,E
CONCHR4 PUSH DE ;SAVE DE
CALL PRTOUT ;SEND IT TO THE PORT
POP DE
LD A,(ECOFLG) ;CHECK FOR LOCAL ECHO
OR A
LD A,E
CALL NZ,TRMOUT ;Echo out terminal device
JP RSKP ;RETURN TO THE CALLER SAY OK
;
; This is the code to process the escape sequences during the
; CONNECT command that do things like return to the KERMIT
; prompt, send a break, turn logging on and off, etc...
;
INTCHR EQU $
CALL GETKEY ;Get a character from translator
JR NZ,INTCHR ;Loop until we get one
INCH00 EQU $
LD B,A ;Put the real character into B
AND 137O ;Convert A to upper case
IFANOT 'C',INCH01 ;Is it connect, if not try other
CALL SCRCMD ;Swap KERMIT screen in
LD A,(SVMAX) ;Restore the old max
LD (MAXCNT),A
RET ;Return to KERMIT
INCH01 LD A,B ;Get the real value
IFANOT '?',INTCH1 ;Is it help, if not try next
LD A,15 ;Turn the cursor off
CALL CONOUT
LD B,4 ;Get the cursor position
CALL XVDCTL
PUSH HL ;Save it
LD HL,2600H ;Save the screen
LD B,6 ;Get screen function
CALL XVDCTL ;Do the move
LD HL,0C00H ;Move to middle
CALL TOSCRPOS ;Move to possition on screen
LD A,31 ;Clear to eos
CALL CONOUT
LD DE,INTHLP ;Get Help message
CALL PRTSTR ;Print message
INCH11 CALL GETKEY ;Get a character
JR NZ,INCH11 ;Jump if no key pressed
POP HL ;Reorder the stack
PUSH AF
PUSH HL
LD HL,2600H ;Get the old screen
LD B,5 ;Put it back into view
CALL XVDCTL
POP HL ;Restore old cursor position
CALL TOSCRPOS ;Position the cursor
LD A,14 ;Turn the cursor back on
CALL CONOUT
POP AF ;Get the character typed back
JR INCH00 ;Loop back to process character
;
INTCH1 AND 137O ;Convert back to uppercase
IFANOT 'B',INTCH2 ;Is it BREAK, if not try next
CALL DOBRK ;Send BREAK out port
JP RSKP ;Return NO error
INTCH2 LD A,B ;Get the real character
IFANOT '0',INTCH3 ;Is it NULL, if not try next
LD E,0 ;Get a NULL
CALL OUTCHR ;Out the port with it
JP RSKP ;Return no error
INTCH3 LD E,B ;Get the real character
LD A,(ESCCHR) ;Get the escape character
IFA E,INTCHZ ;Is it the escape character ?
LD A,B ;Get the real character
AND 137O ;Upper case again
IFANOT 'Q',INTCH4 ;Is it QUIT, if not try next
LD A,(LOGFLG) ;Get the logging flag
IFANOT 2,INTC3A ;Is logging active, jump if not
DEC A ;Turn logging off
LD (LOGFLG),A ;Set the value
JP RSKP ;Return no error
INTC3A LD A,BELL ;Get An error sound
CALL CONOUT ;BEEP AT THEM
JP RSKP ;Return no error
INTCH4 IFANOT 'R',INTCH5 ;Resume logging? Jump if not
LD A,(LOGFLG) ;Check logging status
IFANOT 1,INTC3A ;If not 1, can't resume
INC A ;Turn logging on
LD (LOGFLG),A ;Set the value
JP RSKP ;Return no error
INTCH5 LD A,E ;Get the character typed
CALL PRTOUT ;Send it out the port
JP RSKP ;Return no error
INTCHZ CALL OUTCHR ;Send it out the port
LD A,BELL ;Get a bell
CALL CONOUT ;Send bell to terminal
JP RSKP ;Return no error
;
; Send character to printer
;
PRTIT EQU $
LD A,E ;Get the character
PUSH DE ;Save E for return
CALL XPRT ;Dos printer routine
POP DE ;Restore E
RET ;Return
;
; Generate a real modem break
;
DOBRK LD C,1 ;OPTION 1 OF @CTL
LD DE,(CLDCB) ;Get the *CL DCB
CALL XCTL ;Do @CTL to start Modem break
DI ;Make the pause be exact
LD BC,39000 ;Pause for 200ms
BRKLOOP DEC BC ;Decrement the count
LD A,B
OR C
JR NZ,BRKLOOP ;Loop until done
EI
LD E,0 ;Stop break with any character
JP OUTCHR ;Null is good
;
; Output any none null character to the RS232 port
;
PRTOUT OR A ;Don't send NULLS
RET Z
LD E,A ;Get the character
JP OUTCHR ;Output it
;
; Log a character to the log file
;
LOGONE PUSH AF
PUSH DE
LD E,A
LD A,(LOGFLG)
OR A
LD A,E
CALL NZ,LOGIT
POP DE
POP AF
RET
;
; Output a character to *DO
;
CONOUT PUSH DE ;SAVE THE REGS
PUSH BC
PUSH AF
IFA BELL,BEEPON ;Go if bell
CALL XDSP ;Use the @DSP SVC to display it
CON010 POP BC ;Use BC to get A, and not destroy flags
LD A,B ;Get the old A
POP BC
POP DE
RET ;RETURN TO THE CALLER
;
; Output a character to *SO
;
TRMOUT PUSH DE ;Save the regs
PUSH BC
PUSH AF
LD E,A ;Make a copy of the character
LD A,(EMULFLAG) ;Get the emulation flag
IFZ TRMOUT3 ;Jump if EMULATION set to NONE
;
; Certain control characters are translated on input. In
; particular, the following mappings are in effect.
;
; 8 -> 24 non destructive backspace
; 10 -> 26 non destructive linefeed
; 13 -> 29 True carriage return
;
LD A,E ;Is this a control character?
IFAGE 32,TRMOUT3 ;Jump if not a control character
LD HL,TRTAB ;Get the translation table
LD B,0 ;Make BC an offset into TRTAB
;
; If the character in the translation table is 0, then it is
; ignored. This is handy for blocking out things like cursor
; on/off, and inverse video on/off
;
LD C,A ;Get the character to use as index
ADD HL,BC ;Index to the table
LD A,(HL) ;Get the translated character
IFZ TRMOUT5 ;Return if character is to be ignored
LD E,A ;Make a copy for later
IFANOT 12,TRMOUT1 ;Jump if not a formfeed
CALL CMBLNK ;Clear the screen
JR TRMOUT5
TRMOUT1 IFANOT 7,TRMOUT3 ;Jump if not bell
CALL CONOUT ;DUMB uses BUILTIN Bell
JR TRMOUT5
TRMOUT3 EQU $
LD A,E ;Get the character
LD DE,(TMODCB) ;Get the Device DCB for terminal out
CALL XPUT ;@PUT the character to the device
TRMOUT5 POP BC ;Use BC to get A, and leave Flags alone
LD A,B ;Get A
POP BC ;Restore BC
POP DE ;And the rest
RET
;
; Input a character from *SI
;
TRMIN PUSH DE
PUSH BC
LD DE,(TMIDCB) ;Get the terminal input DCB
CALL XGET ;@GET a character
POP BC ;Restore the regs
POP DE
RET
;
; Sound a bell
;
BEEPON LD A,(BELFLG) ;IS THAT OPTION ON?
IFZ CON010 ;Jump if bell option off
PUSH BC ;Save counter
LD C,50 ;Get the duration
BEEP1 LD A,1 ;Get the value to send out port
OUT (90H),A ;Toggle port high
LD B,130 ;Delay
DJNZ $
DEC A ;Set A to zero
OUT (90H),A ;Toggle port low
LD B,130 ;Delay
DJNZ $
DEC C ;Decrement duration
JR NZ,BEEP1 ;Loop if not done
POP BC ;Restore counter
JR CON010 ;Join return code
;
; Print string pointed to by DE to *DO, EOS is end of string
; NUL characters are thrown out.
;
PRTSTR LD A,(DE) ;GET A CHARACTER
CP EOS ;IS IT THE END?
RET Z ;RETURN TO CALLER IF SO
OR A ;THROW AWAY THE NULL CHARACTER
CALL NZ,CONOUT ;DISPLAY ANYTHING NON-NULL
INC DE ;POINT TO THE NEXT ONE
JR PRTSTR ;LOOP ON
;
; Get a character from *KI
;
CONIN PUSH DE ;SAVE DE
CALL XKBD ;LOOK AT THE KEYBOARD WITHOUT WAITING
POP DE ;RESTORE DE
RET ;RETURN TO THE CALLER
;
; Output a character to *CL. The character is in E.
;
OUTCHR PUSH DE ;SAVE CURRENT DE AND BC
PUSH BC
LD C,E ;Put the character where it should be
OUTCH0 LD A,(XOFREC) ;CHECK TO SEE IF WE CAN TRANSMIT YET!
IFZ OUTCH2
;
; We allow break to force the transmittion of the character that
; is being sent. There are ways that the XON from the host can
; be lost. This allows control to be regained, without rebooting
; which would be the only other choice.
;
OUTCH1 CALL CONIN ;Check the break key
IFANOT 128,OUTCH0 ;Jump if not
XOR A ;Reset the XOF'd flag
LD (XOFREC),A
OUTCH2 LD A,C ;Get the character to send
OUTCH3 LD DE,(CLDCB) ;GET THE DCB OF THE DEVICE TO PUT TO
CALL XPUT ;SEND THE CHARACTER
JR NZ,OUTCH3 ;Transmitter may not be ready, loop if
; needed until character is transmitted
OUTCH4 POP BC ;Restore the regs
POP DE
RET
;
; Character input routine for INPKT. We can timeout on the
; receive by allowing the timer to place a return in the code
; below, at the address RECALRM. Since TRSDOS doesn't allow
; us (neatly, without a hack) to transfer control in a task,
; to some other code, we use the self modifying code. This
; may be considered dirty, but it does work. The RET causes
; the code to behave as though the user had pressed <ENTER> to
; resend the latest packet.
;
INCHR XOR A ;Get a NOP instruction
LD (RECALRM),A ;Remove any stored RET instruction
INCHR1 CALL CONIN ;Check keyboard first to make sure
IFNZ INCHR3
CALL INPORT ;Get a character from the buffer
JP Z,RSKP ;Return if we got one
RECALRM NOP ;Modified by timeout code to be a RET
JR INCHR
INCHR3 IFANOT CR,INCHR4 ;Check which key was pressed
LD A,(TASKSLOT) ;Get the active task
OR A ;See if task aqctive
RET Z ;Return if not
LD C,A ;Get the task slot into c
CALL XRMTSK ;Stop the task
RET ;Return resend status
INCHR4 CHKWKEY 'B'-64 ;Control-B for batch
CHKWKEY 'F'-64 ;Control-F for file
CHKWKEY 'A'-64 ;Control-A for status
CHKWKEY 'E'-64 ;Control-E for send error
CHKWKEY 'D'-64 ;Debug?
CHKWKEY 'H'-64 ;Help?
IFANOT 'C'-64,INCHR1 ;Control-C for abort completely
INCHR5 ADD A,40H ;MAKE IT PRINTABLE
LD (CZSEEN),A
RET
;
; Timer task for receiving a packet. Called every 33.333333333
; milliseconds. We decrement the TIMER counter, and when it
; goes to zero, we write a RET into the above code, and kill
; the task so that is does not return.
;
; Note that we must NOT leave anything on the stack when @KLTSK
; is called or else it will puke.
;
RECTIMOUT EQU $
PUSH HL ;Save the registers used
PUSH AF
LD HL,(TIMER) ;Get the counter
DEC HL ;Decrement it
LD (TIMER),HL ;Store the new value
LD A,H ;Check it for zero
OR L
JR NZ,RECT1
LD A,0C9H ;Get a RET instruction opcode
LD (RECALRM),A ;Write it in
POP AF ;Restore the register
POP HL
JP XKLTSK ;Remove this task, NO RETURN.
;
RECT1 POP AF ;Restore the registers
POP HL
RET ;Return
;
; Move cursor to position on screen
;
TOSCRPOS EQU $
LD B,3
JP XVDCTL
;end of file
<<< m4wild.asm >>>
; m4wild/asm
;
; Build a list of filenames given a list of arbitrary names
; pointed to by HL. Wild card processing is done here.
;
; The resulting blank separated list is returned in HL. The
; number of names put into the buffer is indicated by the
; count in FILECNT. This is a byte valued count, so 255 is
; the maximum number possible.
;
BUILDF EQU $
LD (SRCPTR),HL ;Save the source input pointer
LD HL,FILEBUFF ;Set the pointer to the matches
LD (FBPTR),HL ;buffer where all matches go
XOR A ;Set number of files found to 0
LD (FILECNT),A
BF_0 EQU $
LD HL,(SRCPTR) ;Get the input string
LD BC,0 ;Get zero
LD (SYSFLAG),BC ;No system files
LD (INVFLAG),BC ;No invisible files
XOR A ;Reset response values
LD (INVRESP),A
LD (SYSRESP),A
LD A,' '
BF_A IFANOT (HL),BF_B
INC HL
JR BF_A
;
BF_B LD DE,PARMS ;Get the parse table
CALL XPARAM ;Do @PARAM SVC
JR Z,BF_D ;Jump if parse ok
BF_C STROUT BADPARM ;Print error message
JP KERMIT ;Abort!
;
BF_D LD A,(SYSRESP) ;Get the system response
AND 0A0H ;Valid?
JR NZ,BF_C ;Jump if not
LD A,(INVRESP) ;Check invisble flag
AND 0A0H ;Valid?
JR NZ,BF_C ;Jump if not
LD A,' ' ;Get a space to compare with
BF_E IFANOT (HL),BF_F ;Jump if not space
INC HL
JR BF_E
;
BF_F LD B,32 ;Move 32 characters, MAX
LD DE,TFBUF ;Get the temporary buffer
BF_1 LD A,(HL) ;Get a character
IFALT ' '+1,BF_2 ;Jump if at end of this filename
CALL CPTAL ;Capitalize it
LD (DE),A ;Save the new character
INC DE ;Increment the pointers
INC HL
DJNZ BF_1 ;Loop until done
BF_2 XOR A ;Terminate the string with a zero
LD (DE),A ;Put in a terminator
BF_3 LD A,(HL) ;Get the next character
IFAGE ' '+1,BF_4 ;Jump if not separator
IFA CR,BF_4 ;Jump if end of string
INC HL ;Skip the separator
JR BF_3 ;Loop on
;
BF_4 LD (SRCPTR),HL ;Save the next string pointer
LD A,32 ;Get the max length
SUB B ;Compute length
LD (FNLEN),A ;Save it
JP Z,BF_18 ;Exit if no more names
LD A,1 ;Initially check all drives
LD (MOREDRV),A ;Set the flag
DEC DE ;Check if '/' last character
EX DE,HL ;Put it in HL
LD A,(HL) ;Get the character
IFANOT '/',BF_5 ;Is it a '/'
LD (HL),0 ;Remove the trailing slash
BF_5 LD HL,TFBUF ;Look for a drive specification
LD A,(FNLEN) ;Get the length
LD C,A ;Make BC a 16 bit copy of A
LD B,0
ADD HL,BC ;Compute end of name plus one
DEC HL ;Backup to possible drive number
DEC C ;Decrement the counter
JR Z,BF_7 ;Jump if no characters left
DEC HL ;Backup to possible ':' separator
DEC C ;Decrement counter
JR Z,BF_7 ;Jump no characters left
LD A,(HL) ;Get a possible ':'
IFANOT ':',BF_7 ;Jump if not drive spec
LD (HL),0 ;Terminate with no drive number
INC HL ;Point back at drive number
LD A,(HL) ;Get the drive number
LD HL,FNLEN ;Change the length
DEC (HL)
DEC (HL)
SUB '0' ;Make the drive number binary
LD C,A ;Save the drive to check
XOR A
LD (MOREDRV),A ;No more drives to check
JR BF_8
;
BF_7 EQU $
XOR A ;Zero A
LD C,A ;Set drive number to zero
BF_8 EQU $
PUSH BC ;Save the current drive number
CALL XCHKDRV ;Check this drive
JP NZ,BF_17 ;Jump if drive not ready
LD HL,DIRSPEC ;Get the source of 'DIR/SYS'
LD DE,DIRFCB ;Put it here
LD BC,DLEN ;Move this many characters
LDIR ;Copy the name
POP BC ;Get the drive number
PUSH BC ;Put it back
LD A,C ;Put it into A
ADD A,'0' ;Make it printable
LD (DIRDRV),A ;Set the drive number
LD (SDIRDRV),A ;Save the current drive
LD A,CR ;Get a EOL marker
LD (DIRDRV+1),A ;Put in a terminator
LD HL,DIRBUFF ;Get the buffer
LD B,0 ;LRECL = 256
LD DE,DIRFCB ;Get the FCB
CALL XOPEN ;Try to open the directory
JP NZ,BF_19 ;Jump on open error
LD DE,DIRFCB ;Get the FCB
CALL XSKIP ;Skip HIT and GAT
CALL XSKIP
BF_9 EQU $
LD HL,DIRBUFF ;Get the data buffer
LD DE,DIRFCB ;Get the FCB
CALL XREAD ;Read a record
JP NZ,BF_15 ;Jump if can't read anymore
LD B,8 ;Number of dir entries
LD HL,DIRBUFF ;Get the starting data
BF_10 PUSH BC ;Save the counter
BIT 4,(HL) ;Check for used directory record
JR Z,BF_12 ;Jump entry not in use
BIT 7,(HL) ;Check if FPDE
JR NZ,BF_12 ;Jump if extent or other
LD A,(SYSFLAG) ;Check is system file valid
IFNZ BF_10A ;Jump if system OK
BIT 6,(HL) ;Is it a system file
JR NZ,BF_12 ;Skip it if it is
BF_10A LD A,(INVFLAG) ;Is invisible file valid?
IFNZ BF_10B ;Jump if invisble ok (no check)
BIT 3,(HL) ;Is the file invisible?
JR NZ,BF_12 ;Skip it if it is
BF_10B LD DE,TFBUF ;Get the pattern to match
LD A,1
LD (HASWILD),A ;Set wild cards present flag
CALL ISWILD ;Check if it really is
JR Z,BF_11 ;Jump if there are wild cards
XOR A
LD (HASWILD),A ;Reset has wild cards flag
BF_11 EQU $
CALL MATCH ;See if it matches
JR NZ,BF_12
CALL COPYFILE ;Copy it if it matches
LD A,(HASWILD) ;Check if should check others
IFNZ BF_12 ;Jump if wild, might be more
POP BC ;Otherwise, no wild, so keep only
POP BC ;the first match as in TRSDOS's
JP BF_0 ;normal drive search algorithm
;
BF_12 LD BC,32 ;Get the length of a DIR record
ADD HL,BC ;Point to next
POP BC ;Restore the number of entries
DJNZ BF_10 ;Decrement and loop if not end
JR BF_9 ;Try next drive
;
; Control comes to here on an error in the call to @READ. Check
; to make sure it is EOF, and print an error message if not.
;
BF_15 EQU $
CP 28 ;Check for end of file
JR Z,BF_16 ;Jump if end of file
CALL XERROR0 ;Print the error message
LD DE,DIRFCB ;Close the open file
CALL XCLOSE
JP KERMIT ;Abort completely
;
BF_16 EQU $
LD DE,DIRFCB ;Close the directory
CALL XCLOSE ;Closed
JP NZ,BFCLSERR ;Jump if close error
BF_17 EQU $
POP BC ;Restore drive number
INC C ;Next drive
LD A,8 ;Get max drive number (plus 1)
CP C ;Get next name if no more drvs
JP Z,BF_0 ;Go get next name if end
LD A,(MOREDRV) ;See if should check other drvs
OR A ;Check for zero
JP NZ,BF_8 ;If set, then no drive spec so go
JP BF_0 ;Get the next filename in list
;
; At the end of processing, we update the end of the list of names,
; and return the pointer to the start of the list in HL.
;
BF_18 EQU $
LD HL,(FBPTR) ;Get the pointer
LD (HL),CR ;Terminate the string
LD HL,FILEBUFF ;Return the start of the list
RET
;
; Control comes to here on a directory open error. Print the error
; message, and then go check next drive.
;
BF_19 EQU $
CALL XERROR0
JR BF_17
;
; Control comes to here if CLOSE on DIR/SYS fails.
;
BFCLSERR EQU $
CALL XERROR0 ;Print the error message
JP KERMIT ;Return to command level
;
; Do a wild card match on the 2 strings pointed to by
; HL, and DE. DE points at the pattern containing possible
; wild card characters. HL points at the start of a TRSDOS
; complete directory record. HL must be moved to the start
; of the filename. The filename HL points to has up to 11
; characters in it. The first 8 are the filename, the last
; 3 are the extension. Both are left justified within their
; respective fields, with blanks as fill.
;
MATCH EQU $
PUSH BC ;Save BC
PUSH HL ;Save HL
PUSH DE ;Save DE
LD BC,5 ;Move HL to filename field
ADD HL,BC ;Move the pointer
;
; We must now convert the filename in the directory record
; to have the '/' in it. I.E. the entry may look like:
;
; DIR+5 DIR+15
; +-+-+-+-+-+-+-+-+-+-+-+
; |F|I|L|E| | | | |C| | |
; +-+-+-+-+-+-+-+-+-+-+-+
;
; So we must make the name be FILE/C
;
LD DE,COMPNAME ;Get the destination
LD BC,0B30H ;Number of characters to move
;
; Note that C has a big enough value in it to keep the LDI
; below from changing B which is the loop counter.
;
MATCH_1 LD A,(HL) ;See if at the end of name
INC HL ;Point a head in case ' ' is next
IFA ' ',MATCH_3 ;Skip spaces if at one
DEC HL ;Move back, valid character
LD A,B ;Check if time for '/'
IFANOT 3,MATCH_2 ;If B is 3, then put in a '/'
LD A,'/' ;Get the '/'
LD (DE),A ;Put it in the destination
INC DE ;Point to next position
MATCH_2 LDI ;Move the current character
MATCH_3 DJNZ MATCH_1 ;Loop until all moved
XOR A ;Put in a terminating NULL
LD (DE),A
POP DE ;Get the wild card pattern back
PUSH DE ;Save it again
LD HL,COMPNAME ;Get the name to compare against
;
; Now the matching process starts
;
; From C-Kermit's wild carding, this is the function match()
; HL is string, DE is pattern. There are some things different
; here, but this is mostly a line by line translation.
;
;
LD A,(HL) ;Check for null strings
IFZ NOMATCH ;Return if no match
LD A,(DE) ;Check for null pattern
IFZ NOMATCH ;Return if no match
;
LD (SPAT),DE ;Save current pattern spot
LD (SSTR),HL ;Save current string spot
LD HL,0 ;Reset the 2 pointers
LD (PSAVE),HL
LD (SSAVE),HL
;
MATCH_6 EQU $
LD HL,(SSTR) ;Get the pointer
LD A,(HL) ;Check for end of str
IFZ MATCH_9 ;Jump if at the end
;
LD DE,(SPAT) ;Ge&t the pattern pointer
LD A,(DE) ;Get the character
CP (HL) ;Do the characters match
JR NZ,MATCH_9
INC HL ;Increment the pointers
INC DE
LD (SPAT),DE ;Save the new values
LD (SSTR),HL
JR MATCH_6 ;Loop until done
;
MATCH_9 EQU $
LD A,(HL) ;Check if a match was found
IFNZ MATCH_10 ;Jump if not at end
LD DE,(SPAT) ;Get the pattern pointer
LD A,(DE) ;Check if at end of pattern
IFNZ MATCH_10 ;Jump if not at end
MATCHED CP A ;Set Z status
POP DE ;Restore the saved registers
POP HL
POP BC
RET ;Return the matched status
;
MATCH_10 EQU $
LD DE,(SPAT) ;Get the pattern pointer
LD A,(DE) ;Get the pattern character
IFANOT '$',MATCH_12 ;Jump if not '$'
INC HL ;++sstr
INC DE ;++spat
LD (SSTR),HL
LD (SPAT),DE
JR MATCH_20 ;Skip else case
;
MATCH_12 EQU $
IFANOT '*',MATCH_15 ;Jump if not '*'
INC DE ;Move pattern forward
LD (SPAT),DE ;Save the new value
LD (PSAVE),DE
LD (SSAVE),HL ;Match Zero characters
JR MATCH_20
;
MATCH_15 EQU $
LD HL,(SSAVE) ;Get the saved position
LD A,H ;Check if null pointer
OR L
JR Z,MATCH_17 ;Jump if pointer NULL
LD A,(HL) ;Check if end of string
IFZ MATCH_17 ;Jump if at the end
INC HL
LD (SSTR),HL ;sstr = ++ssave;
LD (SSAVE),HL ;Save new value
LD HL,(PSAVE)
LD (SPAT),HL ;spat = psave;
JR MATCH_20
;
MATCH_17 EQU $
NOMATCH LD A,1 ;Set NZ status
CP 0
POP DE ;Restore the saved registers
POP HL
POP BC
RET ;Return to caller
;
MATCH_20 EQU $
JP MATCH_6 ;Loop
;
; This function takes the string in the COMPNAME data area, and
; appends it to the list of filenames already collected.
;
COPYFILE EQU $
PUSH DE ;Save the regs
PUSH HL
PUSH BC
LD HL,COMPNAME ;Get name matched
LD DE,(FBPTR) ;Get the current position
PUSH DE ;Save address to print from
COPYF_1 EQU $
LD A,(HL) ;Check for end of string
IFZ COPYF_3 ;Jump if at the end
LDI ;Move a character
PUSH HL ;Save HL
PUSH DE ;Copy DE to HL
POP HL
LD BC,FILEBUFF+BUFFSIZE ;Get the end of buffer
OR A ;Reset the carry
SBC HL,BC ;Check for too far
POP HL ;Restore HL back
JR NZ,COPYF_1 ;Loop if not too far
STROUT OUTOFSTR ;Print a message
JP KERMIT
;
COPYF_3 EQU $
PUSH DE
POP HL ;Copy DE to HL
LD BC,FILEBUFF+BUFFSIZE-4 ;Get max for following
OR A
SBC HL,BC ;Compute remaining
JR NZ,COPYF_5
COPYF_4 STROUT OUTOFSTR ;Print message
JP KERMIT ;Abort
;
COPYF_5 LD A,':' ;Put in the drive delimiter
LD (DE),A ;Store it
INC DE ;Point ahead one
LD A,(SDIRDRV) ;Get the drive number
LD (DE),A ;Store it
INC DE ;Point ahead one more
LD A,' ' ;Add a space at the end
LD (DE),A ;Store it
INC DE ;Point ahead
LD A,EOS ;Get the end of string character
LD (DE),A ;Put in a terminator
LD (FBPTR),DE ;Save the new pointer
LD HL,FILECNT ;Increment the number of files
LD A,(HL) ;Get the current count
PUSH AF ;Save the count
INC (HL) ;Add one to counter
IFNZ COPYF_6 ;Jump if not first
LD A,(LOGNAMES) ;Check if should print anything
IFZ COPYF_6 ;Jump if not
STROUT FILESFND ;Print the message only once
COPYF_6 EQU $
POP AF
IFA 255,COPYF_4 ;Jump if not too many names
POP DE ;Get the string
LD A,(LOGNAMES) ;Check if should print anything
IFZ COPYF_7 ;Jump if not
CALL PRTSTR ;Print the string
CALL NEWLIN ;Get a new line
COPYF_7 EQU $
POP BC ;Restore the registers
POP HL
POP DE
RET ;Return to caller
;
; Check if any wild card characters are in the string pointed
; to by HL. Return Z status if there are, NZ if there are not
;
ISWILD EQU $
PUSH HL ;Save the strings address
PUSH DE
EX DE,HL
ISWILD_1 LD A,(HL) ;Get a character
IFZ ISWILD_2 ;End of string? Jump if so
IFA '$',ISWILD_4 ;Jump if it is a wild card
IFA '*',ISWILD_4 ;Jump if it is a wild card
INC HL ;Point to next character
JR ISWILD_1 ;Loop until there
;
ISWILD_2 EQU $
INC A ;Set NZ
ISWILD_3 POP DE ;Restore the registers
POP HL
RET ;Return to caller
;
ISWILD_4 EQU $
CP A ;Set Z status
JR ISWILD_3 ;Return
; end of file
<<< m4xfer.asm >>>
; M4XFER/ASM
;
; FILE ROUTINES
;
; Output the characters in a packet
;
PTCHR LD HL,PUTFILE
CALL DECODE
JP Z,RSKP
RET
;
; Get a packets worth of data
;
GTCHR LD A,(EOFLAG) ;Check for EOF
OR A ;Set or reset Z
RET NZ ;Return if EOF occured
CALL GETPKT ;Get a packets worth
JP RSKP ;Return saying that something is there
;
; Put a character to a file
;
PUTFILE LD DE,(RFIDCB) ;Get the DCB address
CALL XPUT ;Output the character
RET Z ;Return if no error
CALL XERROR0 ;Print an error message
LD A,'X' ;Set EOT flag
LD (CZSEEN),A
RET ;Return to caller
;
; Put a character to the buffer
;
PUTDATA PUSH HL ;Save the pointer
LD HL,(RMTPTR) ;Get the pointer to the start
LD (HL),A ;Store the character
INC HL ;Point to next
LD (HL),0 ;Terminate the string
LD (RMTPTR),HL ;Save the new pointer
POP HL ;Restore the pointer
CP A ;Set Z status
RET ;Return
;
; Get a character from the packet, doing all necessary decoding
;
GETDATA PUSH HL ;Save HL
LD (RMTPTR),HL ;Store as the place to but the data
LD HL,PUTDATA ;Get the address of the routine
CALL DECODE ;Decode it
POP HL ;Restore HL
RET ;Return to caller
;
; Call this address to call the address in HL
;
CALLHL JP (HL)
RET
;
; Get the next file name pointed to by MFNPTR and put it in FCB.
; If no more names are available, then the Carry Flag will be
; set apon return. Otherwise, NC will exist, and FCB will
; contain a valid TRSDOS filename.
;
MFNAME PUSH BC ;Save the registers
PUSH DE
PUSH HL
LD B,32 ;Blank the FCB
LD HL,MFREQ
PUSH HL
LD A,32
MFN0A LD (HL),A
INC HL
DJNZ MFN0A
LD HL,(MFNPTR) ;Get the start of the next name
POP DE ;Get the destination
CALL XFSPEC ;Move and convert
LD (MFNPTR),HL ;Save start of next name
PUSH AF ;Save the returned flags
LD HL,MFREQ ;Get the source
PUSH HL ;Make a copy
LD DE,TFILNAM ;Get the destination
LD BC,32 ;Get the byte count
LDIR ;Move them
LD HL,TFILNAM ;Terminate the string with EOS
LD A,3 ;Find the ETX
LD BC,32 ;Only look this far
CPIR ;Find it
DEC HL ;Back up to the ETX
LD (HL),EOS ;Put in an ETX
POP HL ;Restore the source address
LD DE,FCB ;Get the FCB destination
CALL XFSPEC ;Move a copy into FCB
POP AF ;Restore the return flags
SCF ;Set initial return flag
JR NZ,MFFIX1 ;Abort on error
CCF ;Reset Carry to return valid name
MFFIX1 POP HL ;Restore the registers
POP DE
POP BC
RET ;Return to the caller
;
; Open the filename in FCB for output
;
GETFIL LD A,0FFH
LD (FILFLG),A ;No file open
XOR A ;Get zero
LD (EOFLAG),A ;Not the end of file
LD (LSTCHR),A ;No previous character
PUSH HL
LD DE,FCB ;Get the FCB
LD HL,BUFF ;Get the data buffer
LD B,0 ;Select LRL=256
CALL XOPEN ;Open the file (at least try)
POP HL ;Restore old HL
JR Z,GETFIL1 ;Return if normal open
;
; The following code handles files with LRL's different then
; 256. The LRL open fault can be ignored in this case.
;
CP 42 ;Check for different LRL ERROR
JP NZ,ERRORD ;If not, then error
GETFIL1 JP RSKP ;Ignore LRL open fault
;
; PACKET ROUTINES
;
; Send a packet out the comm port
;
; This routine assembles a packet from the arguments given and
; sends it out the communications port
;
; Arguments:
;
; A - TYPE OF PACKET (D,Y,N,S,R,E,F,Z,T)
; ARGBLK - PACKET SEQUENCE NUMBER
; ARGBLK+1 - NUMBER OF DATA CHARACTERS
;
SPACK LD (ARGBLK+2),A ;Save data for resend to use
LD HL,PACKET ;GET ADDRESS OF THE SEND PACKET.
LD A,(SSOHCH) ;GET THE START OF HEADER CHAR.
PUTHL A ;PUT IN THE PACKET.
LD A,(CURCHK) ;GET CURRENT CHECKSUM TYPE
SUB '1' ;DETERMINE EXTRA LENGTH OF CHECKSUM
LD B,A ;COPY LENGTH
LD A,(ARGBLK+1) ;GET THE NUMBER OF DATA CHARS.
ADD A,' '+3 ;Real packet length made printable
ADD A,B ;DETERMINE OVERALL LENGTH
PUTHL A ;Put in the packet
LD B,0 ;ZERO THE CHECKSUM AC.
LD C,A ;START THE CHECKSUM.
LD A,(ARGBLK) ;GET THE PACKET NUMBER.
TOCHAR ;ADD A SPACE SO THE NUMBER IS PRINTABLE.
PUTHL A ;Put in the packet
CALL NXTSUM ;Get next checksum value
LD A,(ARGBLK+2) ;GET THE PACKET TYPE.
PUTHL A ;Put in the packet
CALL NXTSUM
SPACK2 LD A,(ARGBLK+1) ;GET THE PACKET SIZE.
IFZ SPACK3
DEC A ;DECREMENT THE CHAR COUNT.
LD (ARGBLK+1),A ;PUT IT BACK.
LD A,(HL) ;GET THE NEXT CHAR.
INC HL ;POINT TO NEXT CHAR.
CALL NXTSUM ;Compute next checksum
JR SPACK2 ;GO TRY AGAIN.
SPACK3 LD A,(CURCHK) ;GET THE CURRENT CHECKSUM TYPE
IFA '2',SPACK4
JR NC,SPACK5 ;Go do CRC if '3'
LD A,C ;GET THE CHARACTER TOTAL.
AND 0C0H ;TURN OFF ALL BUT THE TWO HIGH ORDER BITS
RLCA ;TWO LEFT ROTATES SAME AS 6 RIGHTS
RLCA ;. . .
ADD A,C ;ADD IT TO THE OLD BITS.
AND 3FH ;TURN OFF THE TWO HIGH ORDER BITS.
TOCHAR ;ADD A SPACE SO THE NUMBER IS PRINTABLE.
PUTHL A ;Put in the packet
JP SPACK7 ;GO STORE EOL CHARACTER
;
;HERE FOR 3 CHARACTER CRC-CCITT
;
SPACK5 LD (HL),0 ;STORE A NULL FOR CURRENT END
PUSH HL ;SAVE H
LD HL,PACKET+1 ;POINT TO FIRST CHECKSUMED CHARACTER
CALL CRCCLC ;CALCULATE THE CRC
POP HL ;RESTORE THE POINTER
LD C,E ;GET LOW ORDER HALF FOR LATER
LD B,D ;COPY THE HIGH ORDER
LD A,D ;GET THE HIGH ORDER PORTION
RLCA ;SHIFT OFF LOW 4 BITS
RLCA ;. . .
RLCA ;. . .
RLCA ;. . .
AND 0FH ;KEEP ONLY LOW 4 BITS
TOCHAR ;PUT INTO PRINTING RANGE
LD (HL),A ;STORE THE CHARACTER
INC HL ;POINT TO NEXT POSITION
;
;HERE FOR TWO CHARACTER CHECKSUM
;
SPACK4 LD A,B ;GET HIGH ORDER PORTION
AND 0FH ;ONLY KEEP LAST FOUR BITS
RLCA ;SHIFT UP TWO BITS
RLCA ;. . .
LD B,A ;COPY BACK INTO SAFE PLACE
LD A,C ;GET LOW ORDER HALF
RLCA ;SHIFT HIGH TWO BITS
RLCA ;TO LOW TWO BITS
AND 03H ;KEEP ONLY TWO LOW BITS
OR B ;GET HIGH ORDER PORTION IN
TOCHAR ;CONVERT TO PRINTING CHARACTER RANGE
PUTHL A ;Store the character
LD A,C ;GET LOW ORDER PORTION
AND 3FH ;KEEP ONLY SIX BITS
TOCHAR ;CONVERT TO PRINTING RANGE
PUTHL A ;Store the character
SPACK7 LD A,(SEOL) ;GET THE EOL THE OTHER HOST WANTS.
PUTHL A ;Store the character
PUTHL 0 ;End with a NULL
LD A,(DBFLG)
OR A
JR Z,SPACK8 ;debug is off
PUTHL EOS ;Add terminator
SPACK8 CALL OUTPKT ;CALL THE SYSTEM DEPENDENT ROUTINE.
JP QUIT
JP RSKP
;
; WRITE OUT A PACKET.
;
OUTPKT LD A,(SPAD) ;GET THE NUMBER OF PADDING CHARS.
LD B,A
OUTPK2 DEC B
JP M,OUTPK4
LD A,(SPADCH) ;GET THE PADDING CHAR.
LD E,A ;PUT THE CHAR IN RIGHT AC.
CALL OUTCHR ;OUTPUT IT.
JR OUTPK2
OUTPK4 LD A,(DBFLG)
IFZ OUTPK5 ;If not on, then check for logfile
STROUT SPPOS ;Print the SPACK=> message
STROUT PACKET+1 ;Print the data
OUTPK5 LD A,(DEBLOG) ;See if logging in effect
IFZ OUTPK7 ;If not, then finish up
LD DE,DFCB ;Get the debug FCB
TRLOG SPPOS,OUTPK6 ;Log the SPACK=> message
TRLOG PACKET,OUTPK6 ;Log the packet data
JR OUTPK7
OUTPK6 XOR A
LD (DEBLOG),A
LD DE,DFCB
CALL XCLOSE
OUTPK7 LD HL,PACKET ;POINT TO THE PACKET.
OUTPK10 LD A,(HL) ;GET THE NEXT CHARACTER.
IFZ OUTPK11 ;Return success if EOS found
LD E,A ;PUT THE CHAR IN RIGHT AC.
CALL OUTCHR ;OUTPUT THE CHARACTER.
INC HL ;INCREMENT THE CHAR POINTER.
JR OUTPK10
OUTPK11 LD A,(STURN) ;Is turn around needed?
IFZ OUTPK12 JUMP IF NOT NEEDED
LD E,A ;Get the character
CALL OUTCHR ;Output it
OUTPK12 JP RSKP ;Return no error
;
; Compute next checksum
;
NXTSUM ADD A,C
LD C,A
LD A,0 ;Must use load to preserve Carry flag
ADC A,B
LD B,A
RET
;
;THIS ROUTINE WAITS FOR A PACKET TO ARRIVE FROM THE HOST. IT READS
;CHARACTERS UNTIL IT FINDS THE SOH. IT THEN READS THE PACKET INTO PACKET.
;
;RETURNS +1 FAILURE (IF THE CHECKSUM IS WRONG OR THE PACKET TRASHED)
; +3 SUCCESS WITH A - MESSAGE TYPE
; ARGBLK - MESSAGE NUMBER
; ARGBLK+1 - LENGTH OF DATA
;
RPACK LD A,(RTIME) ;Get the timeout value
LD HL,0
IFZ RPACK1 ;If zero, then no timeout
LD L,A ;Get the value as 16 bits
LD C,30 ;Get the factor to extend it by
CALL XMUL16 ;Do the multiplication
LD H,L ;Slide the 24 bit result down
LD L,A
RPACK1 LD (SVTIMER),HL ;Save it as the timer value
RPACK2 CALL STARTTIMER ;Start the timer for receive timeout
CALL INPKT ;READ UP TO A CARRIAGE RETURN.
JP QUIT ;RETURN BAD.
CALL STOPTIMER ;Stop the timeout countdown
RPACK3 CALL GETCHR ;GET A CHARACTER.
JP RPACK2 ;HIT A CR;NULL LINE; JUST START OVER.
CALL CPRSOH ;IS THE CHAR THE START OF HEADER CHAR?
JR NZ,RPACK3 ;NO, GO UNTIL IT IS.
RPACK4 CALL GETCHR ;GET A CHARACTER.
JP QUIT ;HIT THE CARRIAGE RETURN, RETURN BAD.
CALL CPRSOH ;IS THE CHAR THE START OF HEADER CHAR?
JR Z,RPACK4 ;YES, THEN GO START OVER.
LD (PACKET+1),A ;STORE IN PACKET ALSO
LD C,A ;START THE CHECKSUM.
LD A,(CURCHK) ;GET BLOCK CHECK TYPE
SUB '1' ;DETERMINE EXTRA LENGTH OF BLOCK CHECK
LD B,A ;GET A COPY
LD A,C ;GET BACK LENGTH CHARACTER
SUB ' '+3 ;GET THE REAL DATA COUNT.
SUB B ;GET TOTAL LENGTH
LD (ARGBLK+1),A
LD B,0 ;CLEAR HIGH ORDER HALF OF CHECKSUM
CALL GETCHR ;GET A CHARACTER.
JP QUIT ;HIT THE CARRIAGE RETURN, RETURN BAD.
CALL CPRSOH ;IS THE CHAR THE START OF HEADER CHAR?
JR Z,RPACK4 ;YES, THEN GO START OVER.
LD (ARGBLK),A
LD (PACKET+2),A ;SAVE ALSO IN PACKET
CALL NXTSUM ;ADD THE CHARACTER TO THE CHECKSUM
LD A,(ARGBLK)
SUB ' ' ;GET THE REAL PACKET NUMBER.
LD (ARGBLK),A
CALL GETCHR ;GET A CHARACTER.
JP QUIT ;HIT THE CARRIAGE RETURN, RETURN BAD.
CALL CPRSOH ;IS THE CHAR THE START OF HEADER CHAR?
JR Z,RPACK4 ;YES, THEN GO START OVER.
LD (TEMP1),A ;SAVE THE MESSAGE TYPE.
LD (PACKET+3),A ;SAVE IN PACKET
LD (RECTYP),A
CALL NXTSUM ;ADD THE CHARACTER TO THE CHECKSUM.
LD A,(ARGBLK+1) ;GET THE NUMBER OF DATA CHARACTERS.
LD (TEMP2),A
LD HL,DATA ;POINT TO THE DATA BUFFER.
LD (DATPTR),HL
RPACK5 LD A,(TEMP2)
DEC A ;ANY DATA CHARACTERS?
JP M,RPACK6 ;IF NOT GO GET THE CHECKSUM.
LD (TEMP2),A
CALL GETCHR ;GET A CHARACTER.
JP QUIT ;HIT THE END-OF-LINE, RETURN BAD.
CALL CPRSOH ;IS THE CHAR THE START OF HEADER CHAR?
JR Z,RPACK4 ;YES, THEN GO START OVER.
LD HL,(DATPTR)
PUTHL A ;Store the character
LD (DATPTR),HL
CALL NXTSUM ;ADD THE CHARACTER TO THE CHECKSUM.
JR RPACK5 ;GO GET ANOTHER.
RPACK6 CALL CHKECHO ;See if only echo of previous
JP RPACK3 ;Yes, restart
CALL GETCHR ;Get a character
JP QUIT ;HIT THE CARRIAGE RETURN, RETURN BAD.
CALL CPRSOH ;IS THE CHAR THE START OF HEADER CHAR?
JP Z,RPACK4 ;YES, THEN GO START OVER.
SUB ' ' ;TURN THE CHAR BACK INTO A NUMBER.
LD (TEMP3),A
;DETERMINE TYPE OF CHECKSUM
LD A,(CURCHK) ;GET THE CURRENT CHECKSUM TYPE
IFA '2',RPACK9 ;Jump if 2 character
JR NC,RPACK8 ;Jump if 3 character
;
; 1 character checksum
;
LD A,C ;Get the character count
AND 0C0H ;Keep 2 MSB's
RLCA ;Move them to 2 LSB's
RLCA
ADD A,C ;Add the 2 low bits to bottom
AND 3FH ;Remove 2 high bits after add
LD B,A
LD A,(TEMP3) ;GET THE REAL RECEIVED CHECKSUM.
IFA B,RPACK10 ;Jump checksum OK
RPACK7 CALL UPDRTR ;If checksum bad, update retries
RET ;Return error
;
; Here for three character CRC-CCITT
;
RPACK8 LD HL,(DATPTR) ;GET THE ADDRESS OF THE DATA
LD (HL),0 ;Store a zero in the buffer as terminator
LD HL,PACKET+1 ;POINT AT START OF CHECKSUMMED REGION
CALL CRCCLC ;CALCULATE THE CRC
LD C,E ;SAVE LOW ORDER HALF FOR LATER
LD B,D ;ALSO COPY HIGH ORDER
LD A,D ;GET HIGH BYTE
RLCA ;WANT HIGH FOUR BITS
RLCA ;. . .
RLCA ;AND SHIFT TWO MORE
RLCA ;. . .
AND 0FH ;KEEP ONLY 4 BITS
LD D,A ;BACK INTO D
LD A,(TEMP3) ;GET FIRST VALUE BACK
IFANOT D,RPACK7 ;Jump if not correct
CALL GETCHR ;GET A CHARACTER.
JP QUIT ;HIT THE CARRIAGE RETURN, RETURN BAD.
CALL CPRSOH ;IS THE CHAR THE START OF HEADER CHAR?
JP Z,RPACK4 ;YES, THEN GO START OVER.
SUB ' ' ;REMOVE SPACE OFFSET
LD (TEMP3),A ;STORE FOR LATER CHECK
;
; Here for a two character checksum and last two characters of CRC
;
RPACK9 LD A,B ;GET HIGH ORDER PORTION
AND 0FH ;ONLY FOUR BITS
RLCA ;Shift up 2 bits
RLCA
LD B,A ;Save back into B
LD A,C ;Get low order byte
RLCA ;Move the 2 MSB's to 2 LSB's
RLCA
AND 03H ;Save only low 2 bits
OR B ;Get other 4 bits
LD B,A ;Save back into B
LD A,(TEMP3) ;Get this portion of the checksum
IFANOT B,RPACK7 ;If wrong, then give up
CALL GETCHR ;GET A CHARACTER.
JP QUIT ;HIT THE CARRIAGE RETURN, RETURN BAD.
CALL CPRSOH ;IS THE CHAR THE START OF HEADER CHAR?
JP Z,RPACK4 ;YES, THEN GO START OVER.
SUB ' ' ;REMOVE SPACE OFFSET
LD B,A ;SAVE IN SAFE PLACE
LD A,C ;GET LOW 8 BITS OF CHECKSUM
AND 3FH ;KEEP ONLY 6 BITS
IFANOT B,RPACK7 ;Jump if bad value
RPACK10 LD HL,(DATPTR)
PUTHL 0 ;End with a NULL
LD A,(TEMP1) ;GET THE TYPE.
JP RSKP
;
; Input a packet
;
INPKT LD HL,RECPKT ;POINT TO THE BEGINNING OF THE PACKET.
LD (PKTPTR),HL
INPKT2 CALL INCHR ;GET A CHARACTER.
JP INPKT7 ;Skip out if key typed that is valid
LD HL,(PKTPTR) ;Get the packet position
PUTHL A ;Store the character
LD (PKTPTR),HL ;Save the pointer
CALL CPREOL ;IS IT THE EOL CHARACTER?
JR NZ,INPKT2
PUTHL EOS ;Put in the terminator
LD A,(DBFLG)
IFZ INPKT3 ;Jump if debug off
STROUT RPPOS ;Output RPACK=> message
STROUT RECPKT+1 ;Print the received packet
INPKT3 LD A,(DEBLOG) ;See if debug log in on
IFZ INPKT6 ;Jump if not enabled
LD DE,DFCB ;Get the FCB
TRLOG RPPOS,OUTPK6 ;Log the RPACK=> message
TRLOG RECPKT+1,OUTPK6 ;Log the packet
INPKT6 LD HL,RECPKT
LD (PKTPTR),HL ;SAVE THE PACKET POINTER.
LD A,(RTURN) ;Get the turn around character
CALL WAITT ;Go wait for it.
JP RSKP ;Return no error
;
; Error return processing. This code deals with the keystrokes
; that are recognized in INCHR().
;
INPKT7 LD A,(CZSEEN)
IFANOT 'A',INPKT8 ;Status
CALL SHOTRANS ;Show the transfer status
JR INPKT16
INPKT8 IFANOT 'B',INPKT9 ;Cancel Batch?
LD A,'Z' ;Get the packet type
LD (CZSEEN),A
LD DE,CBATCH ;Get the cancel message
CALL CONDIS ;Print it if not doing REMOTE commands
JP INPKT2
INPKT9 IFANOT 'F',INPKT10 ;Cancel FILE?
LD A,'X' ;Get the PACKET type
LD (CZSEEN),A
LD DE,CFILE ;Get the cancel message
CALL CONDIS ;Print it if not doing REMOTE commands
JP INPKT2
INPKT10 IFANOT 'E',INPKT12 ;Send error, and ABORT?
XOR A
LD (CZSEEN),A ;Reset the key pressed flag
CALL STOPTIMER ;Stop the timer
LD A,ABRTMSGLEN ;Get length of message
LD (ARGBLK+1),A ;Save the length
LD HL,ABRTMSG ;Get the message
LD DE,DATA ;Where to put it
LD C,A ;Get the length in BC
LD B,0
LDIR ;Move the message
LD A,'E' ;Get the packet type
CALL SPACK ;Send the error packet
JP ABORT ;Give up on an error
JP KERMIT ;Give up completely
INPKT12 IFANOT 'C',INPKT14 ;Cancel transfer, immediately
XOR A
LD (CZSEEN),A ;Zap the old key pressed
CALL STOPTIMER ;Stop the timer
JP KERMIT ;Jump to restart
INPKT14 IFANOT 'D',INPKT18 ;Toggle debug mode?
LD A,(DBFLG) ;Get the debug flag
XOR 1 ;Toggle value
LD (DBFLG),A ;Store it back
INPKT16 XOR A ;Finish up handling, reset key pressed
LD (CZSEEN),A ;Reset the flag
JP INPKT2 ;Get the next character
INPKT18 IFANOT 'H',INPKT20 ;Help?
STROUT HELPMSG ;Print the message
JR INPKT16 ;Finish up
INPKT20 XOR A ;Otherwise, return no input to force
LD (CZSEEN),A ;resend to occur...
RET ;Return no input packet
;
GETCHR LD HL,(PKTPTR) ;GET THE PACKET POINTER.
LD A,(HL) ;GET THE CHAR.
INC HL
LD (PKTPTR),HL
CALL CPREOL ;IS IT THE END OF LINE
JP NZ,RSKP ;IF NOT RETURN RETSKP.
RET ;IF SO RETURN FAILURE.
;
; Assorted comparison routines
;
CPSSOH PUSH HL
LD HL,SSOHCH
CPSH10 CP (HL)
POP HL
RET
CPRSOH PUSH HL
LD HL,RSOHCH
JR CPSH10
CPSEOL PUSH HL
LD HL,SEOL
JR CPSH10
CPREOL PUSH HL
LD HL,REOL
JR CPSH10
CPSPAD PUSH HL
LD HL,SPADCH
JR CPSH10
CPRPAD PUSH HL
LD HL,RPADCH
JR CPSH10
CPSTME PUSH HL
LD HL,STIME
JR CPSH10
CPRTME PUSH HL
LD HL,RTIME
JR CPSH10
CPSQTE PUSH HL
LD HL,SQUOTE
JR CPSH10
CPRQTE PUSH HL
LD HL,RQUOTE
JR CPSH10
;
;THIS ROUTINE WILL CALCULATE A CRC USING THE CCITT POLYNOMIAL FOR
;A STRING.
;
;USAGE
; HL/ ADDRESS OF STRING
; A/ LENGTH OF STRING
; CALL CRCCLC
;
;16-BIT CRC VALUE IS RETURNED IN DE.
;
;REGISTERS BC AND HL ARE PRESERVED.
;
CRCCLC PUSH HL ;SAVE HL
PUSH BC ;AND BC
LD DE,0 ;INITIAL CRC VALUE IS 0
CRCCL0 LD A,(HL) ;GET A CHARACTER
OR A ;CHECK IF ZERO
JP Z,CRCCL1 ;IF SO, ALL DONE
PUSH HL ;SAVE THE POINTER
XOR E ;ADD IN WITH PREVIOUS VALUE
AND 0FH ;Keep only 4 bits
LD B,0
GETCRCTAB
CALL SRLDE4 ;Shift CRC right by 4
XORATHL E
INC HL
XORATHL D
POP HL
PUSH HL
LD A,(HL)
SRL A
SRL A
SRL A
SRL A
XOR E
AND 0FH
GETCRCTAB
CALL SRLDE4
XORATHL E
INC HL
XORATHL D
POP HL ;AND H
INC HL ;POINT TO NEXT CHARACTER
JP CRCCL0 ;GO GET NEXT CHARACTER
CRCCL1 POP BC ;RESTORE B
POP HL ;AND HL
RET ;AND RETURN, DE=CRC-CCITT
;
; Shift DE right by 4 bits
;
SRLDE4 SRL D
RR E
SRL D
RR E
SRL D
RR E
SRL D
RR E
RET
;
CRCTAB DW 00000H
DW 01081H
DW 02102H
DW 03183H
DW 04204H
DW 05285H
DW 06306H
DW 07387H
DW 08408H
DW 09489H
DW 0A50AH
DW 0B58BH
DW 0C60CH
DW 0D68DH
DW 0E70EH
DW 0F78FH
;
GETNPNT LD A,(HL)
INC HL
LD (OUTPNT),HL
RET
;
; Check if RFIDCB points at FCB.
;
CHKFCB LD DE,(RFIDCB) ;Get the current FCB/DCB pointer
LD HL,FCB ;Get the Address of FCB
OR A ;Reset the carry
SBC HL,DE ;Compute the difference
RET ;Return the flags
;
INCKTRANS PUSH HL ;Save the regs
PUSH AF
LD HL,(KTRANS) ;Get the current count
INC HL ;Add one to it
LD A,H ;Check for overflow
OR L ;Set the flags
LD A,1 ;Set the ok to change curtrans flag
CALL Z,ADD64K ;Add 64K if overflow
LD (KTRANS),HL ;Save the new counter
LD (CURTRANS),HL ;Store as current count too
POP AF ;Restore the regs
POP HL
RET ;Return to caller
;
; Add 64k to the current counter (RTRANS, or STRANS, as well as
; CURTRANS which is used for TRANSACTION logs).
;
ADD64K EQU $
PUSH HL ;Save the regs
LD L,(IX) ;Get the current Kbyte counter
LD H,(IX+1)
LD BC,64 ;Add 64 to it
ADD HL,BC
LD (IX),L ;Store it back
LD (IX+1),H
IFZ ADD64K_1
LD HL,(CURTRANS+2) ;Get the current value
ADD HL,BC ;Add 64
LD (CURTRANS+2),HL ;Store new value
ADD64K_1 POP HL ;Restore HL
RET ;Return
;
; Wait for the turn around character in A
;
TTURN DB 0
;
WAITT OR A ;Check for no turn around
RET Z ;return on ZERO
LD (TTURN),A ;Save the character
WAITT1 CALL INCHR ;Get a character
JP INPKT7 ;Process keyboard character
LD C,A ;Save the character
LD A,(TTURN) ;Check for turn around
CP C ;Is the character received it?
JR NZ,WAITT1 ;No, get another
RET
;
SHOTRANS EQU $
STROUT NPKTSTR ;Print number of packets
LD HL,(NUMPKT)
CALL NOUT
STROUT NRTRSTR ;Print retries
LD HL,(NUMRTR)
CALL NOUT
STROUT NCHRSTR ;Print number of characters
LD HL,(KTRANS)
CALL NOUT
STROUT NRECCH ;Number K of characters recvd
LD HL,(RTRANS)
CALL NOUT
LD A,'K'
CALL CONOUT
STROUT NSNDCH ;Print number of characters sent
LD HL,(STRANS)
CALL NOUT
LD A,'K'
CALL CONOUT
JP NEWLIN
;
CHKECHO PUSH BC
LD A,(SNDTYP)
LD C,A
LD A,(RECTYP)
CP C
POP BC
RET Z
JP RSKP
;
; Convert KERMIT filename to TRSDOS filename
;
GOFIL LD HL,RMTDATA ;Where to put the name
LD A,(ARGBLK+1) ;Number of characters
CALL GETDATA ;Get the name in RMTDATA (HL saved)
LD DE,MFREQ ;Destination
LD BC,8 ;Max characters for first field
GOFIL1 EQU $
LD A,(HL) ;At end of field?
IFA '.',GOFIL8 ;Jump if at separator
IFALT ' ',GOFIL15 ;Stop if at end of string
LD A,C ;Check range
IFANOT 8,GOFIL2 ;If not first character, then skip
LD A,(HL) ;Get the character
CALL ISALPHA ;Is it alphabetic?
JR Z,GOFIL5 ;Jump if it is
LD (HL),'Z' ;Change name
JR GOFIL5 ;Join code
GOFIL2 EQU $ ;Second or later character...
LD A,(HL)
CALL ISALNUM ;Is it alphanumeric?
JR Z,GOFIL5 ;Jump if so
INC HL ;Skip this one
JR GOFIL1 ;Go to the next character
GOFIL5 EQU $
LDI ;Move the character
LD A,B ;Check the remaining count
OR C
JR NZ,GOFIL1 ;Jump if still OK
GOFIL7 EQU $
LD A,(HL) ;Are we at the end yet
IFA '.',GOFIL8 ;Jump if at the separator
IFALT ' ',GOFIL15 ;Stop it at the end
INC HL ;Point to next source character
JR GOFIL7 ;Loop
GOFIL8 EQU $
LD A,C ;Check the count of characters moved
IFANOT 8,GOFIL9 ;Jump if at least one moved
LD A,'X' ;Use this as the first character
LD (DE),A ;Put it in
INC DE ;Point to next slot
GOFIL9 LD (HL),'/' ;Put in separator
LDI ;Move it too
LD BC,3 ;Length of next field
GOFIL10 EQU $
LD A,(HL) ;Get the character
IFALT ' ',GOFIL15 ;Jump if at the end
LD A,C ;Check ranges
IFANOT 3,GOFIL12 ;Jump if not first character
LD A,(HL) ;Get the character (Must be alphabetic)
CALL ISALPHA ;Is it alphbetic?
JR Z,GOFIL13 ;Jump if it is
LD (HL),'Z' ;Make it alphabetic
JR GOFIL13 ;Join other code
GOFIL12 EQU $ ;Second or third character in extension
LD A,(HL) ;Get the character back
CALL ISALNUM ;Is it alphanumeric?
JR Z,GOFIL13 ;Jump if so
INC HL ;Skip it
JR GOFIL10 ;Check the next one
GOFIL13 EQU $
LDI ;Move a char
LD A,B ;Check the count
OR C
JR NZ,GOFIL10 ;Loop if OK
GOFIL15 EQU $
PUSH DE ;Put dest into HL
POP HL
PUTHL ':' ;Add the default drive
LD A,(DEFDSK)
PUTHL A ;Add the drive number
LD (HL),EOS ;Add the end of string byte
PUSH HL ;Save that address
LD HL,MFREQ ;Move the string to the save area
LD DE,TFILNAM ;Get the destination
LD BC,32
LDIR ;Move the bytes
POP HL
LD (HL),3 ;Put in FSPEC terminator
LD (FCBPTR),HL ;Save the end
LD HL,MFREQ ;Validate the filespec
LD DE,FCB
CALL XFSPEC ;Call TRSDOS
JR Z,GOFIL18 ;Jump if OK
LD HL,(FCBPTR) ;Get end of string
LD (HL),EOS ;Put in print terminator
STROUT FCB ;Print the name
JP XERROR0 ;Print system error message and return
GOFIL18 LD HL,FCB ;Get start
LD BC,40 ;Maximum to look
LD A,':' ;Find drive spec to index off of
CPIR ;Look for it. MUST be there
INC HL ;Point after for terminator
LD (FCBPTR),HL ;Save it
DEC HL ;Back up to just after extension
DEC HL
LD (DATPTR),HL ;Save it for renaming
LD A,(FLWFLG) ;Is file warning on?
IFZ GOFIL30 ;Jump if not
LD DE,FCB ;Get the file name
LD HL,BUFF ;Buffer address
LD B,0 ;LRL=256
CALL XOPEN ;Is it there?
JR NZ,GOFIL30 ;Jump if not
LD DE,INFMS5 ;Print renaming message
CALL ERROR3
LD DE,FCB ;Close the file
CALL XCLOSE ;Close restores the filename with @FNAME
GOFIL20 LD HL,(DATPTR) ;Get the pointer to extension
LD DE,FCB ;Get the start
OR A ;Reset the carry
PUSH HL ;Save it
SBC HL,DE ;At the beginning yet
POP HL ;Restore it
JR NZ,GOFIL21 ;Jump if not
LD DE,ERMS16 ;Oops, Can't rename it, stop
JP PRTSTR ;Print, and return
;
GOFIL21 DEC HL ;Point to previous character
LD (DATPTR),HL ;Save the new pointer
GOFIL24 LD HL,(DATPTR) ;Get the pointer
LD A,(HL) ;Get the character
IFALT 'B',GOFIL20 ;Jump if we can't change it
DEC (HL) ;Change the file name
LD HL,FCB ;Get the source address
PUSH HL ;Save it for later
LD DE,TFILNAM ;Get the destination
LD BC,32 ;Number to move
LDIR ;Move them
POP DE ;Restore stack and get FCB address
LD HL,BUFF
LD B,0
CALL XOPEN ;Is it there?
JR NZ,GOFIL27 ;Jump if not
LD DE,FCB ;Close it up
CALL XCLOSE
JR GOFIL24 ;Try another name
;
GOFIL27 LD HL,(FCBPTR) ;Get the end of the file name
LD (HL),EOS ;Add the print terminator
STROUT FCB ;Print the new name
LD (HL),3 ;Put the @OPEN terminator back
GOFIL30 LD DE,FCB ;Get the FCB
LD HL,BUFF ;Get the buffer
LD B,0 ;LRL=256
CALL XINIT ;Create it or zap old file
JP Z,RSKP ;Return on success +4
PUSH AF ;Save error code
LD DE,ERMS11 ;Print the error message
CALL ERROR3
POP AF ;Get the error code back
JP ERRORD ;Print a system error
;
; Restart timer for receive packet timeout
;
STARTTIMER PUSH HL ;Save the clobbered regs
PUSH DE
PUSH BC
LD C,0 ;Get no timer flag for next test
LD HL,(SVTIMER) ;Get the timer value
LD A,H ;Check if not timeout wanted
OR L
JR Z,STARTT3 ;Don't start timer if none needed
LD (TIMER),HL ;Set the real counter
LD C,8 ;Get the task slot number
STARTT1 CALL XCKTSK ;Check is slot in use
JR NZ,STARTT2
LD DE,RECTIME ;Get the TCB
PUSH BC
CALL XADTSK ;Try to add the task
POP BC ;Restore the task slot
JR STARTT3 ;Go save slot used
STARTT2 INC C ;Get next possible slot
IFANOT 11,STARTT1 ;Loop if not at max task slot
STROUT NOTIMER ;Print error message
LD HL,1
LD (SVTIMER),HL ;Zap timer
LD C,0 ;Make sure no timer flag is on
STARTT3 LD A,C ;Save task to stop
LD (TASKSLOT),A
POP BC ;Restore registers
POP DE
POP HL
RET
;
; Stop the timeout task
;
STOPTIMER PUSH HL ;Save the registers
PUSH DE
PUSH BC
LD C,8 ;Get the task slot number
TASKSLOT EQU $-1
CALL XRMTSK
LD HL,0 ;Zero out the timer
LD (TIMER),HL
POP BC ;Restore the registers
POP DE
POP HL
RET
;
; Check if character in A is alphabetic. Z status means YES,
; NZ status means NO
;
ISALPHA CP 'A' ;Check upper case
RET C ;Return if less than
CP 'Z'+1 ;If less than or equal to Z, then A-Z
JR C,ISAL_1 ;Jump to TRUE return
CP 'a' ;Check lower case
RET C ;Return less than
CP 'z'+1 ;Check for a-z
RET NC ;NC means greater than 'z'
ISAL_1 CP A ;Set Z status
RET ;Return
;
; Check if character in A is alphanumeric
;
ISALNUM CP '0' ;Check digits
RET C ;Return too small
CP '9'+1 ;Check max+1
JR NC,ISALPHA ;If too big, go try alphabetic
CP A ;Set Z status
RET ;return it
; end of file
<<< m4mit.doc >>>
_T_R_S_-_8_0 _M_o_d_e_l _4_(_p_) _K_E_R_M_I_T_: _V_e_r_s_i_o_n _5_._2
_F_o_r _U_s_e _U_n_d_e_r _T_R_S_D_O_S _6_._1 _o_r _L_a_t_e_r
_P_r_o_g_r_a_m _b_y: Gregg Wonderly Oklahoma State University,
(gregg@okstate) rewritten from the origi-
nal Model-4 KERMIT which was derived from
the TRS-80 KERMIT done by Stan Barber,
Rice University who modified the CP/M-80
version by Bill Catchings and others.
_L_a_n_g_u_a_g_e: Z80 Assembler, compatible with M80 and
EDAS from Misosys
_V_e_r_s_i_o_n: 5.2
_D_a_t_e: Wed Oct 22 10:17:07 CDT 1986
_D_o_c_u_m_e_n_t_a_t_i_o_n _b_y: Gregg Wonderly
_1. _S_u_m_m_a_r_y _o_f _T_R_S_D_O_S _6._1
_T_R_S_D_O_S (The Radio Shack Disk Operating System) has a
large library of built in commands dealing with files,
directory maintenance, device I/O, etc. Programs are also
used for some functions on some _T_R_S_D_O_S-based DOS's. Model
4(p) KERMIT gives you access to all of the library commands
of _T_R_S_D_O_S versions 6.x via the LOCAL command. Issue the
_L_I_B_R_A_R_Y command at _T_R_S_D_O_S _R_e_a_d_y to obtain a list.
_T_R_S_D_O_S file specifications can be represented as a
sequence of characters of the form
FILESPEC/EXT.PASSWORD:D
_F_I_L_E_S_P_E_C is the filename up to eight characters.
_E_X_T is the file type, up to three characters.
_P_A_S_S_W_O_R_D is the password for that file, up to eight char-
acters.
_D is a numerical drive specification (0-7).
File names, file types and passwords may contain
letters and numbers, but the first character in each must be
a letter. No special characters or spaces are allowed. All
fields are optional except the filespec. Any field added
- 2 -
must be preceded by its special delimiter '/' for file type,
'.' for passwords and ':' for drive specifications. Upper
and lower case characters are equivalent.
_2. _T_R_S_D_O_S _C_o_m_m_a_n_d_s _o_f _I_n_t_e_r_e_s_t
_2._1. _C_A_T _P_A_R_T_S_P_E_C:_D (_O_T_H_E_R _O_P_T_I_O_N_S)
This command is specific to _T_R_S_D_O_S version 6.2 and
later. It displays only the names of visible files on
the drive specified, or all drives if no _p_a_r_t_s_p_e_c is
given. (_o_t_h_e_r _o_p_t_i_o_n_s) allows different formats and
invisible as well as system files to be selected. See
the _T_R_S_D_O_S manual for specifics
_2._2. _D_I_R _P_A_R_T_S_P_E_C:_D (_O_T_H_E_R _O_P_T_I_O_N_S)
DIR is common to all version of TRSDOS. Versions after
6.1 replaced the DIR command with CAT, and changed the
DIR command so that always produces a long listing.
_2._3. _F_R_E_E :_D
Gives statistics on disk usage. If D is present, it
indicates a drive number, and only the statistics for
the specified disk will be shown.
_2._4. _R_E_M_O_V_E/_P_U_R_G_E _F_I_L_E_S_P_E_C (_P_A_R_A_M_E_T_E_R_S)
Remove the file(s) given by FILESPEC from the directory
and frees the space allocated to the file for reassign-
ment. Purge allows PARTSPECs that specify groups of
files. With no PARAMETERS, PURGE prompts before delet-
ing any file. REMOVE requires a full filespec as the
name of the file to remove. REMOVE allows more than
one filespec to be given on the command line.
_2._5. _L_I_S_T _F_I_L_E_S_P_E_C (_P_A_R_A_M_E_T_E_R_S)
Lists the file on the display. Parameters are
described in the _T_R_S_D_O_S manual in detail. (_H_E_X) is
sometimes useful to display the hexidecimal values of
the characters in a file.
_2._6. _R_E_N_A_M_E _o_l_d_f_i_l_e _n_e_w_f_i_l_e
Changes the name of oldfile to newfile, provided that
newfile is a unique file name on that disk.
_3. _C_o_p_y_i_n_g _D_i_s_k_s _a_n_d _F_i_l_e_s:
- 3 -
_3._1. _C_O_P_Y _f_i_l_e_1 _f_i_l_e_2
Copies file1 and name the copy file2. If file2
exists, it will be replaced.
_3._2. _B_A_C_K_U_P :_D :_E
Makes a copy of the disk in drive D on the the
disk in drive E.
_3._3. _F_O_R_M_A_T :_D
Formats the disk in drive D. The disk will be
ready for any normal read or write operation fol-
lowing successful completion of this operation.
This operation must be performed before use of a
blank disk. Reformatting a previously formatted
disk will cause all previously stored information
to be lost.
_4. _T_r_a_n_s_f_e_r_s _w_i_t_h_o_u_t _t_h_e _K_E_R_M_I_T _P_r_o_t_o_c_o_l
Model 4(p) KERMIT adds 2 logical devices to the already
resident devices. These devices are used to access the com-
munications port. These devices, *FI (File Input) and *FO
(File Output), can be used as the source, and destination of
a copy command, respectively. They make use of the status
of the SET FLOW-CONTROL parameter, to send and receive data
using the communications port. For instance, say you are
communicating with a computer that does not have KERMIT.
Say you also wish to transfer a file to this computer to do
some further processing. The normal method involves start-
ing a program on the remote computer to collect the data
into a file on that system. On a VAX/VMS system, you might
use the CREATE command to capture the file. The following
_K_E_R_M_I_T commands will accomplish the transmition of a file in
this case.
OUTPUT CREATE MYPROG.DAT<CR>
LOCAL COPY PROG/DAT *FO
The KERMIT command, OUTPUT, will send the string "CREATE
MYPROG.DAT<CR>" to the host. Let's say for now that this is
sufficient to cause all future characters sent to the host
to be placed into the file MYPROG.DAT on that system. The
KERMIT command LOCAL is then used to invoke the _T_R_S_D_O_S
library command COPY. COPY will copy the contents of the
file "PROG/DAT" to the *FO device. The driver for this dev-
ice is part of the KERMIT program, and will take care of
transmitting the data out of the communications port to the
HOST. If the HOST sends XOFF because DATA is arriving TOO
fast, then the XON/XOFF option to the _K_E_R_M_I_T command, SET
FLOW-CONTROL, will allow the transfer to pause while the
HOST catches up. You may wish to collect the contents of a
- 4 -
file that is on another computer. If particular computer
does not have _K_E_R_M_I_T, you can use a series of commands simi-
lar to those listed below to retrieve the file. It should
be noted that the _S_E_S_S_I_O_N-_L_O_G can also be used to trap the
contents of a file. For that very reason, this is only one
of several possible ways to get a file from another computer
that does not have _K_E_R_M_I_T.
OUTPUT TYPE MYPROG.DAT<CR>
INPUT TYPE MYPROG.DAT<CR><LF>
LOCAL COPY *FI MYPROG/DAT:1
It may help to clarify the use of the _O_U_T_P_U_T command,
and the corresponding _I_N_P_U_T command. If you use the _K_E_R_M_I_T
command _C_O_N_N_E_C_T to enter terminal mode, and then proceed to
tell the host to type out a file, it may start sending data
before you can escape back, and type the _C_O_P_Y command. This
means that some of the data would be lost. With _F_L_O_W-
_C_O_N_T_R_O_L set to _X_O_N/_X_O_F_F, and the remote host recognizing
this fact, the previous commands would not allow any data to
be lost. The use of _I_N_P_U_T is only to remove the characters
ECHOed by the host from the input buffer (The TEXT of the
command "TYPE MYPROG.DAT"). If you are communicating with a
half-duplex system in which _M_o_d_e_l (_4)_p _K_E_R_M_I_T is echoing the
characters typed on the keyboard, then the _I_N_P_U_T command
need not be used.
_5. _C_o_n_t_r_o_l _o_f _F_i_l_e _T_r_a_n_s_f_e_r_s _U_s_i_n_g _t_h_e _K_E_R_M_I_T _P_r_o_t_o_c_o_l
During the transfer of a file using either _S_E_N_D, or _G_E_T
and possibly during the use of the _R_E_M_O_T_E command, protocol
operations may need to be aborted, or altered. Several key
strokes allow the user to control the protocol operations.
These are listed below, and are listed on the screen after
issuing either the _S_E_N_D or _G_E_T commands. The operation of
the _R_E_M_O_T_E command is purposefully silent. The key strokes
are available to the user during _R_E_M_O_T_E commands, for added
flexibility. This allows the user to cancel commands like
_R_E_M_O_T_E _T_Y_P_E that may otherwise cause large amounts of data
to be displayed for an extended amount of time. The valid
key strokes are:
_C_o_n_t_r_o_l-_F During data transfers using the _K_E_R_M_I_T proto-
col, _C_o_n_t_r_o_l-_F will terminate the current
transaction. If there are more files to
transfer, the next transaction will be
started. _M_o_d_e_l _4(_p) _K_E_R_M_I_T will send a sig-
nal to the remote _K_E_R_M_I_T telling it to stop
sending packets for the current transaction.
- 5 -
If the remote _K_E_R_M_I_T understands this signal
(not all implementations of _K_E_R_M_I_T do), it
will comply, otherwise the transaction will
continue.
_C_o_n_t_r_o_l-_B Like _C_o_n_t_r_o_l-_F, except that if a group of
files is being processed this will stop the
entire group. If only a single file is being
_S_E_N_T or _R_E_C_E_I_V_E_D, _C_o_n_t_r_o_l-_B behaves exactly
like _C_o_n_t_r_o_l-_F.
_C_o_n_t_r_o_l-_C Aborts the protocol immediately. This should
be a last resort to stopping a transmission
as it will leave the remote _K_E_R_M_I_T in an unk-
nown state.
_C_o_n_t_r_o_l-_E Aborts the protocol after sending an ERROR
packet to the remote _K_E_R_M_I_T.
_C_o_n_t_r_o_l-_D Toggles _D_E_B_U_G mode _O_N and _O_F_F. This is help-
ful when trying to figure out why a particu-
lar host is unable to talk to _M_o_d_e_l _4(_p) _K_E_R_-
_M_I_T.
<_E_N_T_E_R> If you type <_E_N_T_E_R>, _M_o_d_e_l _4(_p) _K_E_R_M_I_T will
resend the current packet.
_C_o_n_t_r_o_l-_H Displays the list of _K_E_Y_S that you may press
during a transfer. I.E. the keys described
above. This is the same message that is
printed when a SEND, GET, or RECEIVE command
is issued.
_6. _M_o_d_e_l _4(_p) _K_E_R_M_I_T _C_o_m_m_a_n_d_s
_M_o_d_e_l _4(_p) _K_E_R_M_I_T uses a subset of the the _D_E_C_S_Y_S_T_E_M-_2_0
keyword style command language. Each keyword may be abbre-
viated to its minimum unique length. "?" may be typed to
request a list of the available options for the current
field at any point in a command. If insufficient characters
have been typed to identify the current field uniquely,
_M_o_d_e_l _4(_p) _K_E_R_M_I_T will display all available choices, and
then reprompt to allow you to continue from that point. If
there are sufficient characters, then only a single choice
will be displayed. The following list of commands are
available when using _M_o_d_e_l _4(_p) _K_E_R_M_I_T.
- 6 -
_6._1. _B_Y_E
When talking to a remote _K_E_R_M_I_T Server, this command
should shut down a remote server and terminate the
login that you had there. _M_o_d_e_l _4(_p) _K_E_R_M_I_T will then
exit to _T_R_S_D_O_S _R_e_a_d_y.
NOTE: Due to some deviations from the specifica-
tion, some systems do not perform exactly in this
manner. You should check the documentation of the
_K_E_R_M_I_T on the remote system in order to obtain the
operation performed by this command.
_6._2. _C_L_E_A_R
_6._2._1. _I_N_P_U_T-_P_O_R_T
_M_o_d_e_l _4(_p) _K_E_R_M_I_T uses the "Interrupt on received
character available" feature of the COM/DVR com-
munications line driver. This driver is part of
the standard software on your system diskette.
All characters received via the interrupt vector,
are placed in a 256 byte circular buffer. This
command clears all characters currently buffered.
This is used most commonly with the INPUT, OUTPUT,
PULSE, and PAUSE commands, none of which expli-
citly clear the input buffer. YOU MUST DO THIS
YOURSELF. The execution of this command will _n_o_t
send an _X_O_N character to the communications port.
This is also left up to you to do.
_6._2._2. _S_C_R_E_E_N
As you would expect, this command clears the
screen.
_6._3. _C_L_O_S_E
_6._3._1. _D_E_B_U_G-_L_O_G
Closes the file previously opened with the LOG
DEBUG-LOG command. If there is not a debug log-
file active, then a message is printed telling you
so.
_6._3._2. _S_E_S_S_I_O_N-_L_O_G
Closes the file previously opened with the LOG
SESSION-LOG command. If no file is open, you will
be advised so.
- 7 -
_6._3._3. _T_R_A_N_S_A_C_T_I_O_N-_L_O_G
Closes the file previously opened with the LOG
TRANSACTION-LOG command. As with the other log-
files, if a file is not currently open, then a
message to that affect is printed.
_6._4. _C_O_N_N_E_C_T (_c_a_n _b_e _a_b_b_r_e_v_i_a_t_e_d _t_o '_C')
Establish a "virtual terminal" connection to any
host that may be connected to the serial port,
i.e. pass all typed characters to the serial port
and display all input from the serial port on the
screen. A two character sequence of characters is
required to return the user to the _K_E_R_M_I_T program.
An escape character must be typed followed by a
'c' (Case is _n_o_t significant). The default
<ESCAPE> character is entered by pressing the
<SHIFT> key, and then and <CLEAR> key, while hold-
ing the <SHIFT> key down. Pressing '?' after the
<ESCAPE> character will display a list of valid
keystrokes that do helpful things during connect
mode. The first time that you issue the _C_O_N_N_E_C_T
command, a message will be displayed telling you
what the <ESCAPE> character is. The <ESCAPE>
character should generally be an uncommonly-used
control character. The following characters are
valid following the <_E_S_C_A_P_E> character, and gen-
erate specific actions. The actions are described
beside the character.
_C Return to _M_o_d_e_l _4(_p) _K_E_R_M_I_T command
level. The contents of the screen and
the cursor location will be saved prior
to displaying the _K_E_R_M_I_T screen. When
you reconnect to the _H_O_S_T using the _K_E_R_-
_M_I_T command, _C_O_N_N_E_C_T, the old screen
will be restored.
_? List available single-character com-
mands, I.E. These commands.
_B Send a TRUE modem break.
_R Resume logging if file open, and
<ESCAPE>Q was used previously to turn
logging off. See the _L_O_G command for
more information.
_Q Quit logging to file but leave it open.
_0 (_z_e_r_o)Send a null (0) character out the
communications port.
- 8 -
<_E_S_C_A_P_E>Send the <_E_S_C_A_P_E> character itself to
the remote host.
_6._5. _D_I_R _p_a_r_t_s_p_e_c
Produces a listing of the directory for
"partspec". If partspec is not given, than the
directory will be displayed for the _D_E_F_A_U_L_T-_D_I_S_K
drive as established by _S_E_T _D_E_F_A_U_L_T-_D_I_S_K.
_6._6. _E_X_I_T
Exit _M_o_d_e_l _4(_p) _K_E_R_M_I_T, and return to _T_R_S_D_O_S.
Before the _K_E_R_M_I_T program is terminated, all open
files will be closed. This includes the LOGFILES
used for SESSION, TRANSACTION, and DEBUG logging.
The *FO, and *FI devices will also be removed.
_6._7. _E_C_H_O
This command echoes text given as an argument to
the screen. It can used in take files to put mes-
sages on the screen when TAKE-DISPLAY is OFF,
although other uses are possible.
_6._8. _F_I_N_I_S_H
Shuts down a remote server without logging it out.
Leaves you at _M_o_d_e_l _4(_p) _K_E_R_M_I_T command level. A
subsequent _C_O_N_N_E_C_T command will reconnect you to
the remote host. The _r_e_m_o_t_e _K_E_R_M_I_T should return
to the mode it was in prior to entering _S_E_R_V_E_R
mode.
_6._9. _G_E_T _f_i_l_e_s_p_e_c
Get allows you to retrieve files from a remote
host. Get works with either a _S_E_R_V_E_R or a _K_E_R_M_I_T
that has initiated a _S_E_N_D command. Filespec is a
filename compatible with _t_h_a_t system. When _M_o_d_e_l
_4(_p) _K_E_R_M_I_T is talking to a _K_E_R_M_I_T Server, you may
include a filespec in a form legal to the _H_O_S_T
_K_E_R_M_I_T.
_6._1_0. _I_N_P_U_T <_c_o_n_t_r_o_l _s_t_r_i_n_g>
INPUT provides one of 4 commands that provide an
automatic logon facility. INPUT allows you to
watch for the occurrence of certain text strings
that are made up characters arriving in the com-
munications port. This is useful in _T_A_K_E files
that can automatically log you onto a certain sys-
tem.
- 9 -
When _I_N_P_U_T in initiated, it begins matching
characters in the input to those given in the con-
trol string. When an exact match is found as
established by the _S_E_T _I_N_P_U_T options then _I_N_P_U_T
will return to the _K_E_R_M_I_T command level. If _T_A_K_E
is active than the next line of the _T_A_K_E file will
be read. The Control string may be comprised of
any printable _A_S_C_I_I characters. _S_P_A_C_E must not
occur as either the beginning or end of the
string.
_A_S_C_I_I character codes 0-32 are denoted as
<_N_U_L> - <_S_P_A>, and <_D_E_L> represents character 127.
The string <_D_L_Y*> signifies an immediate delay.
The * should be replaced by a character. The sig-
nificance of the character is this. Decimal 48 is
subtracted from the _A_S_C_I_I value of the character
to obtain the number of seconds to delay. Thus,
you can obtain delays 1-9 seconds, with no trick-
ery. Delays longer than that will have to be cal-
culated since the formula (ASCII code - 48
decimal) is used to calculate the binary value to
use as a counter. The "*" should be replaced with
the single proper ASCII character.
If you use <_D_L_Y*> in a _P_U_L_S_E command, it
should be noted that it will only be done once.
An alternative format for control characters is to
explicitly type a carat ("^") preceding a charac-
ter. The result of subtracting 64 from the _A_S_C_I_I
code for the character following will then be
used. Since <, >, and ^ now have special mean-
ings, you will need some way to specify them
explicitly. To do this you should precede them
with a backslash, "\", character. In this case,
backslash itself now must be represented as "\\".
Finally, any and all characters can be represented
using a string of the form \nnn where nnn is 1 or
more octal digits. nnn is evaluated, and the
resulting value will be the ASCII value of the
character. Some examples might be:
INPUT login:<SPA>
Find the string "login:" followed by a
space.
INPUT <SPA>^M^Jenter \\userid\\:<CR><LF>
Find the string with a space followed by
a carriage return followed by a line
feed followed by the text "enter
\userid\:" followed by carriage return
and another linefeed.
- 10 -
INPUT USERNAME\77\40
Find the string "USERNAME? ". Note that
\77 is the _O_N_L_Y way that a question mark
can be specified since a question mark
is recognized by the command stream as a
request for help.
While input is waiting for a match, you may type
characters on the keyboard to be transmitted.
_B_R_E_A_K will abort the _I_N_P_U_T command and if _T_A_K_E is
active, close the take file. _E_S_C_A_P_E will abort
the INPUT command, but will just skip to the next
line in a _T_A_K_E file, if _T_A_K_E is active. These
same 2 actions apply to the _P_U_L_S_E command while no
input has been received.
_6._1_1. _K_I_L_L _w_i_l_d_s_p_e_c
This command performs the task of deleting one or
more files from disk. _W_i_l_d_s_p_e_c is a wild card
filespec that will be evaluated. All files that
match the wildspec will be removed. A _w_i_l_d_s_p_e_c
may contain any characters valid is a TRSDOS
filespec, plus zero or more occurances of the
characters '*', and '$'. These two characters
have special meanings.
When comparing the _w_i_l_d_s_p_e_c with the name of
a file, a '*' matches zero or more of the charac-
ters in the filename. E.g. If a file FOO/ASM is
compared with '*/ASM', then it would match,
because '*' can be thought of as 'FOO', and then
'/ASM' is matched literally. M4*/ASM matches
M4MIT/ASM, M4XFER/ASM, M4SEND/ASM, and any other
filename that begins with M4, and ends with /ASM.
The '$' character matches any single character.
This means that FILE$/DOC matches the filename
FILE1/DOC, but not FILE1A/DOC.
A drivespec may be appended to the _w_i_l_d_s_p_e_c
to force the search for matches to be restricted
to a single drive. An example might be M4*/ASM:1,
which limits the matches to those file on drive 1.
Normally, only visible, nonsystem files are
considered in the search. However, the inclusion
of a parameter list containing either, or both of
the keywords, INVIS or SYSTEM, will include
invisible and/or system files. An example would
be:
KILL (I,S) config/sys (I) backup/cmd
This example would cause _M_o_d_e_l _4(_p) _K_E_R_M_I_T to
attempt to remove the two files listed. Note that
- 11 -
as this example shows, you must specify the param-
eters with each _w_i_l_d_s_p_e_c that you wish to apply
them to, as they are nullified each time that a
new _w_i_l_d_s_p_e_c is evaluated. Other examples are
given in the description of the _S_E_N_D command.
_6._1_2. _L_O_C_A_L <_T_R_S_D_O_S _l_i_b_r_a_r_y _c_o_m_m_a_n_d> (_C_a_n _b_e
_a_b_b_r_e_i_v_i_a_t_e_d _t_o _L)
This command allows you to issue commands from
within _M_o_d_e_l _4(_p) _K_E_R_M_I_T. You must remember where
Model 4(p) KERMIT resides in memory, to assure
that you do not overwrite it. KERMIT loads at
6000H, and continues up through LOW$. From within
KERMIT, you can issue the command:
LOCAL MEMORY
to see where KERMIT ends. The value of LOW$ tells
you this information. KERMIT was placed at 6000H
to allow most of the TRSDOS library programs and
commands to work in conjunction with KERMIT. Some
commands extend above 3000H, and must have memory
available up to approximately 5300H. The COPY
command creates a problem because it apparently
tries to examine HIGH$ to see if there is space to
load a large portion of the source file into
memory before writing it to the destination. This
creates problems because KERMIT moves LOW$ up so
that HIGH$ has a value that will allow additional
high memory module to be loaded. It is suggested
that you not use COPY while KERMIT is running, as
the machine may crash when COPY completes. This
is because it will have copied data into the KER-
MIT memory space.
_6._1_3. _L_O_G
_6._1_3._1. _D_E_B_U_G-_L_O_G
The debug log can be used to debug transfer
problems that sometimes arrise when talking
to a newly written KERMIT. The information
written to the DEBUG-LOG is nearly identical
to that which is displayed on the screen when
the command, SET DEBUG ON, is issued, or the
CTRL-D key is pressed during a transfer.
This file can be closed explicitly with the
_C_L_O_S_E _D_E_B_U_G-_L_O_G command. The EXIT command
also causes an implicit closing of this file.
- 12 -
_6._1_3._2. _S_E_S_S_I_O_N-_L_O_G
When CONNECTed to a foreign host as a termi-
nal, this command establishes a log of the
terminal session in the file specified. This
function depends, to some extent, on the
remote host's ability to do _X_O_N/_X_O_F_F flow
control. Without _F_L_O_W-_C_O_N_T_R_O_L, data may be
lost when _K_E_R_M_I_T writes to the file. The log
file is closed by explicitly typing the _K_E_R_-
_M_I_T command _C_L_O_S_E _S_E_S_S_I_O_N-_L_O_G or implicitly
when _K_E_R_M_I_T is exited via the _E_X_I_T command.
It will also be closed if an I/O error occurs
in file processing for the file involved.
_L_O_G_G_I_N_G may be toggled on and off during _C_O_N_-
_N_E_C_T using the sequence of keys described in
the _C_O_N_N_E_C_T description.
_6._1_3._3. _T_R_A_N_S_A_C_T_I_O_N-_L_O_G
The transaction log is used to keep a record
of the files transfered during a KERMIT ses-
sion. The information includes whether or
not the transaction was SENDING, or RECEIV-
ING, the name of the file transfered, and the
number of bytes involved in the transfer.
_6._1_4. _L_O_G_O_U_T
Logout tells a _r_e_m_o_t_e _k_e_r_m_i_t _s_e_r_v_e_r to terminate
itself, as well as your login session. When this
is completed, you are left at _M_o_d_e_l _4(_p) _K_E_R_M_I_T
command level.
_6._1_5. _O_U_T_P_U_T <_c_o_n_t_r_o_l _s_t_r_i_n_g>
This is the other side of the _I_N_P_U_T command. Con-
trol string follows the same conventions as in
_I_N_P_U_T, and the resulting character(s) will be out-
put to the communications port immediately. It
should be noted that _N_O characters other than what
you specify are transmitted. In other words if
you want to simulate typing some string, followed
by pressing <_E_N_T_E_R>, then you will have to use a
command similar to:
OUTPUT mypassword<CR>
The <_C_R> will explicitly send the _A_S_C_I_I character
13 to the communications port.
- 13 -
_6._1_6. _P_A_U_S_E <_n_u_m_b_e_r _o_f _s_e_c_o_n_d_s>
This command is usually used in conjunction with
_I_N_P_U_T, _O_U_T_P_U_T, and _P_U_L_S_E as a means of syncroniz-
ing _M_o_d_e_l _4(_p) _K_E_R_M_I_T to a remote host. A delay
of the specified number of seconds will be gen-
erated based on the accuracy of the 60HZ inter-
rupt. No means has been made for aborting the
delay. The maximum delay is 65536 seconds by
specifying 0 as the number.
_6._1_7. _P_U_L_S_E <_c_o_n_t_r_o_l _s_t_r_i_n_g>
This command is an extension/combination of _I_N_P_U_T
and _O_U_T_P_U_T. It allows you to transmit one or more
characters repeatedly until a character appears in
the input port. The use of this command is valu-
able when logging onto systems that don't always
respond immediately after the reception of some
control character(s). For instance, you might
(Now that all of the functions of this nature have
been described) use the following commands as part
of a logon sequence to log onto a computer system.
SET INPUT CASE-IGNORE ON
SET INPUT DISPLAY ON
SET OUTPUT HOST-ECHO ON
SET OUTPUT DISPLAY ON
CLEAR INPUT-PORT
PULSE ^T<CR>
INPUT <CR><LF>XYZ:
PAUSE 2
CLEAR INPUT-PORT
PULSE <CR>
INPUT Username:<SPA>
OUTPUT joeblow<CR>
INPUT <CR><LF>Terminal type:
OUTPUT h19<CR>
SET KEY 8 <DEL>
SET KEY 128 <ETX>
After you study this awhile, it should make sense.
If these commands are placed into a _T_A_K_E file,
then you could use a _C_O_N_N_E_C_T command after the
last command, to connect immediately to the host.
If this is done, then _o_n_l_y after you escape back
to _M_o_d_e_l _4(_p) _K_E_R_M_I_T, will the _T_A_K_E file finally
be closed.
_6._1_8. _R_E_C_E_I_V_E <_f_i_l_e_s_p_e_c>
This command is synonomous with the GET command.
It may be abbreviated to the single character 'R',
as in:
- 14 -
R *.asm
_6._1_9. _R_E_M_O_T_E <_c_o_m_m_a_n_d>
_R_e_m_o_t_e commands are not supported in totality by
all _s_e_r_v_e_r_s. If a _s_e_r_v_e_r supports remote com-
mands, then _r_e_m_o_t_e _h_e_l_p should display all of the
commands available to the _r_e_m_o_t_e user of the
server. Below are descriptions of the _r_e_m_o_t_e com-
mands that _M_o_d_e_l _4(_p) _K_E_R_M_I_T knows how to send to
a _r_e_m_o_t_e _s_e_r_v_e_r. The arguments to most commands
are dependent on the _r_e_m_o_t_e system. You should be
familiar with any system before using the _r_e_m_o_t_e
_s_e_r_v_e_r commands available from that server. Usu-
ally only a small number of these commands are
supported since some require abilities that some
operating systems just don't have.
_6._1_9._1. _C_L_O_S_E-_L_O_G
Close a remote _L_O_G previously opened via the
command _R_E_M_O_T_E _S_T_A_R_T-_L_O_G.
_6._1_9._2. _C_O_P_Y
Copy one file to another.
_6._1_9._3. _C_W_D <_d_i_r_e_c_t_o_r_y _p_a_t_h>
If a particular server's operating system
supports the concept of separate directories,
then this command will allow you to change to
a different directory.
_6._1_9._4. _D_E_L_E_T_E
Deletes file(s) from the _r_e_m_o_t_e system. Any
arguments will probably be file names in the
format of the _r_e_m_o_t_e system.
_6._1_9._5. _D_I_R
Display a list of files on the _r_e_m_o_t_e system.
_6._1_9._6. _D_I_S_K
Display information about disk utilization on
the _r_e_m_o_t_e system.
- 15 -
_6._1_9._7. _H_E_L_P
Get information about _r_e_m_o_t_e capabilities on
the _r_e_m_o_t_e system.
_6._1_9._8. _H_O_S_T
Execute a command on the _r_e_m_o_t_e system.
_6._1_9._9. _K_E_R_M_I_T
Execute a _K_E_R_M_I_T command on the _r_e_m_o_t_e sys-
tem. This command should accept a normal
_K_E_R_M_I_T command as an argument. The command,
if valid, will then be executed by the remote
_K_E_R_M_I_T server.
_6._1_9._1_0. _L_O_G_I_N
Create a login entity on the _r_e_m_o_t_e system.
This may be incorporated into a dedicated
server.
_6._1_9._1_1. _M_E_S_S_A_G_E
Send a message to a user on the _r_e_m_o_t_e sys-
tem.
_6._1_9._1_2. _P_R_O_G_R_A_M
Feed command input to a command executing on
the remote system, or control the execution
of a program.
_6._1_9._1_3. _Q_U_E_R_Y-_V_A_R_I_A_B_L_E
Get the value of a variable maintained on the
_r_e_m_o_t_e system.
_6._1_9._1_4. _R_E_N_A_M_E
Change the name of a file on the _r_e_m_o_t_e sys-
tem.
_6._1_9._1_5. _S_E_N_D-_L_O_G
Tells the server to close any open log, and
then transfer it to the user.
_6._1_9._1_6. _S_E_R_V_E_R-_S_T_A_T_U_S
Retrieve certain information about the status
of a REMOTE server. The information returned
is dependent on the REMOTE system.
- 16 -
_6._1_9._1_7. _S_E_T-_V_A_R_I_A_B_L_E
Set the value of a variable on the _r_e_m_o_t_e
system.
_6._1_9._1_8. _S_T_A_R_T-_L_O_G
Start a transaction log on the _r_e_m_o_t_e system.
_6._1_9._1_9. _S_T_O_P-_L_O_G
Stops logging to the log file started by the
_R_E_M_O_T_E _S_T_A_R_T-_L_O_G command. The file is not
closed. Logging may be started again by
using the the command, _R_E_M_O_T_E _S_T_A_R_T-_L_O_G.
_6._1_9._2_0. _T_Y_P_E
Display the contents of the file/files given
as arguments. The _r_e_m_o_t_e server should use
the _K_E_R_M_I_T protocol to send the contents of
the specified file/files to _M_o_d_e_l _4(_p) _K_E_R_-
_M_I_T. The file contents will be displayed on
the screen using the *SO device.
_6._1_9._2_1. _W_H_O
Display a list of users on the _r_e_m_o_t_e system.
_6._2_0. _S_E_N_D <_w_i_l_d_s_p_e_c> (_M_a_y _b_e _a_b_b_r_e_v_i_a_t_e_d _t_o
'_S');
File specifications may contain wild card charac-
ters. The recognized wild card characters are '*'
and '$'. '*' means zero or more of any character.
'$' means exactly one of any character. There are
a lot of specifics associated with wild carding,
and search order through the drives.
When files by the same name exist on dif-
ferent drives, a wild card match of one will also
match all other occurances. e.g. if drive 0 con-
tains the file report/dat, and report.dat also
exist on drive 1, then the command other varia-
tions can be used to send only one of the 2 files.
'SEND */dat:1' will only match files on drive 1.
Another alternative would be
Case is NOT significant, so both REPORT/DAT
and report/dat are identical. so "*/*" is the
same as "*" for all file names with an extension.
"*/*", however, does not match names of the form
"data", "fred", "file", "temp", or others without
extensions. Other examples are given in the
- 17 -
description of the _K_I_L_L command.
_6._2_1. _S_E_T <_p_a_r_a_m_e_t_e_r [_v_a_l_u_e(_s)...]>
Set the specified parameter to the specified
value. Possible settings:
_6._2_1._1. _B_E_L_L _O_N (_o_r _O_F_F)
When _D_U_M_B terminal emulation is in effect, a
simple noise generator is used to produce a
tone like a bell each time the _B_E_L_L character
is received. If you don't like it, than use
_S_E_T _B_E_L_L _O_F_F to disable it.
_6._2_1._2. _B_L_O_C_K-_C_H_E_C_K-_T_Y_P_E
The options are:
_6._2_1._2._1. _1 (_c_h_a_r_a_c_t_e_r _c_h_e_c_k_s_u_m)
Normal, default, standard 6-bit check-
sum.
_6._2_1._2._2. _2 (_c_h_a_r_a_c_t_e_r _c_h_e_c_k_s_u_m)
A 12-bit checksum encoded as two charac-
ters.
_6._2_1._2._3. _3 (_c_h_a_r_a_c_t_e_r _c_r_c-_c_c_i_t_t)
A 16-bit CCITT-format Cyclic Redundancy
Check, encoded as 3 characters.
The 2 and 3 character options should only be
used under conditions of extreme line noise.
Many implementations of _K_E_R_M_I_T only support
the single character checksum.
_6._2_1._3. _D_E_B_U_G_G_I_N_G _O_F_F (_o_r _O_N)
When transmitting or receiving packets, con-
trols whether the packets are displayed on
the local screen.
_6._2_1._4. _D_E_F_A_U_L_T-_D_I_S_K <_d_r_i_v_e _n_u_m_b_e_r>
The default-drive value is used for received
files. The file names created by _M_o_d_e_l _4(_p)
_K_E_R_M_I_T will have a ':' and the default drive
number affixed to the end so that they will
be forced to be saved on the selected drive.
- 18 -
_6._2_1._5. _E_I_G_H_T-_B_I_T-_Q_U_O_T_I_N_G _O_N (_o_r _O_F_F)
This command enables or disables 8th bit
quoting. This is useful when a full 8 bit
path is available for binary file transfers.
_6._2_1._6. _E_M_U_L_A_T_I_O_N _N_O_N_E (_o_r _D_U_M_B)
When connected as a terminal to a foreign
host, _S_E_T _E_M_U_L_A_T_I_O_N controls whether the
Model 4 emulates no terminal, allowing the
use of a terminal filter, or whether a _D_U_M_B
terminal emulation is used. No emulation is
the default.
_6._2_1._7. _E_S_C_A_P_E
Change the escape character for virtual ter-
minal connections. _M_o_d_e_l _4(_p) _K_E_R_M_I_T will
prompt you for the new escape character,
which you type in locally.
_6._2_1._8. _F_I_L_E
_6._2_1._8._1. _D_I_S_P_O_S_I_T_I_O_N _K_E_E_P (_o_r _D_I_S_C_A_R_D)
When the transfer of a file is inter-
rupted, this tells Model 4(p) KERMIT
what to do if it receives only a partial
file. If FILE-DISPOSITION is DISCARD,
then any partial file is removed. Oth-
erwise, the file is left as it is when a
transfer is interrupted.
_6._2_1._8._2. _T_Y_P_E (_A_S_C_I_I _o_r _B_I_N_A_R_Y)
Tells _M_o_d_e_l _4(_p) _K_E_R_M_I_T how to deal with
the file being sent/received. It is
_I_M_P_O_R_T_A_N_T to tell KERMIT if the file is
in _A_S_C_I_I when sending to a _N_O_N _M_o_d_e_l
_4(_p) _K_E_R_M_I_T. The action taken with this
value is as follows. If _A_S_C_I_I mode is
set, then CR-LF pairs of characters are
translated to CR on input, and CR is
translated to CR-LF on output. When
binary mode is in effect, this transla-
tion does not occur.
_6._2_1._9. _F_L_O_W-_C_O_N_T_R_O_L _X_O_N/_X_O_F_F (_o_r _N_O_N_E)
When this feature is set to _X_O_N/_X_O_F_F (the
default), _M_o_d_e_l _4(_p) _K_E_R_M_I_T will try its best
to obey and use _X_O_N characters and _X_O_F_F char-
acters for all transmitions through the
- 19 -
communications port. _N_O_N_E will disable all
attempts at this sort of flow- control.
_6._2_1._1_0. _I_N_P_U_T
_6._2_1._1_0._1. _C_A_S_E-_I_G_N_O_R_E _O_F_F (_o_r _O_N)
Controls whether of not case matching is
done on characters during the input com-
mand. In most instances, you will want
this _O_N.
_6._2_1._1_0._2. _D_I_S_P_L_A_Y _O_F_F (_o_r _O_N)
Controls the display of characters that
are input during the execution of the
_I_N_P_U_T command.
_6._2_1._1_1. _K_E_Y <_k_e_y _v_a_l_u_e> <_s_t_r_i_n_g>
This command allows you to send an arbitrary
(the length of the _K_E_R_M_I_T command line is the
limit) string with a single key stroke. The
definition of string is identical for that of
the _I_N_P_U_T, _O_U_T_P_U_T, and _P_A_U_S_E commands. KEY
VALUE is the ASCII value of the key stroke as
given in the TRSDOS manual. If KEY VALUE is
not given, then you will be asked to press
the key corresponding to the key that you
wish to define. All keys are valid in _s_t_r_i_n_g
except BREAK. Pressing BREAK signals the end
of the definition string. While in _C_O_N_N_E_C_T
mode, typing the defined key will cause the
characters typed as the definition to be
typed instead. Defining a key to have a _N_U_L_L
length deletes any previous definition.
_6._2_1._1_2. _L_O_C_A_L-_E_C_H_O _O_F_F (_o_r _O_N)
When you _C_O_N_N_E_C_T to a remote host, you must
set _L_O_C_A_L-_E_C_H_O _O_N if the host is half duplex,
_O_F_F if full duplex.
_6._2_1._1_3. _O_U_T_P_U_T
_6._2_1._1_3._1. _H_O_S_T-_E_C_H_O _O_N (_o_r _O_F_F)
When using _O_U_T_P_U_T, and communicating
with a remote host, the host commonly
echoes the characters as you type.
Since _O_U_T_P_U_T effectively types charac-
ters for you, these characters may be
echoed back. If _H_O_S_T-_E_C_H_O is _O_N, _O_U_T_P_U_T
will wait for the echoed character to
- 20 -
reappear in the input buffer before it
sends the next. In the example for send-
ing and receiving raw data, that is
above, setting _H_O_S_T-_E_C_H_O _O_N, will enable
us to remove the _I_N_P_U_T _T_Y_P_E
_M_Y_P_R_O_G._D_A_T<_C_R><_L_F> command. Control
characters are _N_O_T normally echoed, so
this feature when set _O_N, will not wait
for them. If you must catch the echo of
a control character, then follow the
_O_U_T_P_U_T command with the appropriate
_I_N_P_U_T command.
_6._2_1._1_3._2. _D_I_S_P_L_A_Y _O_F_F (_o_r _O_N)
This parameter when on controls the
display of characters that are received
when _H_O_S_T-_E_C_H_O is _O_N. Otherwise, They
are displayed based on the status of the
_L_O_C_A_L-_E_C_H_O setting.
_6._2_1._1_4. _P_R_I_N_T_E_R _O_F_F (_o_r _O_N)
Turns copying of _C_O_N_N_E_C_T session to printer
on and off. With _F_L_O_W-_C_O_N_T_R_O_L turned on,
and a sending host that will acknowledge the
_X_O_F_F, you should have no problems using the
printer continuously.
_6._2_1._1_5. _R_E_C_E_I_V_E
_6._2_1._1_5._1. _E_N_D-_O_F-_L_I_N_E <_A_S_C_I_I _c_o_d_e>
Set the end of line character in packets
to some other character than <_C_R> which
is the default.
_6._2_1._1_5._2. _P_A_D-_C_H_A_R <_A_S_C_I_I _c_o_d_e>
If the host you are communicating with
needs one or more padding characters
before it receives actual data during
packet transfers, this character will be
sent _P_A_D_D_I_N_G times.
_6._2_1._1_5._3. _P_A_D_D_I_N_G <_d_e_c_i_m_a_l _n_u_m_b_e_r>
The repeat count for the number of times
the padding character is transmitted.
_6._2_1._1_5._4. _Q_U_O_T_E-_C_H_A_R_A_C_T_E_R <_A_S_C_I_I _c_o_d_e>
The character used to quote control
characters. The default is pound "#"
- 21 -
_6._2_1._1_5._5. _S_T_A_R_T-_O_F-_P_A_C_K_E_T <_A_S_C_I_I _c_o_d_e>
The character used to syncronize the
packets that _K_E_R_M_I_T transmits. By
default <_S_O_H>.
_6._2_1._1_5._6. _T_I_M_E-_O_U_T <_d_e_c_i_m_a_l _n_u_m_b_e_r>
_M_o_d_e_l _4(_p) _K_E_R_M_I_T uses this value as the
number of seconds to wait for a response
to a packet. If no response is received
within the number of seconds given, then
the packet for which the response has
not been received is retransmitted.
_6._2_1._1_5._7. _T_U_R_N-_C_H_A_R
The character used to syncronize KERMIT
when used over a half duplex line.
_M_o_d_e_l _4(_p) _K_E_R_M_I_T will wait for this
character at the end of a packet, and
will send the SEND TURN-CHAR at the end
of a packet.
_6._2_1._1_6. _S_E_N_D
_6._2_1._1_6._1. _E_N_D-_O_F-_L_I_N_E <_A_S_C_I_I _c_o_d_e>
Set the end of line character in packets
to some other character than <_C_R> which
is the default.
_6._2_1._1_6._2. _P_A_D-_C_H_A_R <_A_S_C_I_I _c_o_d_e>
If the host you are communicating with
needs one or more padding characters
before it receives actual data during
packet transfers, this character will be
sent _P_A_D_D_I_N_G times.
_6._2_1._1_6._3. _P_A_D_D_I_N_G <_d_e_c_i_m_a_l _n_u_m_b_e_r>
The repeat count for the number of times
the padding character is transmitted.
_6._2_1._1_6._4. _Q_U_O_T_E-_C_H_A_R_A_C_T_E_R <_A_S_C_I_I _c_o_d_e>
The character used to quote control
characters. The default is pound "#"
_6._2_1._1_6._5. _S_T_A_R_T-_O_F-_P_A_C_K_E_T <_A_S_C_I_I _c_o_d_e>
The character used to syncronize the
packets that _K_E_R_M_I_T transmits. By
- 22 -
default <_S_O_H>.
_6._2_1._1_6._6. _T_I_M_E-_O_U_T <_d_e_c_i_m_a_l _n_u_m_b_e_r>
This value is given to the _o_t_h_e_r host as
its' timeout value. You should assure
that this is different from the RECEIVE
TIME-OUT value so that both timeouts do
not occur simultaneously.
_6._2_1._1_6._7. _T_U_R_N-_C_H_A_R <_A_S_C_I_I _c_o_d_e>
The character used to syncronize KERMIT
when used over a half duplex line.
_M_o_d_e_l _4(_p) _K_E_R_M_I_T will send this charac-
ter at the end of a packet. The RECEIVE
TURN-CHAR will be waited for before data
is transmitted.
_6._2_1._1_7. _T_A_K_E-_D_I_S_P_L_A_Y _O_F_F (_o_r _O_N)
Controls the display of _T_A_K_E files as they
are executed. By default this feature is
off.
_6._2_1._1_8. _W_A_R_N_I_N_G _O_N (_o_r _O_F_F)
Warns user if filename conflicts when receiv-
ing files from remote host, and attempt to
generate a unique name by modifying the given
one. _O_N by default.
_6._2_2. _S_E_T_C_O_M <_T_R_S_D_O_S _S_E_T_C_O_M _c_o_m_m_a_n_d _p_a_r_a_m_e_t_e_r>
Sets/shows the status of the communications
driver, _C_O_M/_D_V_R. If no arguments are given, than
the current status will be shown. Any arguments
must be enclosed in parenthesis as the result of
this command, is a generated _T_R_S_D_O_S command as in:
SETCOM (B=9600,P=N,W=8)
The default values are established according to
you. If you set up the driver for a certain con-
figuration, and then use _S_Y_S_G_E_N to save it, then
that will be the default. _N_O sysgen should give
you:
300 BAUD
EVEN PARITY
DTR=YES
7 DATA BITS
1 STOP BIT
- 23 -
_6._2_3. _S_H_O_W
Allows one or ALL of the options of the _S_E_T com-
mand to be displayed. Using the "?" feature will
aid you if you can't figure out where to find
something. All of the things that can be SET can
be displayed. The items not listed below can be
displayed by using a command like:
SHOW BLOCK
or
SHOW DEFAULT
SHOW ALL will display all of the set values except
keys. You must use SHOW KEY to see these values.
_6._2_3._1. _S_E_N_D
Displays all options described under the _S_E_T _S_E_N_D
command.
_6._2_3._2. _R_E_C_E_I_V_E
Displays all options described under the _S_E_T
_R_E_C_E_I_V_E command.
_6._2_3._3. _K_E_Y <_A_S_C_I_I _k_e_y _v_a_l_u_e>
If <ASCII key value> is specified, then the defin-
ition for the specified key number is display.
Otherwise, a prompt is issued for the user to type
the keystroke that should be taken as the key to
display. \nnn is used to display all values
greater than 127. ^x where x is a character 64
greater than 0 through 31, and 127 is used to
display control characters. Any other printable
ASCII character is displayed normally.
_6._2_4. _S_T_A_T_U_S
Shows certain information about the status of _M_o_d_e_l
_4(_p) _K_E_R_M_I_T. Items currently displayed include the
amount of space left in the _K_E_Y definition table, the
number of bytes written to files during transfers, the
number of bytes read from files during transfers, as
well as statistics on the latest transfer.
_6._2_5. _T_A_K_E <_f_i_l_e_s_p_e_c>
TAKE allows commands to be stored in a file, and then
executed by the _K_E_R_M_I_T command interpreter. Only _o_n_e
level of _T_A_K_E files is supported. This means that a
- 24 -
_T_A_K_E command can not appear inside of a _T_A_K_E file. No
checking is done to enforce this, so good luck if you
want to try it. When _K_E_R_M_I_T is first entered, a check
is made for a file called _K_E_R_M_I_T/_I_N_I on all of the
active disk drives as per normal _T_R_S_D_O_S searching
order. If it is found, than it is used as a _T_A_K_E file
where you can store initialization commands. Pressing
the _B_R_E_A_K key, or the _E_N_T_E_R key during the startup of
KERMIT (before the TAKE file is opened) will cause _K_E_R_-
_M_I_T to skip processing of the _T_A_K_E file.
_7. _S_e_t_t_i_n_g _u_p _t_o _u_s_e _M_o_d_e_l _4(_p) _K_E_R_M_I_T
To use _M_o_d_e_l _4(_p) _K_E_R_M_I_T, you need to have your Model 4
set up properly. The program expects that the *CL device
will be driven by the COM/DVR Communications Driver that
comes with TRSDOS. It also expects that the *SO device is
ROUTED to the *DO device, and that the *SI device is ROUTED
to the *KI device. The former 2 are the defaults, and in
general, you should not worry about them, unless you have
changed them. Setting up the *CL device involves typing the
command:
SET *CL COM/DVR
at the _T_R_S_D_O_S _R_e_a_d_y prompt. If you do not do this, you will
get a message of the form
Can't find *CL DCB
from _M_o_d_e_l _4(_p) _K_E_R_M_I_T when it is starting up. The program
will return control to TRSDOS after issuing this message, as
it is a fatal error.
Model 4(p) KERMIT is not a small program. It occupies
memory starting at 6000H, and extends up past 0D300H. If
you have parts of TRSDOS resident (Using the SYSTEM
(SYSRES=....) command), or perhaps other filters or memory
resident modules, then you should make sure that they do not
extend below the maximum address used by the program. The
last memory address used by _M_o_d_e_l _4(_p) _K_E_R_M_I_T can be
obtained by using the command
LOCAL MEMORY
from within the _M_o_d_e_l _4(_p) _K_E_R_M_I_T program.
- 25 -
_8. _I_n_s_t_a_l_l_a_t_i_o_n
To install _M_o_d_e_l _4(_p) _K_E_R_M_I_T, you must obtain the two
files _M_4_B_O_O._B_A_S and _M_4_M_I_T._H_E_X. Because of the size of the
executable, the hex file could not be placed into a basic
program as data statements. Instead, the basic program
opens and reads the file _M_4_M_I_T._H_E_X. This file is an _A_S_C_I_I
image of the executable. All that needs to be done, is to
run the _B_A_S_I_C program which will convert the file back to
its original binary format. The resulting executable should
probably be called _K_E_R_M_I_T/_C_M_D. Follow the prompts of the
BASIC program and there should not be any problems.
_9. _B_u_i_l_d_i_n_g _M_o_d_e_l _4(_p) _K_E_R_M_I_T from the Source.
The Source for _M_o_d_e_l _4(_p) _K_E_R_M_I_T is in approximately 15
modules. The names of the modules are:
M4ADD/ASM Code for miscellaneous routines.
M4CMD/ASM Command parser code.
M4EQU/ASM Mosts constants are defined here
M4FILE/ASM Additional logfile code such as the LOG
command, and the CLOSE command.
M4GET/ASM Receive file routines + other miscel-
lany.
M4KEY/ASM Code for handling the SET KEY functions
M4LOG/ASM INPUT, OUTPUT, PAUSE, PULSE commands.
M4MAC/ASM Macros used in the program
M4MIT/ASM Main entry and some command routines.
M4PKT/ASM New packet routines for encoding and
decoding packets.
M4RMT/ASM The base of what will be the remote com-
mand.
M4SEND/ASM Send file routines.
M4SET/ASM Set options routines.
M4SHOW/ASM Show settings routines.
M4STR/ASM The majority of storage, prompts, and
messages.
- 26 -
M4TERM/ASM Terminal Emulation, and I/O routines.
M4WILD/ASM Wild card file name processing.
M4XFER/ASM File processing, and some packet stuff.
_M_o_d_e_l _4(_p) _K_E_R_M_I_T was developed using the _E_D_A_S assem-
bler from Misosys. Other macro assemblers should be able to
assemble the program with minor conversions. _M_4_M_I_T/_A_S_M is
the main source module. It will call the other source files
into the assembly (using the *GET directive) as needed. If
any system calls need to be changed, they are all defined in
_M_4_A_D_D/_A_S_M for the most part. All of the SVC's are coded in
_M_4_A_D_D/_A_S_M as subroutines that are accessed by CALL Xaaaaa,
where aaaaa is the name of the _T_R_S_D_O_S supervisor call (SVC)
without the "@" sign.
If this version is moved to another OS, there are
several things that you should consider. The things that
come to mind are:
1. Consider the format of the TRSDOS directory struc-
ture. The wild card routines depend on this
structure for validating directory entries, and
for retrieving the file name.
2. There are 2 places where real time counting is
required. The delay specified in a PAUSE state-
ment can be handled with a counter, as all other
processing is halted (except the interrupt tasks)
during the pause. Currently, the Real Time Clock
task is used to measure the appropriate delay.
The other use of a Real Time counter occurs in the
Receive packet timeout. This must be handled
using asyncronous processes in order to be accu-
rate.
3. There exist code at the beginnning and end of the
segment that accesses the screen which outputs the
bytes 14, and 15 to the *DO device. These are
used to force the cursor to be invisible before
the screen is accessed, and to then make it reap-
pear after the screen access is completed.
4. The interrupt driven receiver must also be delt
with. The code in the routine SETINT, establishes
the interrupt vector that the *CL driver will call
when a "character received interrupt" is gen-
erated.
5. In many instances, the characters having values
16, and 17 are used to enable, and disable reverse
video respectively. If the driver for *DO does
- 27 -
not recognize this convention, as the current one
does, then these characters must be handled in
some manner. I.E. either removed from the source,
or filtered from the terminal output stream. The
PRTSTR() routine is a good place to mask these
characters at, as it is the sole source of output
for strings containing these type of characters.
It should be noted that _K_E_R_M_I_T/_C_M_D loads into RAM at
6000H. This avoids high memory filters and drivers, and
also allows use of _T_R_S_D_O_S library commands that use low
memory beyond 3000H, as FORMAT, and BACKUP do. Exclusive
use is made of the *DO device for screen output from the
KERMIT program, for informational messages and the like.
During connect mode, *SI and *SO are used as the input and
output devices to allow filters to be attached that will not
effect the operation of _M_o_d_e_l _4(_p) _K_E_R_M_I_T during command
operations. If you install a different driver or filter it
must be compatible in these areas.
_1_0. _P_e_r_f_o_r_m_a_n_c_e _S_p_e_c_i_f_i_c_s _o_f _M_o_d_e_l _4(_p) _K_E_R_M_I_T
The _M_o_d_e_l _4(_p) _K_E_R_M_I_T has been tested and proven to
work properly at 9600 BAUD with flow control on, transfer-
ring files between 2 Model 4's. What makes the _M_o_d_e_l _4(_p)
_K_E_R_M_I_T perform so well is the idea of flow control, and the
interrupt driven receiver. With out these features, I
expect that 2400 baud would be the reliable limit. Flow
control can be disabled at speeds less than or equal to
~2400 baud, but greater speeds require that flow control be
functional in order to protect the integrity of data in the
input buffer.
_1_1. _T_h_e _H_e_a_t_h _1_9 _F_i_l_t_e_r
The files _M_4_H_1_9_1._A_S_M, _M_4_H_1_9_2._A_S_M, _M_4_H_1_9._M_A_C, and
_M_4_H_1_9._E_Q_U make up the sources for a Heath 19 terminal emula-
tion filter for the TRS-80 Models 4 and 4p. The assembler
used was EDAS by Misosys. To build the filter from sources,
you need the above 4 files on a disk. _M_4_H_1_9_1._A_S_M is the
main source module, and it *GETs all the other necessary
files.
The structure of the program is pretty simple. Single
character (non escape) sequences, are passed to the filtered
device via the @_C_H_N_I_O svc. This filter depends on the
_T_R_S_D_O_S *_D_O driver being at the end of the chain. Several
control characters are merely translated, and then the new
values are passed to *DO.
- 28 -
A multi-character escape sequence is handled by
remembering the previous characters that the filter was
passed. The previous characters are remembered by the pres-
ence of a non-zero value in the contents of _S_T_A_T_E. The
value in _S_T_A_T_E represents the address of the code to handle
the next character, given the previous string of characters.
The filter is relocatable, but _M_U_S_T reside below screen
memory because it accesses it directly when performing
several of the advanced terminal functions. For this rea-
son, it will never load _a_b_o_v_e _F_3_f_f_H.
_1_2. _T_h_e _S_E_T_H_1_9 _P_r_o_g_r_a_m
The _S_E_T_H_1_9 program allows you to configure a few
options that are available to you when using the _H_1_9 _f_i_l_t_e_r.
The _S_E_T_H_1_9 program is created from the sources _M_4_H_1_9_S._A_S_M,
_M_4_H_1_9._E_Q_U, and _M_4_H_1_9._M_A_C. _M_4_H_1_9_S._A_S_M is the main source
module, and will *GET the other 2 files. The program sup-
ports a few parameters that are listed below.
REMOVE Remove and reclaim if possible.
DURATION Length of BELL tone.
FREQUENCY Frequency value (bigger value is lower
tone) for BELL.
BELL Turn audible BELL ON or OFF.
BLOCK Block cursor character.
CURSOR Normal cursor character.
STRIP8 Control display of 8 bit data.
HELP Displays information similiar to this.
SHOW Displays the current settings of the
parameters, this is the default.
These options are specified when you invoke _S_E_T_H_1_9, as per
the usual TRSDOS 6.x parameter list. An example is shown
below:
SETH19 (BLOCK=191,CURSOR=23,BELL=ON,SHOW)
This command sets the normal CURSOR, and the edit mode
CURSOR values, as well as turning the audible bell on. The
show parameter causes 2 lines similiar to those below to be
printed on the screen.
Normal Cursor: 23, Block Cursor: 191
- 29 -
Bell: ON, Frequency: 20, Duration: 120
Strip8: ON
The REMOVE option takes several things for granted, as
it tries to thoroughly remove the device. It assumes that
the H19 filter is attached to the *HP device, and that this
device is a filter hooked to *SO. Further more, it assumes
that *SO is routed to *DO.
This particular set up can be used easily if the fol-
lowing commands are used to set up the filter:
SET *HP H19/FLT FILTER *SO *HP
This is assuming that *SO is routed to *DO. The SETH19 com-
mand will perform these very operations if you invoke it,
and the memory module, $_H_E_A_T_H, is not in place.
The other parameters to the SETH19 command can be used
to control certain preferable options to the filter. Set-
ting _B_E_L_L off causes the filter to flash the screen when it
receives an ASCII(7) character. If BELL is set _O_N, then an
audible bell is issued when an ASCII(7) is received.
When BELL is ON, then the _D_U_R_A_T_I_O_N, and _F_R_E_Q_U_E_N_C_Y
parameters take effect. These 2 parameters select the
length and pitch, respectively, of the BELL tone. The FRE-
QUENCY value is used as a delay between oscillations of the
sound port, so the bigger the number, the lower the tone
will be.
The _d_e_f_a_u_l_t _D_U_R_A_T_I_O_N is set to 20, and the FREQUENCY is
set to 125. You can adjust them as you please. The DURA-
TION is inversely proportional to the FREQUENCY, since the
delay caused by the FREQUENCY value is part of the overall
DURATION of the sound. This means that as you increase FRE-
QUENCY, you must _d_e_c_r_e_a_s_e DURATION to maintain the same
length of BELL, and vice-versa.
The _B_L_O_C_K and _C_U_R_S_O_R parameters are used to control the
characters that are used as the cursor by the H19 filter.
The H19 terminal has the ability to use a visual mode cur-
sor, or a line mode cursor. Since the normal visual mode
cursor is usually a block cursor, the parameter BLOCK is
used to set the ASCII value of the visual mode cursor. The
CURSOR parameter sets the normal line mode cursor.
The switch between cursors must be done by the HOST
computer that is attached to the Model 4's communications
port. There is no magic to when the BLOCK cursor is
selected, see the description of the recognized control
sequences below.
- 30 -
The STRIP8 parameter controls whether or not data is
printed on the screen with the eighth bit set. Normally,
the filter now trims the eighth bit off so that parity can
be ignored. The command
SETH19 (STRIP8=NO)
will cause the eighth bit to not be stripped. That is to
say, data will be used as it is received by the filter.
Note that when this is done, some control characters with
parity bits attached may not be recognized.
_1_3. _F_u_t_u_r_e _m_o_d_i_f_i_c_a_t_i_o_n_s
It should be fairly straight forward to build extra
states into the filter so that it will recognize the ANSI
3.64 sequences for the operations the filter knows how to
perform. Full support of all the ANSI 3.64 sequences would
be a non-trivial investment in time. The best bet here
would, be a completely new device driver, since the overhead
of going to *DO is already costly, and trying to implement
scroll regions with *DO would be a HACK at best. If some-
body wants to do the conversion, I would like to have a copy
of the result.
_1_4. _H_E_A_T_H-_1_9 _f_i_l_t_e_r _c_a_p_a_b_i_l_i_t_i_e_s
The HEATH-19 terminal supports several advanced video
capabilities that make it an ideal source for a terminal
emulation package. Below is a list of the functions sup-
ported by the Model 4(p) H-19 emulator, and the escape
sequences that perform the operations.
_1_5. _H_e_a_t_h/_Z_e_n_i_t_h-_1_9 _C_o_n_t_r_o_l _C_o_d_e_s
The Heath/Zenith-19 terminal is equivalent to the DEC
VT52 with extensions for line and character insertion and
deletion. Items marked with an asterisk are not currently
supported by Model 4(p) H19 emulation.
Cursor Functions
Sequence Mnemonic Definition
ESC H HCUH Cursor Home
ESC C HCUF Cursor Forward
ESC D HCUB Cursor Backward
ESC B HCUD Cursor Down
ESC A HCUU Cursor Up
ESC I HRI Reverse Index
*ESC n HCPR Cursor Position Report
ESC j HSCP Save Cursor Position
ESC k HRCP Set Cursor to Previously Saved Position
- 31 -
ESC Y HDCA Direct Cursor Addressing, 1-based:
31+line# 31+col# (same as VT52)
Erasing and Editing
Sequence Mnemonic Definition
ESC E HCD Clear Display (Shift Erase)
ESC b HBD Erase Beginning of Display
ESC J HEOP Erase to End of Page (Erase Key)
ESC l HEL Erase Entire Line
ESC o HEBL Erase Beginning of Line
ESC K HEOL Erase to End of Line
ESC L HIL Insert Line
ESC M HDL Delete Line
ESC N HDCH Delete Character
ESC @ HEIM Enter Insert Character Mode
ESC O HERM Exit Insert Character Mode
Configuration
Sequence Mnemonic Definition
*ESC z HRAM Reset to Power-Up Configuration
*ESC r Bn HMBR Modify Baud Rate: Bn=
A=110, B=150, C=300, D=600, E=1200,
F=1800, G=2000, H=2400, I=3600, J=4800,
K=7200, L=9600, M=19200
ESC x Ps HSM Set Mode(s): Ps=
* 1 = Enable 25th line
* 2 = No key click
* 3 = Hold screen mode
4 = Block cursor
5 = Cursor off
* 6 = Keypad shifted
* 7 = Alternate keypad mode
8 = Auto line feed on CR
9 = Auto CR on line feed
ESC y Ps HRM Reset mode(s): Ps=
* 1 = Disable 25th line
* 2 = Enable key click
* 3 = Exit hold screen mode
4 = Underscore cursor
5 = Cursor on
* 6 = Keypad unshifted
* 7 = Exit alternate keypad mode
8 = No auto line feed
9 = No auto CR
- 32 -
*ESC < HEAM Enter ANSI Mode
Modes of Operation
Sequence Mnemonic Definition
*ESC [ HEHS Enter Hold Screen Mode
*ESC \ HXHS Exit Hold Screen Mode
ESC p HERV Enter Reverse Video Mode
ESC q HXRV Exit Reverse Video Mode
*ESC F HEGM Enter Graphics Mode
*ESC G HXGM Exit Graphics Mode
*ESC t HEKS Enter Keypad Shifted Mode
*ESC u HXKS Exit Keypad Shifted Mode
*ESC = HAKM Enter Alternate Keypad Mode
*ESC > HXAM Exit Alternate Keypad Mode
Additional Operations
Sequence Mnemonic Definition
*ESC } HDK Keyboard Disable
*ESC { HEK Keyboard Enable
*ESC v HEWA Wrap Around at End of Line
*ESC w HXWA Discard at End of Line
*ESC Z HID Identify as VT52 (ESC / K)
*ESC ] HX25 Transmit 25th Line
*ESC # HXMP Transmit Page
Enhanced Character Support
ESC [ p1 ; ... pn m Set Graphics Rendition
where p1, ..., pn are chosen from the following:
*0 Reset to normal character display.
*1 Display characters in high intensity.
*4 Display characters underlined.
*5 Display characters blinking.
*7 Display characters in reverse video.
The Heath-19 transmits the following sequences, but
it will not respond to them if they are received. Model
4(p) Kermit will transmit them only if they are programmed
with SET KEY.
ESC S HF1 Function Key #1
ESC T HF2 Function Key #2
ESC U HF3 Function Key #3
ESC V HF4 Function Key #4
ESC W HF5 Function Key #5
ESC P HF7 Function Key #7
- 33 -
ESC Q HF8 Function Key #8
ESC R HF9 Function Key #9
My thanks to Michael Carter and Roland Stolfa for their
help in testing and debugging this implementation.
Gregg Wonderly
Department of Computing and Information Sciences
Oklahoma State University
UUCP: {cbosgd, ea, ihnp4, isucs1, mcvax, uokvax}!okstate!gregg
ARPA: gregg@A.CS.OKSTATE.EDU
<<< m4mit.hex >>>
05064B45524D495401020060ED7322D33124D5CD008AFD228BBA210EBB110FBB0180073620EDB0
0601210000CDC189C282602289BA218CDECDC189C282601E43164CCD408A228FBA20311E531649
CD408A2291BA202E1E53164FCD408A2293BA2027CD708AAF329AD9CD8E6011F4AACD026ECDCD8B
CD9760C3EE61115FABCD026EC32562117BAB18F5116DAB18F0CD518A1120AACD026EC3478AD511
28CDCD026ED1C93124D5119AD91ACB7FC483891120C7CDB864112BCD3E01CD2A65C3D461219760
E5E521C1604F060009E9C3D48CC3E661C3C76BC39363C38577C33B7DC3A168C3966EC3046FC385
62C3D162C32763C3218BC3638BC3A661C38C61C35661C36592C3D891C3E993C3539301020061C3
2861C34163C309613E05118DD6D5CD2A65C3DD61E14F0600093600CDCF8A118DD6CD026EC39760
3E01119DD0CD2A65C3D461326ED83E04CD2A65C3DD613A6ED84FB72006CD0E8BC39760FE03C2D4
61CD8E60C397601169BA3E02CD2A65C3DD61B7CADD61FD2A8BBAFDCB12C62115C31169BA0600CD
6E8920083E013265BAC39760CD518AAF3265BAC397603E051120C6CD2A65C3DD61CDCF8A3E0D12
2119C6CD2A8AC397602A1CD37E23FE2028FAFE0D2804FE3F2013E5FDE1FD36FF4CFD360049FD36
0142FD36020D2BCDCF8ACD2A8AC397601132C7CD026EC397601161C7CD026EC397603E04CD2A65
C3DD61119AD91ACB7FC4838911C2D93A2AD5B7C48301020062891112DA3A2BD5B7C483891169BA
3A2CD5B7C483890E04FD210000ED5B8FBACD9189CD8E602A89BA0601CDC1892A7A8CCD4F622AC9
8CCD4F62CDC187ED7B22D3210000FD2A8BBAFDCB126EC0C3478A060836002310FBC93E413288D6
CDCF8A3A63DE4F0600218DD6E53E00CDCD73D1C3026ED5CDCF8AD1C3026EB7C8C3518ACD026EC3
CF8A3E04CD2A65C3DD61CDCF8ACD0E8BAF3264D53E31325AD5CD4E80AF3262DE3E013263DE218D
D636463E47CDA981C39C62CDB482C39C62FE59CA9760FE452006CD5C62C39760FE4EC48F6D18CB
3E04CD2A65C3DD61CDCF8ACDE562C33B63C39760AF3264D5CD0E8B3E31325AD5CD4E80AF3262DE
3E013263DE218DD601020063364C3E47CDA981C32163CDB482C3F162FE59CA9564FE45CA5C62FE
4EC48F6D18D01176C8C3026E3E04CD2A65C3DD61CDCF8ACDE562C33B63C3EE61CDCF8AC39760CD
5D64B7201E3A2AD5B7280FAF322AD511C2D9CD8389C4518A180611D8BACD026EC39760FE012015
3A2BD5B728EDAF322BD51112DACD8389C4518A18E43A2CD5B728D8AF322CD511EAD9CD8389C451
8A18CFCD5D64B7CAE563FE02CA23643A2BD5B7280911BBBACD026EC397601112DAD53E02CD2A65
C3DD61B7200B2189AF1112DA012000EDB0D12162DD0600CD6789280AFE2A2806CD518AC397603E
01322BD5C397603A2AD5B72803C3A5633E0211C2D9D5CD2A65C3DD61B7200B217DAF0102006411
C2D9012000EDB02162DBD10600CD67892804FE2A20C0AF32D5AF3E02322AD5C397603A2CD5B728
03C3A5633E0211EAD9D5CD2A65C3DD61B7200B2173AF11EAD9012000EDB0D12162DC0600CD6789
2804FE2A20823E01322CD5C397603E011175D0CD2A65C3D461C93E00C36E64E5D53275647EFE00
280CE5D5CDAD89D1E120082318EFD1E1C39564CD518A11C8AACD026ED1E1C9E1232323E9E5C5D5
1193AFD5CD158AEB3600E13E20BE20032318FAEBCD026ED1C1E1C9E1E52212D2ED7310D2ED5314
D22118D2221AD3221CD3AF320DD2320ED22F320FD23A65BAB728063AD0AFB7280ACDCF8AED5B14
D2CD026EC9ED7B10D22118D2221CD33EFF320FD22A0102006512D2E9ED7B10D22118D2221AD322
1CD3CDCF8AAF320DD2320ED23EFF320FD2ED5B14D2CD026E2A12D2E9320CD2CD0968FE06CA9765
FE04CAF165FE01CA2C66FE02CAB267FE10CAB267FE03CAB267FE05CA5A6511C4D1CD026EC9EB22
16D20600CD4368B7F28365E67FFE1BC8FE3F281EFE20280F782A16D2360DEBC39564210DD23600
042A16D277232216D218D2112CA9CD0B66C3F0640600210000229AAFCD4368B7F2B765E67FFE1B
C8FE3F283978ED5B9AAFC3956404E5D5C52A9AAF0E0AF5CD318A656FF1D630F2D865C1D1E1114B
C7CD026EC39760FE0A30F04F060009229AAFC1D1E118B71164A9CD0B66C3F064CD4368B7F0E67F
FE3F20091160C9CD010200660B66C3F064FE1BC8C39564CD026EAF320DD2CDCF8AED5B14D2CD02
6E2A1AD32B3600221AD31118D2CD026EC9ED5316D21A471313ED531ED32A1CD32220D378B7C82A
1ED3235E231D7BFEFFFA5C67CD4368B7F25267E67FFE3FC22767E5D5AF320DD2119ABACD026E21
0ED235D1E12A16D246237E32A2AFAF32A3AF237E3299AF234E7932A1AF23221ED3ED5B20D31AFE
3F2816CD776713BE2320600DF28E661AFE3F2805FE00C3FB663A99AFB72841D5E5C5ED5B1ED3CD
90683AA2AF473AA3AF80473AA4AFB838097832A3AF3AA2AF1809CDCF8A3AA2AF32A3AF914FC5ED
5B1ED3CD026EC13E20CD8F6D0D20F8C1E1D13E03815F1600191083180A2BF2F0662801020067EF
AF320DD2CDCF8ACDCF8AED5B14D2CD026E2A1CD336002A1AD32B221AD31118D2CD026EC3F064FE
1BC8E5D5CD8267C344672A1AD30118D2B7ED4211E7D1CD026EC30365D1E11C160019235E23567B
C39564CD7767BE200423C3476616007BB7F2656716FF1923232323221ED3052A20D3221CD3C33E
66FE613806FE7B3002E65FC905F81C4B7BB7C81600191E04194623EB2A1ED3237E914FB82801F0
2A20D30DFA9564EB4623EB7E23CD7767B8C0C3A067ED5318D31120C60600CD4368B7F2D467E67F
FE1BC8FE3F200E1144A9CD0B66C3F06412130418E23E0D1278B7281EE52120C6ED5B18D3CD6089
C20568EB3E03012800EDB1212700B7ED4245E1221C01020068D378C39564E1C3518AF5D5E53A0D
D2B7202D2A1AD3E51118D2B7ED5245E1CD2388DA036578320ED24806002118D2E509221AD3C1B7
ED42CA03653EFF320DD2E1D1F1C9E5C53A0DD2B7CC09682A1CD37E23221CD3FE202804FE092011
3A0FD2B720E33EFF320FD23E20C1E11820F5AF320FD2F1C1E1FE1B2814FE3F2807FE0D2803FE0A
C0E52A1CD32B221CD3E1F680C9F5D50100001AFE002804130318F7D1F1C91147CE3E113247CE3E
133248CE3E01CD2A65C3D46121BE684F060009E9C35B6AC3756AC3F36AC3A66AC38F69C37E6AC3
E16AC3EA6AC3D78AC38669C3AF69C3B269C3166BC36769C31969C34069C310691154CF3E01CD2A
65C3D461326ED83E0102006904CD2A65C3DD613A6ED832B6AFC39760CDFC6A32D0AFC397603E01
115BD1CD2A65C3D4614FFE002009CDFC6A32CD9DC39760FE03C2DD61CDFC6A32D3AFC397603E01
113FD1CD2A65C3D4614FFE002009CDFC6A32CF9DC39760FE03C2DD61CDFC6A32D4AFC3976011B9
D03E01CD2A65C3D461326ED83E04CD2A65C3DD613A6ED83268BAC39760CDFC6A328EBAC3976011
90D13E01CD2A65C3D461326ED84F3E04CD2A65C3DD613A6ED83259D5C39760AF18023E0132B5BA
11D1D03E01CD2A65C3D46121CA694F060009E9C3FF69C3DF69C32E6AC33A6AC3406AC3466AC334
6A3E06CD2A65C3DD61B7CAD4617AB728091110BACD026EC397607B324DD5C39760210102006A4F
D522B9BA3E06CD2A65C3DD61B7CAD4617AB728091110BACD026EC397602AB9BA3AB5BAB7CC4F6A
C4506AC397602153D5C3026A2157D5C3026A214BD5C3026A2151D5C3026A2155D5C3026AC30E8A
2373C9E56F2600CD9A64E1C93E04CD2A65C3DD6111A1C9CD026ECD238A3234D5CD048CC39760CD
FC6A322DD5C397601161D03E01CD2A65C3D461326ED83E04CD2A65C3DD613A6ED8322FD5C39760
CDFC6A3230D5C39760112DCF3E01CD2A65C3D4614F060021B96A09E9C3F168C3C26AC39D6A1179
D13E01CD2A65C3D461326ED83E04CD2A65C3DD613A6ED83231D5C39760CDFC6A3233D5C39760CD
FC6A3232D5C39760CDFC6A32AAAFC3976011A4D13E0102006B01CD2A65C3D461326ED83E04CD2A
65C3DD613A6ED8C93E06CD2A65C3D461B7285D7AB720507B320CBA3E051187D5ED53CDAFCD2A65
C3DD61218DD6220DBAF5AF320FBAF1B7281ECD1D962019CDD994C297605F3ACB9DB72806AF32CB
9D18E87BCDB86B18E2218DD63A0FBA473A0CBACD1F91C397601110BACD026EC3976011F9ABCD02
6ECD0D6EB728FA320CBACD17741117ACCD026E218DD60600CD0D6EB728FAFE80280D77CD177404
3EFFB828032318E978320FBA18ADE52A0DBA7723220DBA210FBA34E1C93E04CD2A65C3DD61CD3F
8C3A97BA3298BA3E503297BA3A12C3B7201A1128CDCD026E11D3C8CD026ECD048C11F5C8CD026E
3E013212C33E0ECD0102006C8F6D3E1E326C6CCD586CCD776CC3976018F0E52A17C63A15C6BD28
35F37E324D6C2C2217C62166BA35FB3A68BAB7281CC54E3A67BAB728133A97BACB3FB9380BD51E
11CD136EAF3267BAD1C13E00BFE1C9AF3266BA3CE1C9CD126CC05FCD816D3A33D5B7C45C6D7BCD
9E6D06001001C978326C6CC3586CCDFA90C295645F3A34D5BBCAA06CFE802006CD636DC395647B
D5CD7B6DD13A2DD5B77BC49E6DC39564CDFA9020FB47E65FFE43200ACD588C3A98BA3297BAC978
FE3F20403E0FCD8F6D0604CD9F89E52100260606CD9F8921000CCD916E3E1FCD8F6D11C2C9CD02
6ECDFA9020FBE1F5E52100260605CD9F89E1CD916E3E0ECD8F6DF118AAE65FFE42200102006D06
CD636DC3956478FE3020081E00CD136EC39564583A34D5BB283678E65FFE5120163A2AD5FE0220
073D322AD5C395643E07CD8F6DC39564FE52200E3A2AD5FE0120ED3C322AD5C395647BCD7B6DC3
9564CD136E3E07CD8F6DC395647BD5CD9889D1C90E01ED5B8FBACD9189F30158980B78B120FBFB
1E00C3136EB7C85FC3136EF5D55F3A2AD5B77BC42089D1F1C9D5C5F5FE07284ECD388AC178C1D1
C9D5C5F55F3A2FD5B728237BFE20301E21D6AF06004F097EB7281B5FFE0C2005CD8E601811FE07
2005CD8F6D18087BED5B93BACDAD89C178C1D1C9D5C5ED5B91BACDA689C1D1C93A8EBAB728AFC5
0E323E01D390068210FE3DD390068210FE0D20EEC10102006E18971AFE00C8B7C48F6D1318F5D5
CD1C8AD1C9D5C54B3ACFAFB7280BCD0D6EFE8020F3AF32CFAF79ED5B8FBACDAD8920F7C1D1C9AF
32446ECD0D6EB72009CD126CCA95640018EDFE0D200A3AC587B7C84FCDEB89C9FE022818FE0628
14FE012810FE05280CFE042808FE082804FE0320C7C640325CD5C9E5F52AB79C2B22B79C7CB520
0A3EC932446EF1E1C3F289F1E1C90603C39F893E333247CE3248CE3E01113FCECD2A65C3D461FE
242815FE092811326ED83E04CD2A65C3DD61CDCF8A3A6ED821CE6E4F060009019760C5E9C3BA73
C3FB72C35371C32073C3A273C30A73C39373C38473C36373C3EC72C36272C3D871C3D073C3C271
C38071C3A171C3440102006F71C3286F3E04CD2A65C3DD611158ACCD026E21FBB9ED4BFAB1B7ED
42CD9A64CDCF8ACDEC85C3976011AFCACD026E2113001185CBCD5C743A8EBACDB874CDCF8A2115
001156CCCD5C742151D5CD7974211300118CCBCD5C743A33D5CDB874CDCF8A2115001165CCCD5C
742157D5CD79742113001196CBCD5C743A32D5CDB874CDCF8A2115001174CCCD5C74214FD5CD79
7421130011A2CBCD5C743A31D5115CCBB728031164CBCD026ECDCF8A2115001185CCCD5C742155
D5CD797421130011AECBCD5C743A2DD5CDB874CDCF8A2115001196CCCD5C74214BD5CD79742113
0011BBCBCD5C74CDD788CD048CCDDC88CDCF8A21150011A8CCCD5C74214DD5CD79740102007021
130011C9CBCD5C743A30D5CDB874CDCF8A21150011BACCCD5C742153D5CD797421130011D8CBCD
5C743A68BA114ACBB720031155CBCD026ECDCF8A11DDCACD026E21130011E7CBCD5C74CDD7883A
29D5CD8F6DCDDC88CDCF8A21150011CDCCCD5C743AD3AFCDA974012006CDA074CD737421130011
F7CBCD5C743A2FD51155CBB72803116DCBCD026ECDCF8A21150011DECCCD5C743ACD9DCDA97401
2006CDA074CD73742113001108CCCD5C74CDD7883AB6AF1174CBB72003117ECBCD026ECDDC88CD
CF8A1109CBCD026E211300111BCCCD5C74CDD7883A59D5CD8F6D110DCDCD026ECDDC88CDCF8A21
150011EDCCCD5C743AD4AFCDA974012006CDA074CD010200717374211300112ECCCD5C743AD0AF
CDB874CDCF8A21150011FFCCCD5C743ACF9DCDA974012006CDA074CD73742113001142CCCD5C74
3AAAAFCDB874CDCF8ACDCF8AC39760112ECCCD026E3AD0AFCDB874C3CF8A1142CCCD026E3AAAAF
CDB874C3CF8A1108CCCD026ECDD7883AB6AF1174CBB72003117ECBCD026ECDDC88C3CF8ACDCF8A
11DECCCD026E3ACD9DCDB874CDCF8A11CDCCCD026E3AD3AFCDB874C3CF8ACDCF8A11FFCCCD026E
3ACF9DCDB874CDCF8A11EDCCCD026E3AD4AFCDB874C3CF8A11D8CBCD026E114ACB3A68BAB7C202
6E1155CBC3026E3E04CD2A65C3DD61CDCF8A2115001156CCCD5C743A51D5CD526ACDCF8A211500
1165CCCD5C743A5701020072D5CD526ACDCF8A2115001174CCCD5C743A4FD5CD526ACDCF8A2115
001185CCCD5C743A55D5CD526ACDCF8A2115001196CCCD5C743A4BD5CD526ACDCF8A21150011A8
CCCD5C743A4DD5CD526ACDCF8A21150011BACCCD5C743A53D5CD526ACDCF8AC93E04CD2A65C3DD
61CDCF8A2115001156CCCD5C743A52D5CD526ACDCF8A2115001165CCCD5C743A58D5CD526ACDCF
8A2115001174CCCD5C743A50D5CD526ACDCF8A2115001185CCCD5C743A56D5CD526ACDCF8A2115
001196CCCD5C743A4CD5CD526ACDCF8A21150011A8CCCD5C743A4ED5CD526ACDCF8A21150011BA
CCCD5C743A54D5CD526ACDCF8AC91185CBCD026E3A8EBACDB874C3CF8A11AECBCD02010200736E
3A2DD5CDB874C3CF8A11F7CBCD026E3A2FD5B71155CBCA026E116DCBC3026E112DCF3E01CD2A65
C3D461CDCF8A326ED83E04CD2A65C3DD613A6ED84F060021447309E9C36271C34D73C3757311A2
CBCD026E115CCB3A31D5B7CA026E1164CBC3026E11E7CBCD026ECDD7883A29D5CD8F6DC3DC8811
C9CBCD026E3A30D5CDB874C3CF8A1196CBCD026E3A32D5CDB874C3CF8A118CCBCD026E3A33D5CD
B874C3CF8A111BCCCD026ECDD7883A59D5CD8F6DCDDC88110DCDC3026E11BBCBCD026ECDD788CD
048CC3DC884F097EC90977C93E06CD2A65C3DD61B728297AB7201CCDCF8A7BCD6591B4280CCDCF
8A7EB7C8CD17742318F71127BAC3026E1110BACD02010200746EC3976011F9ABCD026ECD0D6EB7
28FAF5CD1774F118CCFE20300EF53E5ECD8F6DF1C640E67FC38F6DFE7F28EEDA8F6D4F3E5CCD8F
6D79E6C0CB07CB07E603C630CD8F6D79E638CB3FCB3FCB3FE607C630CD8F6D79E607C630C38F6D
D5CD9068B7ED42457DB728073E20CD8F6D10F9D1C3026E1135CBC3026E7EE5CD8D743E20CD8F6D
E1237ECD8D74CD7374C91193AF6F2600CD158AEB36001193AFCD026EC9F579CD8F6D10FAF1C911
44CBB72803113FCB210700C35C741144CBB7CA026E113FCBC3026E000000E5C5D522C574CDA880
CDDE7421000022C574D1C1E1C9C5D5E53A5AD5D631473A49D5D6059032C7742AA6AF010000B7ED
42F20275CD0C772201020075B4AF01000021ADAF097E21FED70977B728030C18F0793248D5AF32
ADAF2AB4AF010000B7ED42FA9675CD0C7722A6AF3A48D53247D54F060021FED7092243D52AB4AF
7DCD9D752A43D501FED7B7ED427D3248D52AA6AF22B4AF3A48D54F3AC774B9CA9675F293750100
003A47D5C5814F21FED7097EC121ADAF0977B728030C18E93A47D53248D54F060021FED7093600
C39675C31D753A48D5E1D1C1C9C5D5E54F3AA5AFB7CA18762AA6AF7DB920213AA8AF3C32A8AFFE
5EFA79763AA9AFCD7C773AA8AFC620CD7C77AF32A8AFC318763AA8AFFE012027AF32A8AF79CD9D
752A43D511FED7B7ED523AC774BDFAF3757D3247D5AF32A8AF79CD9D75C379763AA801020076AF
FE02FA18763AA9AFCD7C773AA8AFC621CD7C77AF32A8AF79E67F4779E68057B7280D3AAAAFB728
073AABAFCD7C774879FE7F2804FE20300C3AACAFCD7C7779C640E67F4F2A43D53AACAFB8200277
233AA5AFB7280B3AA9AFB820053AACAF77233AAAAFB7280B3AABAFB820053AACAF772371232243
D53600E1D1C1C9229EAFC5D5E5218DD6223FD54F0600E5093600E13E0132A8AF7E234FB7CA0077
3AA5AFB728103AA9AFB9200A7ED6202332A8AF7E234FAF573AAAAFB7280B3AABAFB9200516807E
234F3AACAFB9201B7E234FE67F5F7BFE40FADD76FE60FAE176FE3F200679D640E67F4F7AB14F3A
A8AF47DD21C1AFCDA58579CD5477200910F1C3917601020077E1D1C1C9CD518A3E01B718F43A31
D5B720103AA0AFFE0D20093E0A32A0AF6F2600C92AC5747CB5280A7E2322C574B72818180F119A
D9CDA689200EDD21C5AFCDA58532A0AF6F2600C93EFF3226D532A0AF6F67C9E5C54F3AA0AFFE0D
20113A99BAB7280B3A31D5B7200579FE0A280A7932A0AF2A9EAFCD4181C1E1C92A43D577232243
D5C9CDCF8A3E523288D6118DD63E05CD2A65C3DD61B7280E3263DE3271D8EB36003E723288D6CD
F8772100002260D52262D522BFAFAF325FD53264D5325CD53E523299BACD9E80CD0E8B1157ADCD
026ECD798FC397601195C83A5CD5B72807AF325CD51145C93A99BAB7C47F62C3976011A1C818F1
AF3235D52162DA220102007839D5CD0E8BC9CD4E803E31325AD5CDB482C3CB781827CD4E803E31
325AD53A71D83263DEAF3262DE3E52CDA981C389783E31325AD5CDB482C396601800FE53203E3A
64D53265D5AF3264D53A62DECD7180CD83803A63DE218DD6CD2F79218DD6CDEB783263DE3E59CD
A981C389783A5BD5325AD53E663288D63E46CD9E80C9FE45203FCD5762C38978DD21C1AFCD877C
3E413288D63A2364FE01C011EAD92156AACD6964C3A878C9AF32236411EAD9CD8389C93E413288
D6DD21C5AFCD877CC39578AF325FD51803CDE3783A5FD53262DEAF3263DE3E4ECDA981C389783E
4ECD9E80C92A62D5232262D5C93A4AD5CD2A793A4BD5CD2A793A4ED5CD2A793A50D501020079C6
4077233A52D5CD2A793A56D577233AAAAFB728053659231803364E233A5BD577233AA9AF77233E
09C9C6207723C93271D8C5AF4732A5AFCDB4797ED6203249D5CDB479237ED620324CD5CDB47923
7ED620324DD5CDB479237EC640E67F324FD5CDB479237ED6203251D5CDB479237E3255D5CDB479
233AAAAFB728147EFE592807FE4E2005AF18053E2632ABAF32AAAFCDB479237E4F3A59D5B92802
3E31325BD5CDB479237EFE2028074F32A9AF32A5AFC1C93A71D804B8F0E1C1C9CD4E80CDB482C3
CB78FE532023CD3D7CCD2E7CC2C878CDE378218DD6CDEB783263DE3E59CDA981C389783E53CD9E
80C9FE5A201ECD3D7CCD2E7CC2C878CDE378AF32630102007ADE3E59CDA981C389783E5ACD9E80
C9FE46203BCD347CC2C878CD7180CD83803E463299BACD9E80CD4386C38978CDF877CD78803263
DE3E59CDA981C389783E743288D63A5CD5FE5AC8AF325CD5C9FE42201BCD9E80CD347CC2C878AF
3263DE3E59CDA981C389783E433288D6C9FE58C2C580CD347CC0CD567CCD707CCDCF8ACD788032
63DE3E59CDA981C389783A5FD5CD7180CD83803E643288D6C911F2BACD026E1166D5CD026E3A2C
D5B7282111EAD921F2BACD6964C3DF7A2166D5CD6964C3DF7A21BEAACD6964C3DF7ACDDB80119A
D9ED5395BACDA8803E643288D6C9AF322CD511EAD9CD838918E4CD4E80CDB482C3CB78FE442067
CD347C2821CD3D7C0102007BCD2E7CC2C878CDE378AF3264D53263DE3E59CDA981C389783E25CD
9E80C9CD7180CD83803A64D53265D53A63DECD0181C38978AF3264D53263DE4F3A5CD5B7280A4F
3E013263DE79328DD63E59CDA981C389783A60D5E603C03E2ECD9E80C9FE462021CD3D7CCD2E7C
C2C878CDE378AF3264D53263DE3E59CDA981C389783E25CD9E80C9FE5AC2187CCD9E80CD347CC2
C878CD7180CD83803A63DEFE0120483A8DD6FE4420473A2CD5B7280C11EAD9216BAACD6964C30C
7C3AB6AFB72829CD9A85202ACD078A2805CD518A18201156AECD026E3A2CD5B7281411EAD92156
AECD6964C30C7C1806CD9A85CC8389AF325CD5CD78803263DE3E59CDA981C389783E0102007C66
3288D6DD21C1AFCD877CC9AF322CD511EAD9CD838918D5FE58C2C580CD2E7CC0AF3263DE3E59CD
A981C38978C93A5FD53D18033A5FD5473A62DEB8C93AB6BA473A65D5B8380AD111CBC7CD7262C3
89783C3265D5C9ED5B93BAED5395BAAF3299BACDCF8AC9F53A99BAB7C4026EF1C9218DD63A63DE
B7C84F0600093600118DD6CD026EC3CF8A2ABFAFDD4E02DD460309AFDCBB857CE603474DDD7102
DD70037CE6FC6F2600CB3DCB3DDD4E00DD460109DD7500DD7401CDC77C21000022BFAF22C9AF22
CBAFC9F53A2CD5B72846E5D5C52ACBAF7CB52815CD237D11EAD9CD6964C3167D21E1ABCD6964C3
167D2AC9AFCD237D11EAD9CD6964C3167D21E6ABCD0102007D6964C3167D21BEAACD6964C3167D
CDDB80C1D1E1F1C911EAD9CD8389AF322CD5C3117DD5C51193AFD5CD158AEB3600E13E20BE2003
2318FAC1D1C9CDCF8A3E05119AD8D5CD2A65C3D461E1225DD53E0132B7AFCD31963A28A8B72009
1190A9CD026EC39760225DD5CD4381300BCDCF8A3E13CD538AC39760CDF877AF325FD53264D521
00002260D52262D522BFAF3E31325AD53E533288D63299BACD9E80CD0E8B1157ADCD026ECD798F
C39760CD4E803E31325AD53A59D5325BD5218DD6CDEB783263DE3A60D53262DE3E53CDA981C390
78CDB482C39660FE592025CD347CC0CD8B803A63DE218DD6CD2F793A5BD5325AD53E463288D6CD
9E80CD8681C3B3780102007EC9FE4EC2C580CD9E80C9CD4E80AF325CD5118DD62172D801FF007E
FE2F280DFE3A281CFE203818EDA00418EE362EEDA0047EFE203809FE3A2805EDA00418F2ED533F
D5223BD5783263DEEB36003A5FD53262DE3E46CDA981C39078CDB482C39660FE592029CD347CC0
CD8B80CDA880CD0B81C3777E180EFEFFC2B3783E5A3288D6CD9E80C93E543288D63299BAC9FE4E
C2C580CD9E80CD9480C018CD1101BBCD026E1166D5CD026E3A2CD5B7282D11EAD92101BBCD6964
C3D17E2166D5CD6964C3D17E21BEAACD6964C3D17ECDDB80180AAF322CD511EAD9CD83893E4432
88D6C9CD4E80118DD621FED73A48D5B728054F0600EDB03A48D53263DE3A5FD532620102007FDE
3E44CDA981C3B3783A60D5E6033E2ECC9E80CDB482C39660FE592045CD347CC0CD8B803A63DEFE
0120133A8DD6FE5A2005325CD51807FE582003325CD53A5CD5B72809CD9E803E5A3288D6C9CD0B
81C3547FC9FEFFC2B3783E5A3288D6CD9E80C9FE4EC2C580CD9E80CD948028DECDE378C9CD4E80
CDD0803A5CD5B728223A2CD5B7280C11EAD9216BAACD6964C307803AB6AFB728073E44328DD63E
013263DE3E5ACDA981C39078CDB482C39660FE592043CD347CC0CD8B80CD9A85CC83893A5CD5FE
5A281FCD4381381ACD8681C3B378AF325CD53E463288D6CD9E80DD21C5AFCD877CC93E423288D6
CD9E80DD21C5AFCD877CC9FE4EC2C580CD9E80CDE30102008078CD9480C018B0AF322CD511EAD9
CD8389C3917FCD4E80CDD0803E42CDA981C39078CDB482C39660FE59200DCD347CC0CD8B803E43
3288D6C9FE4EC2C580CD9E80CDE378CD9480CA3080B728E3C93AB6BA473A64D5B8380AD111F6C7
CD7262C3B378B72807F53E25CD9E80F13C3264D5C93CE63F325FD5C93A64D53265D5AF3264D5C9
2A60D5232260D5C9CD7180CD8380C378803A5FD53C473A62DEB8C94F3A99BAB7C879C38F6DAF32
26D53248D53247D532ADAF32A8AF32A0AF21FFFF22A6AF22B4AFC9FE45C2B378CD5762C3B3783A
5FD53262DEAF3263DEC9F5C5E5D52120C6E5CDD689360D233600E1D1CD6964CDF780E1C1F1C9AF
32236411EAD9C3830102008189211681CD7D76CA9564C93A26D5B7C0CDDE74C39564ED5B95BACD
AD89C8CD518A3E58325CD5C9E52A9CAF77233600229CAFE1BFC9E5229CAF212781CD7D76E1C9E9
C9C5D5E506202172D8E53E20772310FC2A5DD5D1CD6089225DD5F52172D8E51166D5012000EDB0
2166D53E03012000EDB12B3600E1119AD9CD6089F13720013FE1D1C1C93EFF3227D5AF3226D532
28D5E5119AD92162DA0600CD6E89E12805FE2AC27A62C395643264DE2189D63A53D577233A5AD5
D631473A63DEC62380772306004F3A62DEC6207723CDAD823A64DE7723CDAD823A63DEB7280B3D
3263DE7E23CDAD8218EF3A5AD5FE322828300F79E6C0070781E63FC6207723C32E820102008236
00E5218AD6CD1D85E14B427A07070707E60FC620772378E60F070747790707E603B0C620772379
E63FC62077233A51D577233600233A32D5B72803360023CD4882C39660C395643A4DD54705FA59
823A4FD55FCD136E18F33A32D5B7280C1120CDCD026E118AD6CD026E3A2BD5B728211112DA2120
CDCD6964C388822189D6CD6964C38882180AAF322BD51112DACD83892189D67EB728075FCD136E
2318F53A57D5B728045FCD136EC39564814F3E008847C93A4CD5210000B728086F0E1ECD318A65
6F22BB9CCD8687CDF183C39660CDC187CDD184C3C882CDE78420F5CDD184C39660CDE78428F532
8AD64F3A5AD5D6314779D623903263DE0600CDD18401020083C39660CDE78428D73262DE328BD6
CDAD823A62DED6203262DECDD184C39660CDE78428BB326ED8328CD632D1AFCDAD823A63DE326F
D8218DD6223FD53A6FD83DFA5E83326FD8CDD184C39660CDE784288E2A3FD57723223FD5CDAD82
18DECD3586C3D482CDD184C39660CDE784CADF82D6203270D83A5AD5FE322841301379E6C00707
81E63F473A70D8B82858CDE378C92A3FD53600218AD6CD1D854B427A07070707E60F573A70D8BA
20E1CDD184C39660CDE784CADF82D6203270D878E60F070747790707E603B0473A70D8B820BDCD
D184C39660CDE784CADF82D6204779E63FB820A82A3FD53600233A6ED8C39564218ED72245D5CD
346EC349842A45D50102008477232245D5CDF38420ED3600233A32D5B7280C1118CDCD026E118F
D7CD026E3A2BD5B728151112DA2118CDCD6964C38882218FD7CD6964C38882218ED72245D53A58
D5CDD985C395643A5CD5FE412005CDEC851864FE42200E3E5A325CD51114ADCD667CC3F783FE46
200E3E58325CD5112BADCD667CC3F783FE452022AF325CD5CDC1873E133263DE218EC9118DD64F
0600EDB03E45CDA981C39078C39760FE43200AAF325CD5CDC187C39760FE44200F3A32D5EE0132
32D5AF325CD5C3F783FE4820081157ADCD026E18EDAF325CD5C92A45D57E232245D5CDF384C295
64C9E52153D5BEE1C9E52154D518F7E52151D518F1E52152D518EBE5214FD518E5E50102008521
50D518DFE5214BD518D9E5214CD518D3E52155D518CDE52156D518C7E5C51100007EB7CA6085E5
ABE60F06004F2174850909CD63857BAE5F237AAE57E1E57ECB3FCB3FCB3FCB3FABE60F4F217485
0909CD63857BAE5F237AAE57E123C32285C1E1C9CB3ACB1BCB3ACB1BCB3ACB1BCB3ACB1BC90000
8110022183310442855206638773088489940AA58BB50CC68DD60EE78FF77E232237D5C9ED5B95
BA219AD9B7ED52C9E5F52ABFAF237CB53E01CCBB8522BFAF22C9AFF1E1C9E5DD6E00DD66010140
0009DD7500DD7401B728072ACBAF0922CBAFE1C900B7C832D885CD346EC349844F3AD885B920F3
C9119CACCD026E2A60D5CD9A6411B4ACCD026E2A6201020086D5CD9A6411CCACCD026E2ABFAFCD
9A6411E4ACCD026E2AC1AFCD9A643E4BCD8F6D11FCACCD026E2AC5AFCD9A643E4BCD8F6DC3CF8A
C53AD2AF4F3AD1AFB9C1C8C395642187D53A63DECD35811172D80108007EFE2E282EFE20385D79
FE08200A7ECDD387280D365A18097ECDE28728032318DFEDA078B120D97EFE2E2807FE20383623
18F479FE0820043E581213362FEDA00103007EFE20381E79FE03200A7ECDD387280D365A18097E
CDE28728032318E3EDA078B120DDD5E1363A233A29D577233600E52172D81166D5012000EDB0E1
3603223BD52172D8119AD9CD6089280E2A3BD53600119AD9CD026EC3518A219AD90128003E3AED
B123223BD52B2B22010200873FD53A30D5B72865119AD92162DA0600CD6E89205811A9C8CD7262
119AD9CD83892A3FD5119AD9B7E5ED52E12006112EC8C3026E2B223FD52A3FD57EFE4238E13521
9AD9E51166D5012000EDB0D12162DA0600CD6E892008119AD9CD838918D82A3BD53600119AD9CD
026E3603119AD92162DA0600CD6789CA9564F511E4C7CD7262F1C37A62E5D5C50E002ABB9C7CB5
282722B79C0E08CDE489200A11B99CC5CDDD89C118130CFE0B20EC11C2A9CD026E21010022BB9C
0E007932C587C1D1E1C9E5D5C50E08CDEB8921000022B79CC1D1E1C9FE41D8FE5B3806FE61D8FE
7BD0BFC9FE30D8FE3A30EABFC92118D20600CD0D6EFE80281B1169BACDA6892013770102008823
04FE0D280B4F3AD0AFB779C48F6D18E6C91169BACD8389AF3265BA3E1DCD8F6D37C93A65BAB7C2
EB87FD2A8BBAFDCB126E28092118D2010050C3BA89E5D5783271D8CD238AC2B688FE08200D5F78
B728F1052B7BCD8F6D18E9FE0D2825FE18200D78B728DD3E08CD8F6D052B18F3FE1B2810FE8120
043E1B1808FE802804FE2038C004772003051810FE0D2828FE1B2824FE80282023CD8F6DFE3FC2
43883E08CD8F6D2BE5FDE13E20FDBEFF2807783D3E20C48F6D783D2008F5C17EFE3F7820013C47
7EFE1B280BCB273807CB3FF610CD8F6DD1E1C93E10C38F6D3E11C38F6D203C2A15C6712C3A17C6
BD28312215C63A97BA5F2166BA347EBB38223A68BA01020089B7281C79FE132805FE112004AF32
CFAF3A67BAB720093C3267BA1E13CD136EC9F53A2AD5FE02202FF1F5FE0A20093AD5AFFE0D2822
3E0AD532D5AF11C2D9CDAD892813CD518A11C2D9CD838911DDAACD026EAF322AD5D1F1C93E11EF
32528AC93E4EEF32528AC93E3AEF32528AC93E3BEF32528AC93E43EF32528AC93E48EF32528AC9
3E3CEF32528AC93E49EF32528AC93E05EF32528AC9C5F54F3E0618133E0FEF32528AC93E03EF32
528AC9C5F54F3E04EFC132528A78C1C93E09EF32528AC93E64EF32528AC93E4CEF32528AC93E21
EF32528AC93E13EF32528AC93E1DEF32528AC93E1CEF32528AC93E1EEF32528AC93E20EF32528A
C93E10EF32528AC90102008A3E65EF32528AC93E39EF32528AC93E60EF32528AC93E61EF32528A
C93E08EF32528AC93E01EF32528AC93E19EF32528AC93E5BEF32528AC9C5F54F3E02C3B2893E52
EF32528AC96F26003E16EF32528AC93E00C5F5FD2A8BBAFDCB02B6FDCB02BEFDCB12B6F6C04FCD
CF8A3E1AC3B289FD21E188ED5B8FBA0E04CD9189110000CD408A204122C98CE5DDE1DD360646DD
36074F3E02DD770021C08CDD7501DD7402110000CD408A201D227A8CE5DDE1DD360646DD360749
3E01DD770021718CDD7501DD7402C91189ABCD026EC3EE61F53E0DCD8F6DF1C93E06CD2A65C3DD
61B7CAD4617AB7201F4BCDCF892019C530061181AACD026E119BAACD026EC179C6300102008B32
29D5C397603E20CD538AC39760F53A17C63215C6AF3266BA32CFAF3267BAF1C93E051173AECD2A
65C3DD61B7200B3A29D53273AE3E0D3274AECDCF8ACDCF8AFD2A8BBAFD7E1BE60F2167AEFE0228
03216BAE116FAE010400D5EDB0E1CD2A8AC397603E05119AD8D5CD2A65C3DD61B72858CDCF8AE1
225DD5AF32B7AFCD31963A28A8B72844225DD5CD4381383C1172D80600218DD6CD6E892809FE2A
2805CD518A1826219AD90120003E03EDB12B360011B3AACD026E119AD9CD026ECDCF8A1172D8CD
078A28C118D5C39760CD008AFD7E0AE6F8FD770A062ECDF989FD7E0AE607C01169BA21BD9C010B
00EDB01169BA2115C30600CD6E892803FE2AC03E010102008C3265BAC93A34D5FE20300AF5113C
C9CD026EF1F640CD8F6DC93E0FCD8F6D2100260606CD9F89210EBB0605CD9F89210026110EBB01
8007EDB03E0ECD8F6DC9CD198C0604CD9F892210C32A0EC30603CD9F893E0ECD8F6DC9CD198C06
04CD9F89220EC32A10C30603CD9F893E0ECD8F6DC9180CC08C04494E50240000000000CD126C28
14CD0D6EB728F5FE8020043E1CB7C95FCD136E18E74F3A68BAB7200979FE1128DBFE1328D73A7E
8CFE0D79200E3A31D5B7792007FE0A327E8C28C1BFC9180BD38C044F5554240000000059CD136E
79BFC93E01116BCFCD2A65C3D4614FCDCF8A060021EF8C093E4732BCAFE9C39C8EC3568EC34C8E
C3608EC36A8EC3200102008D8FC37E8EC3928EC3A68EC3888EC3B08EC3BA8EC3C48EC3D08EC3DC
8EC3E88EC3F48EC3008FC30C8FC3748EC3168F1187D5060032B7BAFE4A2804FE56200479121304
0E00ED53B8AFED43BAAFCD528F3E31325AD5AF3262DE3E493288D6CDF8772100002260D52262D5
AF3299BA325FD53264D5325CD5CD0E8BCD798FC39760CD4E803A5FD53262DE21FED7118DD63ABC
AFFE432801133AB8BAB728054F0600EDB04F3ABCAFFE4328093AB7BA328DD60C3E47F5793263DE
3E31325AD53A59D5325BD5F1CDA981C39078CDB482C39660FE5320263A63DE218DD6CD2F79218D
D6CDEB783263DE3E59CDA981C390783A5BD5325AD53E663288D6C9FE58201ACD567C0102008ECD
707CCD8B803263DE3E59CDA981C390783E643288D6C9FE59200CCDCF8ACD707C3E433288D6C9FE
4EC8FE452009CD5762CDCF8AC397601141ADCD026EAF3263DE3E45CDA981C39078C397603E0132
BDAF3E44C32E8D3E0132BDAF3E45C32E8D3E0132BDAF3E55C32E8D3E0132BDAF3E48C32E8D3E02
32BDAF3E50C32E8D3E0132BDAF3E50C32E8D3E0132BDAF3E54C32E8D3E0232BDAF3E57C32E8D3E
0232BDAF3E43C32E8D3E0232BDAF3E52C32E8D3E0232BDAF3E4BC32E8D3E0232BDAF3E4DC32E8D
0E533E0232BDAF3E56C32E8D0E513E0232BDAF3E56C32E8D0E633E0132BDAF3E4AC32E8D0E733E
0132BDAF3E4AC32E8D0E2B3E0132BDAF3E4AC32E8D0102008F0E2D3E0132BDAF3E4AC32E8D3E03
32BDAF3E6CC32E8D3E0132BDAF3E51C32E8D11FED73E05CD2A65C3D4613271D83E04CD2A65C3DD
613A71D832B8BA4F060021FED70936003E0132BDAF3E4332BCAFC34F8D3E05118DD6CD2A65C3D4
61CD9290C3708F2187D5CDC8743A48D532B8BAC9117AACCD026EC397603A88D6FE442006CDE17E
C3798FFE462006CD0A7EC3798FFE542006CD9C7EC3798FFE5A2006CD737FC3798FFE532006CDAD
7DC3798FFE422006CD1480C3798FFE432006CDD977C3798FFE412006CDF377C3798FFE642006CD
EB7AC3798FFE662006CDBD79C3798FFE742006CD9C7AC3798FFE522006CD0678C3798FFE722006
CD1678C3798FFE47010200902006CD7F8DC3798FFE492006CD1890C3798FCDF377C39760CD4E80
3E31325AD53A59D5325BD5218DD6CDEB783263DE3A5FD53262DE3E49CDA981C39078CDB482C396
60FE59C26490CD347CC0CD8B803A63DE218DD6CD2F793A5BD5325AD53E473288D6C9FE4E2004CD
E378C9FE45C290783E503249D5AF324DD5324FD53E0D3251D53E31325AD53E233255D53E473288
D6C9218DD6ED5BB8AFED4BBAAFD5C5133ABDAF47F132BDAF7EFE20202123BE28FC10060412130C
18EF79C620E377E1D5130E003ABDAF3C32BDAF20DCD1C9380F0CEDA00C3ABDAF3C32BDAF20CBD1
C9E179C62077AF123ABDAF32B8BAB7CA95643CFE5CF032B8BAC395642AFCB97EB7280102009106
2322FCB9BFC921FEB922FCB9CDD86DC03202BACD6591B420E33A02BABFC92203BA3205BAF57832
01BAF1CD6591B4C47B913A01BAB7C821FBB9ED5BFAB1B7ED524F0600B7ED42300711BAABCD026E
C92A03BAD5EDB0EB36002322FAB1D12A06BA732372C921F8AF4F0600CB01300104CB81092206BA
7E23666FC92A06BA5EAF77235677ED5308BA626BEDB1E5B7ED52220ABA2AFAB1C1B7ED42C5E5C1
E178B12802EDB0ED53FAB121F8AF0600C54E23462B78B1281CE52A08BAB7ED42F2D1916069ED4B
0ABAB7ED424D44E17123701802E12323C110D6C93E05118DD6ED53CDAFCD2A65C3DD613E0132D3
9DCD1D96206DCDD994C293945F3ACB9DB72806AF3201020092CB9D18E8CD136E3A2AD5B77BC420
89FE2038D93ACF9DB728D37BF5CD126C2817CD0D6EB728F5FE80CA7694FE1BCA7F94FE81CA7F94
18E45F3AD4AFB77BC49E6D3A2AD5B77BC42089CD3C945FF1CD3C94BB28997BFE2038941166A8C3
6E94AF32D39DC397603E05118DD6ED53CDAFCD2A65C3DD613E0132D49D21019A0600CD1D96C2A5
92CDD994C293945F3ACB9DB72806AF32CB9D18E773230420E2119CA8CD026EC3BE943600783201
9BAF0E01CD649416024A3A019BB9FAE2924A0DCD55945F1C1D28144BCD5094474A0DCD5094B828
074BCD55945F18E87B3C4ACD64941418D11E003ACA9DB728404FAF32CA9D7932CC9D4F3AD3AFB7
280479CD9E6D3A2A01020093D5B779C420891C1C1D28194B0DCD5094CD3C944F3ACC9DCD3C94B9
28074BCD55945F18E33A019BBB2822CD126C28C1CD0D6EB728F5FE80CA7694FE1BCA7F94FE81CA
7F94D55FCD136ED118DEAF32D49DC397603E05118DD6ED53CDAFCD2A65C3DD613E0132D59D2104
9B22029BCD1D96C28A93CDD994C293945F3ACB9DB72806AF32CB9D18E7732318E37723360001B8
0BCD126C2849C5CD0D6EB7281DFE80C1CA7694FE1BCA7F94FE81CA7F94C55FCD136E3A2AD5B77B
C42089C10B78B120D121049B7EFE0D2006237E2BB728C023E55FCD136E3A2AD5B77BC42089E118
E432CA9DAF32D59DC397603E06CD2A65C3DD61B720031101006B620E1ECD318A656F0102009422
B79C0E08CDE4892014FD2A8BBAFD7E0AE6F8FD770A11B59CCDDD8918140CFE0B20E211EAA9CD02
6E01FFFFCDF989C397602AB79C7CB520F9C39760F53ACD9DB7280BF1FE61F8FE7BF0E65F1801F1
C921019A1803210199C50600097EC1C921019A1803210199C506000977C1C9CD026E1803CD518A
11B9A8CD026EC3BE94118EA8CD026E2A1AD336001118D2CD026EC397603AD19DB7280811CEA8CD
026E181D3AD29DB7280811EEA8CD026E180F3AD69DB7CA9760110EA9CD026E18003AD09DB7CA97
603A65BAB7CA97601169BACD8389AF3265BAC39760E5C5D5FE5C2041AF473C32D19DCD1D96C2D6
95FE30FA1895FE3AF21895FE30FA0F95FE3AF20F9501020095D630CB20CB20CB208047CD1D9628
E72ACDAF2B22CDAF7778F5AF32D19DF1C3D595FE5E20163E0132D29DCD1D96C2D695D640F5AF32
D29DF1C3D595FE3CC2D5953E0132D69D21A99CCD1D96C2D695FE3E2807CD4494772318EF36FF21
049C462311A99C1ABE2022237E13FE303806FE5B300218EF4F1AFEFF200F79FEFACAA395F5AF32
D69DF1C3D5954F7EFE2A20067932AF9C18D23EFEC5010000EDB1C110C0C3DA953AAF9CD6306F26
000E1ECD318A656F22B79CFD2A8BBAFD7E0AE6F8FD770A0E0811B59CCDDD892AB79C7CB520F93E
0132CB9DBFD1C1E1C9114AA8CD026EAF3C18F2E5F5FDE5FD2A8BBA2AB79C2B22B79C7CB5200CFD
CB0A86FDE1F1E1CD01020096F289C9FDCB0A46280F21000022B79C26322B7CB520FB18DFFDE1F1
E1C9E52ACDAF7E2322CDAFFE0D2803BFE1C9FE0EE1C922D79D2126A02226A8AF3228A82AD79D01
0000ED4346A8ED4348A8AF3242A83239A83E20BE20032318FA1131A8CD598928091141AACD026E
C397603A39A8E6A020F03A42A8E6A020E93E20BE20032318FA062011269F7EFE213808CD449412
132310F3AF127EFE213007FE0D28032318F422D79D3E209032039FCAA6973E0132049F1BEB7EFE
2F2002360021269F3A039F4F0600092B0D281B2B0D28177EFE3A20123600237E21039F3535D630
4FAF32049F1802AF4FC5CDCF89C294972129A811059F010800EDB0C1C579C630320D010200979F
32E29D3E0D320E9F21E39D060011059FCD6E89C2AF9711059FCD7C89CD7C8921E39D11059FCD75
89C27B97060821E39DC5CB66283CCB7E20383A46A8B72004CB76202E3A48A8B72004CB5E202411
269F3E0132D99DCDE8982804AF32D99DCDBA97200ECD70983AD99DB72005C1C1C33E9601200009
C110B818A5FE1C280CCD518A11059FCD8389C3976011059FCD8389C2B497C10C3E08B9CA3E963A
049FB7C2E796C33E962A26A8360D2126A0C9CD518A18E0CD518AC39760C5E5D50105000911E39E
01300B7E23FE20280C2B78FE0320043E2F1213EDA010ECAF12D1D521E39E7EB7287F1AB7287BED
53DA9D22DC9D21000022DE9D22E09D2ADC9D7EB7280102009813ED5BDA9D1ABE200B2313ED53DA
9D22DC9D18E67EB7200DED5BDA9D1AB72005BFD1E1C1C9ED5BDA9D1AFE24200B231322DC9DED53
DA9D1834FE2A200E13ED53DA9DED53DE9D22E09D18222AE09D7CB528137EB7280F2322DC9D22E0
9D2ADE9D22DA9D18083E01FE00D1E1C1C9C3FA97D5E5C521E39EED5B26A8D57EB72817EDA0E5D5
E10126A8B7ED42E120EE11A2A9CD026EC39760D5E10122A8B7ED42200911A2A9CD026EC397603E
3A12133AE29D12133E2012133E0012ED5326A82128A87EF534B7200C3AB7AFB728061180A9CD02
6EF1FEFF28C9D13AB7AFB72806CD026ECDCF8AC1E1D1C9E5D5EB7EB7280BFE24280BFE2A280723
18F13CD1E1C9BF1801030099FA0105019B00000001A7049C2341434B06FE42454C07FE425308FE
43414E18FE43520DFE44433111FE44433212FE44433313FE44433414FE44454C7FFE444C4510FE
444C592AFAFE454D19FE454E5105FE454F5404FE4553431BFE45544217FE4553431BFE46460CFE
46531CFE47531DFE485409FE4C460AFE4E414B15FE4E554C00FE52531EFE53490FFE534F0EFE53
4F4801FE53504120FE53545802FE5355421AFE53594E16FE56531FFE56541FFE000115B59CE495
0000776E00004B45524D49542F494E490D011BCA9D000000000000010000000000000000000000
000000000000300125039F00004449522F5359533A300D00000000000000000000000000000000
00000000000000010226A826A0004449522F5359533A805653595354454D0046A855494E564953
0048A800000000000D42616420636F646520696E73696465206F66203C2E2E2E3E2773000D486F
737420646964206E6F74206563686F206C617374206368617261637465722073656E740D000D49
676E6F72696E67203D3E20000D537472696E6720746F6F2062696720666F722062756666657221
0D000D4F7065726174696F6E2061626F72746564210D000D4D697373696E672063686172616374
657220666F6C6C6F77696E67205C0D000D4D697373696E672063686172616374657220666F6C6C
6F77696E67205E0D000D4D697373696E67203E20696E203C2E2E2E3E2073657175010226A9656E
63650D000D10456E7465722061207465787420737472696E67110D000D10456E74657220612066
696C652073706563696669636174696F6E21110D000D10456E746572206120446563696D616C20
6E756D62657221110D0053656E64696E672066696C65733A0D00104E6F2066696C657320666F75
6E64110D0010546F6F206D616E792066696C65732C206F7574206F66207370616365110D000D10
4E6F207461736B20736C6F747320617661696C61626C6520666F722074696D656F7574110D000D
104E6F207461736B20736C6F747320617661696C61626C6520666F722064656C61792C20757369
6E672031207365636F6E64110D000D1043616E27010226AA74206D6F7665204C4F572420746F20
6E65772076616C7565110D000D42616420706172616D65746572206C6973740D005472616E7361
6374696F6E2061626F727465640D005472616E73616374696F6E2063616E63656C65640D000D44
726976652069732077726974652070726F746563746564000D44656661756C7420647269766520
6368616E6765640D0052656D6F76696E673A200020202054696D653A20004C6F672066696C6520
492F4F206572726F722E20204C6F672066696C6520434C4F534544210D0020202020000D545253
2D3830204D6F64656C203428702920545253444F5320362E32202D204B45524D4954202D205665
7273696F6E2035010226AB2E320D427920477265676720576F6E6465726C790D0D547970652061
203F20666F722068656C7020617420616E792074696D652E2E2E2E0D000D4E6F202A434C204443
42210D000D4E6F202A534F20444342210D000D4E6F202A534920444342210D000D43616E206E6F
742066696E6420612044434220666F7220746865202A4649206F72202A464F2064657669636573
210D000D4E6F7420656E6F756768207370616365206C65667420666F7220646566696E6974696F
6E0D004B202B2000206279746573207472616E7366657265642E000D5072657373206B65797374
726F6B6520796F75206465736972653A20000D456E74657220646566696E697469010226AC6F6E
20737472696E672C20656E642077697468203C425245414B3E2028323535206368617261637465
7273204D4158290D000D52656D61696E696E67206B657920646566696E6974696F6E2073706163
653A20000D537472696E6720746F6F206C6F6E6720666F72206F6E65207061636B6574210D000D
4E756D626572206F66207061636B65747320203D3E20000D4E756D626572206F66207265747269
657320203D3E20000D4279746573207472616E7366657265642020203D3E20000D4B6279746573
207265636569766564202020203D3E20000D4B6279746573207472616E736D6974746564203D3E
200020105B43616E63656C6C696E672062617463010226AD685D11200020105B43616E63656C6C
696E672066696C655D1120000D556E6B6E6F776E207061636B657420747970650D000D20202020
204354524C2D46203D3E2043616E63656C2066696C652020202020202020202020204354524C2D
42203D3E2043616E63656C2042617463680D20202020204354524C2D43203D3E20517569742070
726F746F636F6C202020202020202020204354524C2D41203D3E205472616E7366657220737461
7475730D20202020204354524C2D44203D3E20546F67676C6520646562756767696E6720202020
2020204354524C2D48203D3E2054686973206D6573736167650D20202020204354524C2D45203D
3E2053656E6420014B26AE6572726F722C207175697420202020202020454E54455220203D3E20
526573656E64206C617374207061636B65740D000720105B4469736361726465645D1120004341
542044495220012273AF5452414E532F4C4F470D53455353494F4E2F4C4F470D44454255472F4C
4F470D011699AF00000000000000000000004E000000007E0126230102B4AF0000000100000000
0000000000000000000000000000000000000000000000000000000102030405060718091A0B0C
1D0000101112131415161718191A1B1C1D1E1F2021000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000102B4B0000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
00014AB4B100000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000FCB101
43FCB9FEB90000000000000000000000000000000000000D56616C7565206F7574206F66207261
6E676521210D000D4E6F20646566696E6974696F6E2065786973747300010665BA000000010187
89BA0000000000010000000000000000B4500108204F6E65206F662074686520666F6C6C6F7769
6E672E2E2E0D000007000000000D104C6F6766696C6520697320616C7265616479204F50454E21
110D000D104C6F6766696C65206973206E6F74204F50454E21110D00000D526563656976696E67
203D3E20000D53656E64696E67203D3E200001090EC300000000000030010D15C615C515C55345
54434F4D20010220C70E10114B45524D495420342870293E000D000D10556E7265636F676E697A
656420636F6D6D616E64110D000D10496C6C6567616C20636861726163746572110D000D104E6F
7420636F6E6669726D6564110D00556E61626C6520746F207265636569766520696E6974696174
650D00556E61626C6520746F20726563656976652066696C65206E616D650D00556E61626C6520
746F207265636569766520656E64206F662066696C650D00556E61626C6520746F207265636569
766520646174610D000D53797374656D20444F53206572726F720D004E6F2061636B6E6F776C65
6467656D656E742066726F6D2074686520686F73740D000D556E61626C6520010220C8746F2066
696E642066696C650D00556E61626C6520746F2072656E616D652066696C65000D556E61626C65
20746F2074656C6C20686F73742074686174207468652073657373696F6E2069732066696E6973
686564000D556E61626C6520746F2074656C6C20686F737420746F206C6F676F757400070D436F
6D706C6574656400074661696C65640052656E616D696E672066696C65203D3E20000D3C436C6F
73696E6720746865206C6F672066696C653E000D3C436F6E6E656374656420746F2072656D6F74
6520686F73742C207479706520004320746F2072657475726E3E0D3C434C4541523E2069732043
6F6E74726F6C2D5F0D000D3C436F6E6E6563010220C974696F6E20636C6F7365642C206261636B
206174206D6963726F3E00436F6E74726F6C2D00070D496E746572727570746564000D46696C65
204B494C4C4544000D10436F6E6669726D2077697468203C454E5445523E2C2063616E63656C20
77697468203C425245414B3E110D005472616E736665722061626F727465642E2E2E0D54797065
20746865206E657720657363617065206368617261637465723A2000100D110D0D202020203F20
3D202054686973206D6573736167650D2020202030203D2020287A65726F29205472616E736D69
742061204E554C4C0D2020202042203D202053656E64206D6F64656D20627265616B0D20202020
43203D2020010220CA436C6F73652074686520636F6E6E656374696F6E0D2020202051203D2020
51756974206C6F6767696E672073657373696F6E0D2020202052203D2020526573756D65206C6F
6767696E672073657373696F6E0D0D547970652074686520657363617065206368617261637465
7220616761696E20746F2073656E6420697420746F2074686520686F73742E100D110020202020
202020202020202020202020202020202020201053656E6411202010526563656976651120207C
20200010496E7075742073657474696E6773112020202020202020202020202020202020202020
202020207C202000104F75747075742073657474696E677311202020202020010220CB20202020
202020202020202020202020207C2020002020202020207C202000104F4E1100104F4646110010
584F4E2D584F46461100104E4F4E45110010415343494911001042494E41525911001044554D42
110010444953434152441100104B454550110042656C6C3A20005072696E7465723A2000446562
756767696E673A200046696C6520747970653A20004C6F63616C206563686F3A20004573636170
6520636861723A200046696C65207761726E696E673A2000466C6F7720636F6E74726F6C3A2000
44656661756C742064726976653A2000456D756C6174696F6E20747970653A200046696C652064
6973706F736974696F6E3A2000426C6F636B010220CC20636865636B20747970653A2000446973
706C61792054414B452066696C653A20004569676874206269742071756F74696E673A2000456E
642D6F662D6C696E653A2020005475726E2061726F756E643A2020005061642063686172616374
65723A202000436F6E74726F6C2071756F74653A20200054696D65206F75742076616C75653A20
200050616464696E67204C656E6774683A20200053746172742D6F662D7061636B65743A202000
446973706C617920696E7075743A20200049676E6F726520636173653A202000446973706C6179
206F75747075743A2020004D61746368206563686F3A2020002D63686172616374657200525061
636B3D3E00010220CD535061636B3D3E001C1F001E090103425945002121000143000606010543
4C454152003F3F0105434C4F53450042420107434F4E4E45435400060601034449520024240001
4500030301044543484F004545010445584954000303010646494E495348001B1B010347455400
0C0C0105494E50555400333301044B494C4C00272700014C002A2A01054C4F43414C002A2A0103
4C4F4700090901064C4F474F5554001E1E01064F55545055540036360105504155534500393901
0550554C5345003C3C000152000C0C010752454345495645000C0C010652454D4F544500000000
0153000F0F010453454E44000F0F01035345540012120106534554434F4D00010220CE2D2D0104
53484F570015150106535441545553001818010454414B4500303012130103414C4C0011130104
42454C4C001B1B0110424C4F434B2D434845434B2D54595045000C0C0109444542554747494E47
001515010C44454641554C542D4449534B001818011145494748542D4249542D51554F54494E47
0006060109454D554C4154494F4E000F0F0106455343415045000000010446494C45000909010C
464C4F572D434F4E54524F4C0027270105494E50555400292901034B4559002424010A4C4F4341
4C2D4543484F00030301064F5554505554002D2D01075052494E54455200121201075245434549
5645001E1E010453454E44002121010C5441010220CF4B452D444953504C4159003030030D010B
444953504F534954494F4E00000001045459504500030301075741524E494E4700060602090107
4449534341524400010101044B45455000000015100109434C4F53452D4C4F47002A2A0104434F
5059001E1E0103435744000000010644454C455445000303010344495200060601044449534B00
0909010448454C50000C0C0104484F5354000F0F01064B45524D495400121201054C4F47494E00
363601074D455353414745002121010750524F4752414D003939010E51554552592D5641524941
424C45002727010652454E414D45001818010853454E442D4C4F47002D2D010D5345525645522D
5354415455010220D053003C3C010C5345542D5641524941424C45002424010953544152542D4C
4F47003030010853544F502D4C4F47003333010454595045001B1B010357484F00151502060104
44554D4200030301044E4F4E45000000030D01054445425547000101010753455353494F4E0000
00010B5452414E53414354494F4E000202020C010A494E5055542D504F52540000000106534352
45454E000303020A01044E4F4E450000000108584F4E2D584F46460001010711010B454E442D4F
462D4C494E45000C0C01085041442D43484152000000010750414444494E47000303010F51554F
54452D434841524143544552000F0F010F53544152542D4F462D5041434B4501FA20D154000606
010854494D452D4F555400090901095455524E2D43484152001212020B0109484F53542D454348
4F0000000107444953504C4159000303020D010B434153452D49474E4F52450000000107444953
504C41590003030208010642494E41525900010101054153434949000000030801013100313101
0132003232010133003333040500024E4F00000001024F4E00010101034F464600000000035945
530001010D50726F6772616D206572726F722C20496E76616C696420434F4D4E442063616C6C00
0D416D626967756F7573000D496C6C6567616C20696E7075742066696C6573706563000D000000
00000000000000000000010E18D3000000000000000000000000014424D5000000000030000000
000000000000001F00000000000000000000000062DB000000000000205E0F0A000000000D0D01
0123230000313131009AD800000000000000010388D60001066ED8000000000202006000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000
***** 854 *****
<<< m4mit.hlp >>>
TRS-80 Model 4(p) KERMIT version 5.2 for TRSDOS 6.x, January 1986:
An advanced Kermit derived from TRS-80 Kermit, which was in turn
derived from CP/M-80 Kermit. Sum bugs have been fixed, as well
as the addition of wild cards in the SEND command. The SET
command was modified with regard to the FILE-TYPE, and
FILE-DISPOSITION options. These have become sub commands to a new
SET FILE command. The equivalent functions are now accessed via
SET FILE TYPE, and SET FILE DISPOSITION.
The following files are provided in the Kermit distribution:
Assembler source, consisting of the following modules:
M4ADD.ASM M4H191.ASM
M4KEY.ASM M4MIT.ASM
M4SEND.ASM M4STR.ASM
M4CMD.ASM M4H192.ASM
M4LOG.ASM M4PKT.ASM
M4SET.ASM M4TERM.ASM
M4GET.ASM M4H19S.ASM
M4MAC.ASM M4RMT.ASM
M4SHOW.ASM M4WILD.ASM
M4XFER.ASM
Documentation:
M4MIT.HEX -- Hexified object module for KERMIT executable
M4H19.HEX -- Hexified object module for H19 filter
M4H19S.HEX -- Hexified object module for SETH19 program
M4MIT.NR -- Nroff source for M4MIT.DOC
M4MIT.DOC -- Documentation
M4MIT.HLP -- This file
M4BOO.BAS -- Basic program for converting the hex files to
runnable programs
Here is a list of all of the command line commands that are currently
functional:
BYE
CLEAR
INPUT-PORT
SCREEN
CLOSE
SESSION-LOG
CONNECT
DIR partspec
EXIT
FINISH
GET filespec
INPUT control string
KILL filespec
LOCAL TRSDOS command
LOG filespec
LOGOUT
OUTPUT control string
PAUSE number of seconds
PULSE control string
REMOTE command
CLOSE-LOG
COPY
CWD
DELETE
DIR
DISK
HELP
HOST
KERMIT
LOGIN
MESSAGE
PROGRAM
QUERY-VARIABLE
RENAME
SEND-LOG
SET-VARIABLE
START-LOG
STOP-LOG
TYPE
WHO
SEND filespec(s)
SET parameter [value(s)] ...
BELL ON (or OFF)
BLOCK-CHECK-TYPE
1
2
3
DEBUGGING OFF (or ON)
DEFAULT-DISK (drive number)
EIGHT-BIT-QUOTING ON (or OFF)
EMULATION NONE (or DUMB)
ESCAPE
FILE
DISPOSITION KEEP (or DISCARD)
TYPE (ASCII or BINARY)
FLOW-CONTROL XON/XOFF (or NONE)
INPUT
CASE-IGNORE OFF (or ON)
DISPLAY OFF (or ON)
KEY <key value> string
LOCAL-ECHO OFF (or ON)
OUTPUT
HOST-ECHO ON (or OFF)
DISPLAY OFF (or ON)
PRINTER OFF (or ON)
RECEIVE
END-OF-LINE ascii code
PAD-CHAR ascii code
PADDING decimal number
QUOTE-CHARACTER ascii code
START-OF-PACKET ascii code
TIME-OUT decimal number
TURN-CHAR
SEND
END-OF-LINE ascii code
PAD-CHAR ascii code
PADDING decimal number
QUOTE-CHARACTER ascii code
START-OF-PACKET ascii code
TIME-OUT decimal number
TURN-CHAR
TAKE-DISPLAY OFF (or ON)
WARNING ON (or OFF)
SETCOM
SHOW
STATUS
TAKE filespec
<<< m4mit.nr >>>
.po 13
.na
.nh
.LP
.ND
.NP
.tl ''\fITRS-80 Model 4(p) KERMIT: Version 5.2\fR''
.sp
.tl ''\fIFor Use Under TRSDOS 6.1 or Later\fR''
.sp 2
.IP \fIProgram\ by:\fR 19
Gregg Wonderly Oklahoma State University, (gregg@okstate)
rewritten from the original Model-4 KERMIT which was derived
from the TRS-80 KERMIT done by Stan Barber, Rice University who
modified the CP/M-80 version by Bill Catchings and others.
.IP \fILanguage:\fR 19
Z80 Assembler, compatible with M80 and EDAS from Misosys
.IP \fIVersion:\fR 19
5.2
.IP \fIDate:\fR 19
Wed Oct 22 10:17:07 CDT 1986
.IP \fIDocumentation\ by:\fR 19
Gregg Wonderly
.sp 2
.NH
Summary of TRSDOS 6.1
.sp
.PP
\fITRSDOS\fR (The Radio Shack Disk Operating System)
has a large library of built
in commands dealing with files, directory maintenance, device I/O, etc.
Programs are also used for some functions on some \fITRSDOS\fR-based DOS's.
Model 4(p) KERMIT gives you access to all of the library
commands of \fITRSDOS\fR versions 6.x via the LOCAL command.
Issue the \fILIBRARY\fR command at \fITRSDOS Ready\fR to obtain a list.
.PP
\fITRSDOS\fR file specifications can be represented as a sequence of
characters of the form
.RS
.sp
FILESPEC/EXT.PASSWORD:D
.sp
.RE
.IP \fIFILESPEC\fR 11
is the filename up to eight characters.
.IP \fIEXT\fR
is the file type, up to three characters.
.IP \fIPASSWORD\fR
is the password for that file, up to eight characters.
.IP \fID\fR
is a numerical drive specification (0-7).
.PP
File names, file types and passwords may contain letters and numbers, but the
first character in each must be a letter. No special characters or spaces are
allowed. All fields are optional except the filespec. Any field added must be
preceded by its special delimiter '/' for file type, '.' for passwords
and ':' for drive specifications. Upper and lower case characters are
equivalent.
.NH
TRSDOS Commands of Interest
.sp
.NH 2
CAT PARTSPEC:D (OTHER OPTIONS)
.sp
.RS
This command is specific to \fITRSDOS\fR version
6.2 and later. It displays only
the names of visible files on the drive specified, or all drives if
no \fIpartspec\fR is given. \fI(other options)\fR allows different formats
and invisible as well as system files to be selected. See the \fITRSDOS\fR
manual for specifics
.RE
.NH 2
DIR PARTSPEC:D (OTHER OPTIONS)
.sp
.RS
DIR is common to all version of TRSDOS. Versions after 6.1 replaced the
DIR command with CAT, and changed the DIR command so that always
produces a long listing.
.RE
.NH 2
FREE :D
.sp
.RS
Gives statistics on disk usage. If D is present,
it indicates a drive number, and only the
statistics for the specified disk will be shown.
.RE
.NH 2
REMOVE/PURGE FILESPEC (PARAMETERS)
.sp
.RS
Remove the file(s) given by FILESPEC from the directory and frees the space
allocated to the file for reassignment. Purge allows PARTSPECs that
specify groups of files. With no PARAMETERS, PURGE prompts before
deleting any file. REMOVE requires a full filespec as the name of the
file to remove. REMOVE allows more than one filespec to
be given on the command line.
.RE
.NH 2
LIST FILESPEC (PARAMETERS)
.sp
.RS
Lists the file on the display. Parameters are described in the \fITRSDOS\fR
manual in detail. \fI(HEX)\fR is sometimes useful to display the hexidecimal
values of the characters in a file.
.RE
.NH 2
RENAME oldfile newfile
.sp
.RS
Changes the name of oldfile to newfile, provided that newfile is a
unique file name on that disk.
.RE
.NH
Copying Disks and Files:
.RS
.NH 2
COPY file1 file2
.sp
.RS
Copies file1 and name the copy file2. If file2 exists, it
will be replaced.
.RE
.NH 2
BACKUP :D :E
.sp
.RS
Makes a copy of the disk in drive D on the the disk in drive E.
.RE
.NH 2
FORMAT :D
.sp
.RS
Formats the disk in drive D. The disk will be ready for any normal
read or write operation following successful completion of this
operation. This operation must be performed before use of a blank disk.
Reformatting a previously formatted disk will cause all previously
stored information to be lost.
.RE
.RE
.NH
Transfers without the KERMIT Protocol
.PP
Model 4(p) KERMIT adds
2 logical devices to the already resident devices. These devices are
used to access the communications port. These devices,
*FI (File Input) and *FO (File Output), can be used as the source, and
destination of a copy command, respectively. They make use of the status of
the SET FLOW-CONTROL parameter, to send and receive data using the
communications port. For instance, say you are communicating with a computer
that does not have KERMIT. Say you also wish to transfer a file to
this computer to do some further processing. The normal method involves
starting a program on the remote computer to collect the data into a file
on that system. On a VAX/VMS system, you might use the CREATE command to
capture the file. The following \fIKERMIT\fR commands will accomplish
the transmition of a file in this case.
.sp
.RS
OUTPUT CREATE MYPROG.DAT<CR>
.br
LOCAL COPY PROG/DAT *FO
.RE
.sp
The KERMIT command, OUTPUT,
will send the string "CREATE MYPROG.DAT<CR>" to the host.
Let's say for now that this is sufficient to cause all future characters sent
to the host to be placed into the file MYPROG.DAT on that system.
The KERMIT command LOCAL is then used to invoke the \fITRSDOS\fR library
command COPY. COPY will copy the contents of the file "PROG/DAT" to the
*FO device. The driver for this device is part of the KERMIT program,
and will take care of transmitting the data out of the communications
port to the HOST. If the HOST sends XOFF because DATA is arriving TOO
fast, then the XON/XOFF option to the \fIKERMIT\fR command, SET FLOW-CONTROL,
will allow the transfer to pause while the HOST catches up.
You may wish to collect the contents of a file that is on another computer.
If particular computer does not have \fIKERMIT\fR,
you can use a series of commands similar to those listed below to
retrieve the file. It should be noted that the \fISESSION-LOG\fR
can also be used to trap the contents of a file.
For that very reason, this is only one of several possible ways
to get a file from another computer that does not have \fIKERMIT\fR.
.sp
.RS
OUTPUT TYPE MYPROG.DAT<CR>
.br
INPUT TYPE MYPROG.DAT<CR><LF>
.br
LOCAL COPY *FI MYPROG/DAT:1
.RE
.PP
It may help to
clarify the use of the \fIOUTPUT\fR command, and the corresponding
\fIINPUT\fR command. If you use the \fIKERMIT\fR command \fICONNECT\fR to
enter terminal mode, and then proceed to tell the host
to type out a file, it may start sending data
before you can escape back, and type the \fICOPY\fR command.
This means that some
of the data would be lost. With \fIFLOW-CONTROL\fR set to \fIXON/XOFF,\fR
and the remote
host recognizing this fact, the previous commands would not allow any data
to be lost. The use of \fIINPUT\fR is only to remove the characters
ECHOed by the
host from the input buffer (The TEXT of the command
"TYPE MYPROG.DAT"). If you are communicating with a half-duplex system
in which \fIModel (4)p KERMIT\fR is echoing the
characters typed on the keyboard, then the \fIINPUT\fR command
need not be used.
.sp 3
.NH
Control of File Transfers Using the KERMIT Protocol
.sp
.PP
During the transfer of a file using either \fISEND\fR, or \fIGET\fR and possibly
during the use of the \fIREMOTE\fR command, protocol operations may need to be
aborted, or altered. Several key strokes allow
the user to control the protocol operations. These are listed below,
and are listed on the screen after issuing either the \fISEND\fR or \fIGET\fR
commands. The operation of the \fIREMOTE\fR command is purposefully silent.
The key strokes are available to the user during \fIREMOTE\fR commands,
for added flexibility. This allows
the user to cancel commands like \fIREMOTE TYPE\fR that may otherwise cause
large amounts of data to be displayed for an extended amount of time.
The valid key strokes are:
.sp
.IP \fIControl-F\fR 15
During data transfers using the \fIKERMIT\fR protocol,
\fIControl-F\fR will terminate the current transaction.
If there are more files to transfer, the next transaction will be started.
\fIModel 4(p) KERMIT\fR will send a signal to the remote \fIKERMIT\fR
telling it to stop sending packets for the current transaction.
If the remote \fIKERMIT\fR understands this signal
(not all implementations of \fIKERMIT\fR
do), it will comply, otherwise the transaction will continue.
.IP \fIControl-B\fR
Like \fIControl-F\fR, except that if a group of files is being processed
this will stop the entire group. If only a
single file is being \fISENT\fR or \fIRECEIVED\fR, \fIControl-B\fR
behaves exactly like \fIControl-F\fR.
.IP \fIControl-C\fR
Aborts the protocol immediately. This should be a last resort to
stopping a transmission as it will leave the remote \fIKERMIT\fR in an
unknown state.
.IP \fIControl-E\fR
Aborts the protocol after sending an ERROR packet to the remote \fIKERMIT\fR.
.IP \fIControl-D\fR
Toggles \fIDEBUG\fR mode \fION\fR and \fIOFF.\fR This is helpful when
trying to figure out why a particular host is unable to talk to
\fIModel 4(p) KERMIT\fR.
.IP \fI<ENTER>\fR
If you type \fI<ENTER>\fR, \fIModel 4(p) KERMIT\fR will resend
the current packet.
.IP \fIControl-H\fR
Displays the list of \fIKEYS\fR that you may press during a transfer. I.E.
the keys described above. This is the same message that is printed when
a SEND, GET, or RECEIVE command is issued.
.sp 3
.NH
Model 4(p) KERMIT Commands
.sp
.PP
\fIModel 4(p) KERMIT\fR uses a subset of the
the \fIDECSYSTEM-20\fR keyword style command language. Each
keyword may be abbreviated to its minimum unique length. "?" may be typed to
request a list of the available options for the current field at any point in a
command. If insufficient characters have been typed to identify the
current field uniquely, \fIModel 4(p) KERMIT\fR will display all
available choices,
and then reprompt to allow you to continue from that point. If there are
sufficient characters, then only a single choice will be displayed. The
following list of commands are available when using \fIModel 4(p) KERMIT\fR.
.NH 2
BYE
.sp
.RS
When talking to a remote \fIKERMIT\fR Server, this command should shut down a
remote server and terminate the login that you had there.
\fIModel 4(p) KERMIT\fR will then exit to \fITRSDOS Ready\fR.
.RS
.sp
NOTE: Due to some
deviations from the specification, some systems do not perform exactly
in this manner. You should check the documentation of the \fIKERMIT\fR on the
remote system in order to obtain the operation performed by this command.
.RE
.RE
.NH 2
CLEAR
.sp
.RS
.NH 3
INPUT-PORT
.sp
.RS
\fIModel 4(p) KERMIT\fR uses the "Interrupt on received character available"
feature of the COM/DVR communications line driver. This driver is part of the
standard software on your system diskette.
All characters received via the interrupt vector, are placed in a 256 byte
circular buffer. This command clears all characters currently buffered.
This is used most commonly with the INPUT, OUTPUT, PULSE, and PAUSE
commands, none of which explicitly clear the input buffer. YOU MUST DO
THIS YOURSELF. The execution of this command will \fInot\fR send
an \fIXON\fR character to the communications port. This is also left
up to you to do.
.RE
.NH 3
SCREEN
.sp
.RS
As you would expect, this command clears the screen.
.RE
.RE
.NH 2
CLOSE
.sp
.RS
.NH 3
DEBUG-LOG
.sp
.RS
Closes the file previously opened with the LOG DEBUG-LOG command. If
there is not a debug logfile active, then a message is printed telling
you so.
.RE
.NH 3
SESSION-LOG
.sp
.RS
Closes the file previously opened with the LOG SESSION-LOG command. If
no file is open, you will be advised so.
.RE
.NH 3
TRANSACTION-LOG
.sp
.RS
Closes the file previously opened with the LOG TRANSACTION-LOG command. As
with the other logfiles, if a file is not currently open, then a message
to that affect is printed.
.RE
.NH 2
CONNECT (can be abbreviated to 'C')
.sp
.RS
Establish a "virtual terminal" connection to any host that may be
connected to the serial port, i.e. pass all typed characters
to the serial port and display all input from the serial port on the screen.
A two character sequence of characters is required to return the user to the
\fIKERMIT\fR program. An escape character must be typed followed by a 'c'
(Case is \fInot\fR significant).
The default <ESCAPE> character is entered by pressing the
<SHIFT> key, and then and <CLEAR> key, while holding the <SHIFT> key down.
Pressing '?'
after the <ESCAPE> character will display a list of valid keystrokes
that do helpful things during connect mode.
The first time that
you issue the \fICONNECT\fR command, a
message will be displayed telling you what the <ESCAPE> character is.
The <ESCAPE> character should generally be an uncommonly-used control character.
The following characters are valid following the \fI<ESCAPE>\fR character,
and generate specific actions. The actions are described beside the
character.
.RS
.IP \fIC\fR
Return to \fIModel 4(p) KERMIT\fR command level. The contents of the
screen and
the cursor location will be saved prior to displaying the \fIKERMIT\fR screen.
When you reconnect to the \fIHOST\fR using the \fIKERMIT\fR command,
\fICONNECT,\fR the old screen will be restored.
.IP _?
List available single-character commands, I.E. These commands.
.IP \fIB\fR
Send a TRUE modem break.
.IP \fIR\fR
Resume logging if file open, and <ESCAPE>Q was used
previously to turn logging off. See the \fILOG\fR command for more
information.
.IP \fIQ\fR
Quit logging to file but leave it open.
.IP \fI0\ (zero)\fR
Send a null (0) character out the communications port.
.IP \fI<ESCAPE>\fR
Send the \fI<ESCAPE>\fR character itself to the remote host.
.RE
.RE
.NH 2
DIR partspec
.sp
.RS
Produces a listing of the directory for "partspec". If partspec is
not given, than the directory will be displayed for the \fIDEFAULT-DISK\fR
drive as established by \fISET DEFAULT-DISK\fR.
.RE
.NH 2
EXIT
.sp
.RS
Exit \fIModel 4(p) KERMIT\fR, and return to \fITRSDOS\fR. Before the
\fIKERMIT\fR program is terminated, all open files will be closed. This
includes the LOGFILES used for SESSION, TRANSACTION, and DEBUG logging.
The *FO, and *FI devices will also be removed.
.RE
.NH 2
ECHO
.sp
.RS
This command echoes text given as an argument to the screen. It can used
in take files to put messages on the screen when TAKE-DISPLAY is OFF,
although other uses are possible.
.RE
.NH 2
FINISH
.sp
.RS
Shuts down a remote server without logging it out.
Leaves you at \fIModel 4(p) KERMIT\fR command level.
A subsequent \fICONNECT\fR command will reconnect you to the
remote host. The \fIremote KERMIT\fR should return to the
mode it was in prior to entering \fISERVER\fR mode.
.RE
.NH 2
GET filespec
.sp
.RS
Get allows you to retrieve files from a remote host. Get works
with either a \fISERVER\fR or a \fIKERMIT\fR that has initiated
a \fISEND\fR command. Filespec is a filename compatible with
\fIthat\fR system. When \fIModel 4(p) KERMIT\fR is talking to
a \fIKERMIT\fR Server, you may include
a filespec in a form legal to the \fIHOST KERMIT\fR.
.RE
.NH 2
INPUT <control string>
.sp
.RS
INPUT provides one of 4 commands that provide an automatic logon facility.
INPUT allows
you to watch for the occurrence of certain text strings that are made up
characters arriving in the communications port.
This is useful in \fITAKE\fR files that can automatically log you
onto a certain system.
.PP
When \fIINPUT\fR in initiated, it begins matching
characters in the input to those given in the control string. When
an exact match is found as established by the \fISET INPUT\fR options then
\fIINPUT\fR will return to the \fIKERMIT\fR command level.
If \fITAKE\fR is active
than the next line of the \fITAKE\fR file will be read. The Control string
may be comprised of any printable \fIASCII\fR characters. \fISPACE\fR
must not occur as either the beginning or end of the string.
.PP
\fIASCII\fR character codes
0-32 are denoted as \fI<NUL>\fR - \fI<SPA>,\fR and \fI<DEL>\fR represents
character 127.
The string \fI<DLY*>\fR signifies an immediate delay. The * should be replaced
by a character. The significance of the character is this. Decimal 48
is subtracted from the \fIASCII\fR value of the character to obtain the
number of seconds to delay. Thus, you can obtain delays
1-9 seconds, with no trickery. Delays longer than that will have
to be calculated since the formula (ASCII code - 48 decimal) is used
to calculate the binary value to use as a counter. The "*" should
be replaced with the single proper ASCII character.
.PP
If you use \fI<DLY*>\fR in
a \fIPULSE\fR command, it should be noted that it will only be done once.
An alternative format for control characters is to explicitly type
a carat ("^") preceding a character. The result of subtracting
64 from the \fIASCII\fR code for the character following will then be
used. Since <, >, and ^ now have special meanings, you will need
some way to specify them explicitly. To do this you should precede
them with a backslash, "\\", character. In this case, backslash itself
now must be represented as "\\\\". Finally, any and all characters
can be represented using a string of the form \\nnn where nnn is 1 or
more octal digits. nnn is evaluated, and the resulting value will
be the ASCII value of the character. Some examples might be:
.sp
.RS
INPUT login:<SPA>
.sp
.RS
Find the string "login:" followed by a space.
.RE
.sp
INPUT <SPA>^M^Jenter \\\\userid\\\\:<CR><LF>
.sp
.RS
Find the string with a space followed by a carriage
return followed by a line feed followed by the text
"enter \\userid\\:" followed by carriage return and another
linefeed.
.RE
.sp
INPUT USERNAME\\77\\40
.sp
.RS
Find the string "USERNAME? ". Note that \\77 is the \fIONLY\fR
way that a question mark can be specified since a question mark is
recognized by the command stream as a request for help.
.RE
.RE
.sp
While input is waiting for a match, you may type characters on the
keyboard to be transmitted. \fIBREAK\fR will abort the \fIINPUT\fR
command and if \fITAKE\fR is active, close the take file. \fIESCAPE\fR
will abort the INPUT command, but will just skip to the next line in
a \fITAKE\fR file, if \fITAKE\fR is active. These same 2 actions apply
to the \fIPULSE\fR command while no input has been received.
.RE
.NH 2
KILL wildspec
.sp
.RS
This command performs the task of deleting one or more files from
disk. \fIWildspec\fR is a wild card filespec that will be evaluated.
All files that match the \fRwildspec\fR will be removed. A \fIwildspec\fR
may contain any characters valid is a TRSDOS filespec, plus zero or more
occurances of the characters '*', and '$'. These two characters
have special meanings.
.PP
When comparing the \fIwildspec\fR with the
name of a file, a '*' matches zero or more of the characters in the
filename. E.g. If a file FOO/ASM is compared with '*/ASM', then it
would match, because '*' can be thought of as 'FOO', and then '/ASM'
is matched literally. M4*/ASM matches M4MIT/ASM, M4XFER/ASM, M4SEND/ASM,
and any other filename that begins with M4, and ends with /ASM. The '$'
character matches any single character. This means that FILE$/DOC matches
the filename FILE1/DOC, but not FILE1A/DOC.
.PP
A drivespec may be appended to the \fIwildspec\fR to force the search for
matches to be restricted to a single drive. An example might be M4*/ASM:1,
which limits the matches to those file on drive 1.
.PP
Normally, only visible, nonsystem files are considered in the search.
However, the inclusion of a parameter list containing either, or both of the
keywords, INVIS or SYSTEM, will include invisible and/or system files.
An example would be:
.RS
KILL (I,S) config/sys (I) backup/cmd
.RE
This example would cause \fIModel 4(p) KERMIT\fR to attempt to remove
the two files listed. Note that as this example shows, you must specify
the parameters with each \fIwildspec\fR that you wish to apply them to, as
they are nullified each time that a new \fIwildspec\fR is evaluated.
Other examples are given in the description of the \fISEND\fR command.
.RE
.NH 2
LOCAL <TRSDOS library command> (Can be abbreiviated to L)
.sp
.RS
This command allows you to issue commands from within
\fIModel 4(p) KERMIT\fR. You must remember where Model 4(p) KERMIT
resides in memory, to assure that you do not overwrite it. KERMIT
loads at 6000H, and continues up through LOW$. From within KERMIT,
you can issue the command:
.RS
.sp
LOCAL MEMORY
.RE
.sp
to see where KERMIT ends. The value of LOW$ tells you this information.
KERMIT was placed at 6000H to allow most of the TRSDOS library
programs and commands to work in conjunction with KERMIT. Some commands
extend above 3000H, and must have memory available up to approximately
5300H. The COPY command creates a problem because it apparently tries
to examine HIGH$ to see if there is space to load a large portion of
the source file into memory before writing it to the destination. This
creates problems because KERMIT moves LOW$ up so that HIGH$ has a value
that will allow additional high memory module to be loaded. It is suggested
that you not use COPY while KERMIT is running, as the machine may crash when
COPY completes. This is because it will have copied data into the KERMIT
memory space.
.RE
.NH 2
LOG
.RS
.NH 3
DEBUG-LOG
.sp
.RS
The debug log can be used to debug transfer problems that sometimes
arrise when talking to a newly written KERMIT. The information written
to the DEBUG-LOG is nearly identical to that which is displayed on the
screen when the command, SET DEBUG ON, is issued, or the CTRL-D key is
pressed during a transfer. This file can be closed explicitly with the
\fICLOSE DEBUG-LOG\fR command. The EXIT command also causes an implicit
closing of this file.
.RE
.NH 3
SESSION-LOG
.sp
.RS
When CONNECTed to a foreign host as a terminal, this command establishes
a log of the terminal session in the file specified.
This function depends, to
some extent, on the remote host's ability to do \fIXON/XOFF\fR flow control.
Without \fIFLOW-CONTROL,\fR data may be lost when \fIKERMIT\fR writes to
the file. The log file is closed by explicitly
typing the \fIKERMIT\fR command \fICLOSE SESSION-LOG\fR or implicitly when
\fIKERMIT\fR is exited via the \fIEXIT\fR command.
It will also be closed if an I/O error occurs in file processing for
the file involved. \fILOGGING\fR may be toggled on and off
during \fICONNECT\fR using the sequence of keys described in
the \fICONNECT\fR description.
.RE
.NH 3
TRANSACTION-LOG
.sp
.RS
The transaction log is used to keep a record of the files transfered
during a KERMIT session. The information includes whether or not
the transaction was SENDING, or RECEIVING, the name of the
file transfered, and the number of bytes involved in the transfer.
.RE
.RE
.NH 2
LOGOUT
.sp
.RS
Logout tells a \fIremote kermit server\fR to terminate itself, as
well as your login session. When this is completed, you are left
at \fIModel 4(p) KERMIT\fR command level.
.RE
.NH 2
OUTPUT <control string>
.sp
.RS
This is the other side of the \fIINPUT\fR command. Control string follows
the same conventions as in \fIINPUT,\fR and the resulting character(s) will
be output to the communications port immediately. It should be noted
that \fINO\fR characters other than what you specify are transmitted. In
other words if you want to simulate typing some string, followed by
pressing \fI<ENTER>,\fR then you will have to use a command similar to:
.sp
.RS
OUTPUT mypassword<CR>
.sp
.RE
.sp
The \fI<CR>\fR will explicitly send the \fIASCII\fR
character 13 to the communications port.
.RE
.NH 2
PAUSE <number of seconds>
.sp
.RS
This command is usually used in conjunction with \fIINPUT,\fR
\fIOUTPUT,\fR and \fIPULSE\fR as a means of syncronizing
\fIModel 4(p) KERMIT\fR to a remote host.
A delay of the specified number of seconds will be generated based on
the accuracy of the 60HZ interrupt. No means has been made for
aborting the delay. The maximum delay is 65536 seconds by specifying
0 as the number.
.RE
.NH 2
PULSE <control string>
.sp
.RS
This command is an extension/combination of \fIINPUT\fR and \fIOUTPUT.\fR
It allows you to transmit one or more characters repeatedly until a character
appears in the input port. The use of this command is valuable when
logging onto systems that don't always respond immediately after
the reception of some control character(s). For instance, you might
(Now that all of the functions of this nature have been described)
use the following commands as part of a logon sequence to log onto a
computer system.
.sp
.RS
SET INPUT CASE-IGNORE ON
.br
SET INPUT DISPLAY ON
.br
SET OUTPUT HOST-ECHO ON
.br
SET OUTPUT DISPLAY ON
.br
CLEAR INPUT-PORT
.br
PULSE ^T<CR>
.br
INPUT <CR><LF>XYZ:
.br
PAUSE 2
.br
CLEAR INPUT-PORT
.br
PULSE <CR>
.br
INPUT Username:<SPA>
.br
OUTPUT joeblow<CR>
.br
INPUT <CR><LF>Terminal type:
.br
OUTPUT h19<CR>
.br
SET KEY 8 <DEL>
.br
SET KEY 128 <ETX>
.RE
.sp
After you study this awhile, it should make sense. If these commands
are placed into a \fITAKE\fR file, then
you could use a \fICONNECT\fR command after the last command, to
connect immediately to the host. If this is done, then \fIonly\fR
after you escape back to \fIModel 4(p) KERMIT\fR, will the \fITAKE\fR file
finally be closed.
.RE
.NH 2
RECEIVE <filespec>
.RS
This command is synonomous with the GET command. It may be abbreviated to
the single character 'R', as in:
.RS
.sp
R *.asm
.sp
.RE
.RE
.NH 2
REMOTE <command>
.sp
.RS
\fIRemote\fR commands are not supported in totality by all \fIservers\fR.
If a \fIserver\fR supports remote commands, then \fIremote help\fR should
display all of the commands available to the \fIremote\fR user of the
server. Below are descriptions of the \fIremote\fR commands that
\fIModel 4(p) KERMIT\fR knows how to send to a \fIremote server\fR.
The arguments to most commands are dependent on the \fIremote\fR
system. You should be familiar with any system before using the
\fIremote server\fR commands available from that server. Usually only
a small number of these commands are supported since some require
abilities that some operating systems just don't have.
.sp
.NH 3
CLOSE-LOG
.sp
.RS
Close a remote \fILOG\fR previously opened via the command
\fIREMOTE START-LOG\fR.
.RE
.NH 3
COPY
.sp
.RS
Copy one file to another.
.RE
.NH 3
CWD <directory path>
.sp
.RS
If a particular server's operating system supports the concept of
separate directories, then this command will allow you to change to
a different directory.
.RE
.NH 3
DELETE
.sp
.RS
Deletes file(s) from the \fIremote\fR system. Any arguments will probably
be file names in the format of the \fIremote\fR system.
.RE
.NH 3
DIR
.sp
.RS
Display a list of files on the \fIremote\fR system.
.RE
.NH 3
DISK
.sp
.RS
Display information about disk utilization on the \fIremote\fR system.
.RE
.NH 3
HELP
.sp
.RS
Get information about \fIremote\fR capabilities on the \fIremote\fR system.
.RE
.NH 3
HOST
.sp
.RS
Execute a command on the \fIremote\fR system.
.RE
.NH 3
KERMIT
.sp
.RS
Execute a \fIKERMIT\fR command on the \fIremote\fR system. This command should
accept a normal \fIKERMIT\fR command as an argument. The command,
if valid, will then be executed by the remote \fIKERMIT\fR server.
.RE
.NH 3
LOGIN
.sp
.RS
Create a login entity on the \fIremote\fR system. This may be incorporated
into a dedicated server.
.RE
.NH 3
MESSAGE
.sp
.RS
Send a message to a user on the \fIremote\fR system.
.RE
.NH 3
PROGRAM
.sp
.RS
Feed command input to a command executing on the remote system, or
control the execution of a program.
.RE
.NH 3
QUERY-VARIABLE
.sp
.RS
Get the value of a variable maintained on the \fIremote\fR system.
.RE
.NH 3
RENAME
.sp
.RS
Change the name of a file on the \fIremote\fR system.
.RE
.NH 3
SEND-LOG
.sp
.RS
Tells the server to close any open log, and then transfer it to the
user.
.RE
.NH 3
SERVER-STATUS
.sp
.RS
Retrieve certain information about the status of a REMOTE server. The
information returned is dependent on the REMOTE system.
.RE
.NH 3
SET-VARIABLE
.sp
.RS
Set the value of a variable on the \fIremote\fR system.
.RE
.NH 3
START-LOG
.sp
.RS
Start a transaction log on the \fIremote\fR system.
.RE
.NH 3
STOP-LOG
.sp
.RS
Stops logging to the log file started by the \fIREMOTE START-LOG\fR
command. The file is not closed. Logging may be started again by
using the the command, \fIREMOTE START-LOG\fR.
.RE
.NH 3
TYPE
.sp
.RS
Display the contents of the file/files given as arguments. The \fIremote\fR
server should use the \fIKERMIT\fR protocol to send the contents of the
specified file/files to \fIModel 4(p) KERMIT\fR. The file contents will be
displayed on the screen using the *SO device.
.RE
.NH 3
WHO
.sp
.RS
Display a list of users on the \fIremote\fR system.
.RE
.RE
.NH 2
SEND <wildspec> (May be abbreviated to 'S');
.sp
.RS
File specifications may contain wild card characters. The recognized
wild card characters are '*' and '$'. '*' means zero or more of
any character. '$' means exactly one of any character. There are a lot
of specifics associated with wild carding, and search order through the
drives.
.PP
When files by the same name exist on different drives, a wild card match
of one will also match all other occurances. e.g. if drive 0 contains the
file report/dat, and report.dat also exist on drive 1, then the command
'SEND */dat' will collect both names for sending. On the other hand,
other variations can be used to send only one of the 2 files. 'SEND
*/dat:1' will only match files on drive 1. Another alternative would be
'SEND report/dat:1' which would send only report/dat on drive 1.
.PP
Case is NOT significant, so both REPORT/DAT and report/dat are identical.
'/' is not significantly different from other characters in a file name,
so "*/*" is the same as "*" for all file names with an extension. "*/*",
however, does not match names of the form "data", "fred", "file", "temp",
or others without extensions. Other examples are given in the description
of the \fIKILL\fR command.
.RE
.NH 2
SET <parameter [value(s)...]>
.sp
.RS
Set the specified parameter to the specified value. Possible settings:
.sp
.NH 3
BELL ON (or OFF)
.sp
.RS
When \fIDUMB\fR terminal emulation is in effect, a simple noise generator
is used to produce a tone like a bell each time the \fIBELL\fR character is
received. If you don't like it, than use \fISET BELL OFF\fR to disable it.
.RE
.NH 3
BLOCK-CHECK-TYPE
.sp
.RS
The options are:
.NH 4
1 (character checksum)
.sp
.RS
Normal, default, standard 6-bit checksum.
.RE
.NH 4
2 (character checksum)
.sp
.RS
A 12-bit checksum encoded as two characters.
.RE
.NH 4
3 (character crc-ccitt)
.sp
.RS
A 16-bit CCITT-format Cyclic Redundancy Check, encoded
as 3 characters.
.RE
.sp
The 2 and 3 character options should only be used under
conditions of extreme line noise. Many implementations of \fIKERMIT\fR
only support the single character checksum.
.RE
.NH 3
DEBUGGING OFF (or ON)
.sp
.RS
When transmitting or receiving packets, controls whether the
packets are displayed on the local screen.
.RE
.NH 3
DEFAULT-DISK <drive number>
.sp
.RS
The default-drive value is used for received files. The file names created
by \fIModel 4(p) KERMIT\fR will have a ':' and the default drive number
affixed to the end so that they will be forced to be saved on the selected
drive.
.RE
.NH 3
EIGHT-BIT-QUOTING ON (or OFF)
.sp
.RS
This command enables or disables 8th bit quoting. This is useful when
a full 8 bit path is available for binary file transfers.
.RE
.NH 3
EMULATION NONE (or DUMB)
.sp
.RS
When connected as a terminal to a foreign host, \fISET EMULATION\fR controls
whether the Model 4 emulates no terminal, allowing the use
of a terminal filter, or whether a \fIDUMB\fR terminal emulation is used.
No emulation is the default.
.RE
.NH 3
ESCAPE
.sp
.RS
Change the escape character for virtual terminal connections.
\fIModel 4(p) KERMIT\fR will prompt you for the new escape
character, which you type in locally.
.RE
.NH 3
FILE
.RS
.NH 4
DISPOSITION KEEP (or DISCARD)
.sp
.RS
When the transfer of a file is interrupted, this tells Model 4(p) KERMIT
what to do if it receives only a partial file. If FILE-DISPOSITION is
DISCARD, then any partial file is removed. Otherwise, the file is left as
it is when a transfer is interrupted.
.RE
.NH 4
TYPE (ASCII or BINARY)
.sp
.RS
Tells \fIModel 4(p) KERMIT\fR how to deal with the file being
sent/received. It is \fIIMPORTANT\fR to tell KERMIT if the file
is in \fIASCII\fR when sending to a \fINON Model 4(p) KERMIT\fR.
The action taken with this value is as follows. If \fIASCII\fR mode
is set, then CR-LF pairs of characters are translated to CR on
input, and CR is translated to CR-LF on output. When binary mode
is in effect, this translation does not occur.
.RE
.RE
.NH 3
FLOW-CONTROL XON/XOFF (or NONE)
.sp
.RS
When this feature is set to \fIXON/XOFF\fR (the default),
\fIModel 4(p) KERMIT\fR
will try its best to obey and use \fIXON\fR characters and \fIXOFF\fR
characters for all transmitions through the communications
port. \fINONE\fR will disable all attempts at this sort of flow-
control.
.RE
.NH 3
INPUT
.RS
.NH 4
CASE-IGNORE OFF (or ON)
.sp
.RS
Controls whether of not case matching is done on
characters during the input command. In most
instances, you will want this \fION\fR.
.RE
.NH 4
DISPLAY OFF (or ON)
.sp
.RS
Controls the display of characters that are input
during the execution of the \fIINPUT\fR command.
.RE
.RE
.NH 3
KEY <key value> <string>
.sp
.RS
This command allows you to send an arbitrary (the length of the
\fIKERMIT\fR command line is the limit)
string with a single key stroke. The definition of string is identical
for that of the \fIINPUT\fR, \fIOUTPUT\fR, and \fIPAUSE\fR commands.
KEY VALUE is the ASCII value of the key stroke as given in the TRSDOS
manual. If KEY VALUE is not given, then you will be asked to press
the key corresponding to the key that you wish to define. All keys are valid
in \fIstring\fR except BREAK. Pressing BREAK signals the end of the definition
string. While in \fICONNECT\fR mode, typing the defined key will cause the
characters typed as the definition to be typed instead. Defining a key
to have a \fINULL\fR length deletes any previous definition.
.RE
.NH 3
LOCAL-ECHO OFF (or ON)
.sp
.RS
When you \fICONNECT\fR to a remote host, you must set \fILOCAL-ECHO ON\fR
if the host is half duplex, \fIOFF\fR if full duplex.
.RE
.NH 3
OUTPUT
.RS
.NH 4
HOST-ECHO ON (or OFF)
.sp
.RS
When using \fIOUTPUT\fR, and communicating with a remote host,
the host commonly echoes the characters as you type.
Since \fIOUTPUT\fR effectively types characters for you,
these characters may be echoed back. If \fIHOST-ECHO\fR is
\fION\fR, \fIOUTPUT\fR will wait for the echoed character to
reappear in the input buffer before it sends the next.
In the example for sending and receiving raw data,
that is above, setting \fIHOST-ECHO ON\fR, will enable us
to remove the \fIINPUT TYPE MYPROG.DAT<CR><LF>\fR command.
Control characters are \fINOT\fR normally echoed, so this
feature when set \fION\fR, will not wait for them. If you
must catch the echo of a control character, then
follow the \fIOUTPUT\fR command with the appropriate \fIINPUT\fR
command.
.RE
.NH 4
DISPLAY OFF (or ON)
.sp
.RS
This parameter when on controls the display of characters
that are received when \fIHOST-ECHO\fR is \fION\fR. Otherwise,
They are displayed based on the status of the \fILOCAL-ECHO\fR
setting.
.RE
.RE
.NH 3
PRINTER OFF (or ON)
.sp
.RS
Turns copying of \fICONNECT\fR session to printer on and
off. With \fIFLOW-CONTROL\fR turned on, and a sending host that will
acknowledge the \fIXOFF\fR, you should have no problems using the
printer continuously.
.RE
.NH 3
RECEIVE
.RS
.NH 4
END-OF-LINE <ASCII code>
.sp
.RS
Set the end of line character in packets to some other
character than \fI<CR>\fR which is the default.
.RE
.NH 4
PAD-CHAR <ASCII code>
.sp
.RS
If the host you are communicating with needs one or
more padding characters before it receives actual data
during packet transfers, this character will be sent
\fIPADDING\fR times.
.RE
.NH 4
PADDING <decimal number>
.sp
.RS
The repeat count for the number of times the padding
character is transmitted.
.RE
.NH 4
QUOTE-CHARACTER <ASCII code>
.sp
.RS
The character used to quote control characters. The default is pound "#"
.RE
.NH 4
START-OF-PACKET <ASCII code>
.sp
.RS
The character used to syncronize the packets that
\fIKERMIT\fR transmits. By default \fI<SOH>\fR.
.RE
.NH 4
TIME-OUT <decimal number>
.sp
.RS
\fIModel 4(p) KERMIT\fR uses this value as the number of seconds to wait for
a response to a packet. If no response is received within the number of
seconds given, then the packet for which the response has not been received
is retransmitted.
.RE
.NH 4
TURN-CHAR
.sp
.RS
The character used to syncronize KERMIT when used over a half duplex
line. \fIModel 4(p) KERMIT\fR will wait for this character at the
end of a packet, and will send the SEND TURN-CHAR at the end of a packet.
.RE
.RE
.NH 3
SEND
.RS
.NH 4
END-OF-LINE <ASCII code>
.sp
.RS
Set the end of line character in packets to some other
character than \fI<CR>\fR which is the default.
.RE
.NH 4
PAD-CHAR <ASCII code>
.sp
.RS
If the host you are communicating with needs one or
more padding characters before it receives actual data
during packet transfers, this character will be sent
\fIPADDING\fR times.
.RE
.NH 4
PADDING <decimal number>
.sp
.RS
The repeat count for the number of times the padding
character is transmitted.
.RE
.NH 4
QUOTE-CHARACTER <ASCII code>
.sp
.RS
The character used to quote control characters. The default is pound "#"
.RE
.NH 4
START-OF-PACKET <ASCII code>
.sp
.RS
The character used to syncronize the packets that
\fIKERMIT\fR transmits. By default \fI<SOH>\fR.
.RE
.NH 4
TIME-OUT <decimal number>
.sp
.RS
This value is given to the \fIother\fR host as its' timeout value. You
should assure that this is different from the RECEIVE TIME-OUT value so
that both timeouts do not occur simultaneously.
.RE
.NH 4
TURN-CHAR <ASCII code>
.sp
.RS
The character used to syncronize KERMIT when used over a half duplex
line. \fIModel 4(p) KERMIT\fR will send this character at the end of a
packet. The RECEIVE TURN-CHAR will be waited for before data is transmitted.
.RE
.RE
.NH 3
TAKE-DISPLAY OFF (or ON)
.sp
.RS
Controls the display of \fITAKE\fR files as they are executed.
By default this feature is off.
.RE
.NH 3
WARNING ON (or OFF)
.sp
.RS
Warns user if filename conflicts when receiving files from
remote host, and attempt to generate a unique name by modifying
the given one. \fION\fR by default.
.RE
.RE
.NH 2
SETCOM <TRSDOS SETCOM command parameter>
.sp
.RS
Sets/shows the status of the communications driver, \fICOM/DVR\fR. If no
arguments are given, than the current status will be shown. Any
arguments must be enclosed in parenthesis as the result of this
command, is a generated \fITRSDOS\fR command as in:
.RS
.sp
SETCOM (B=9600,P=N,W=8)
.RE
.sp
The default values are established according to you. If you set up
the driver for a certain configuration, and then use \fISYSGEN\fR to save
it, then that will be the default. \fINO\fR sysgen should give you:
.RS
.sp
300 BAUD
.br
EVEN PARITY
.br
DTR=YES
.br
7 DATA BITS
.br
1 STOP BIT
.RE
.RE
.sp
.NH 2
SHOW
.sp
.RS
Allows one or ALL of the options of the \fISET\fR command to be displayed.
Using the "?" feature will aid you if you can't figure out where to
find something. All of the things that can be SET can be displayed.
The items not listed below can be displayed by using a command like:
.RS
.sp
SHOW BLOCK
.RE
.sp
or
.sp
.RS
SHOW DEFAULT
.RE
.sp
SHOW ALL will display all of the set values except keys. You must use
SHOW KEY to see these values.
.RE
.NH 3
SEND
.sp
.RS
Displays all options described under the \fISET SEND\fR command.
.RE
.NH 3
RECEIVE
.sp
.RS
Displays all options described under the \fISET RECEIVE\fR command.
.RE
.NH 3
KEY <ASCII key value>
.sp
.RS
If <ASCII key value> is specified, then the definition for the specified
key number is display. Otherwise, a prompt is issued for the user to
type the keystroke that should be taken as the key to display. \\nnn
is used to display all values greater than 127. ^x where x is a
character 64 greater than 0 through 31, and 127 is used to display
control characters. Any other printable ASCII character is displayed
normally.
.RE
.RE
.NH 2
STATUS
.sp
.RS
Shows certain information about the status of \fIModel 4(p) KERMIT\fR. Items
currently displayed include the amount of space left in the \fIKEY\fR definition
table, the number of bytes written to files during transfers, the number
of bytes read from files during transfers, as well as statistics on the
latest transfer.
.RE
.NH 2
TAKE <filespec>
.sp
.RS
TAKE allows commands to be stored in a file, and then executed by
the \fIKERMIT\fR command interpreter. Only \fIone\fR level of \fITAKE\fR
files is
supported. This means that a \fITAKE\fR command can not appear inside of
a \fITAKE\fR file. No checking is done to enforce this, so good luck if you
want to try it. When \fIKERMIT\fR is first entered, a check is made for
a file called \fIKERMIT/INI\fR on all of the active disk drives as per
normal \fITRSDOS\fR searching order. If it is found, than it is used as
a \fITAKE\fR file where you can store initialization commands. Pressing the
\fIBREAK\fR key, or the \fIENTER\fR key during the startup of KERMIT (before the
TAKE file is opened) will cause \fIKERMIT\fR to skip
processing of the \fITAKE\fR file.
.RE
.sp 3
.NH
Setting up to use Model 4(p) KERMIT
.PP
To use \fIModel 4(p) KERMIT\fR, you need to have your Model 4 set up
properly. The program expects that the *CL device will be driven by the
COM/DVR Communications Driver that comes with TRSDOS. It also expects that
the *SO device is ROUTED to the *DO device, and that the *SI device is
ROUTED to the *KI device. The former 2 are the defaults, and in general,
you should not worry about them, unless you have changed them. Setting up
the *CL device involves typing the command:
.RS
.sp
SET *CL COM/DVR
.RE
.sp
at the \fITRSDOS Ready\fR prompt. If you do not do this, you will get a message
of the form
.RS
.sp
Can't find *CL DCB
.RE
.sp
from \fIModel 4(p) KERMIT\fR when it is starting up. The program will return
control to TRSDOS after issuing this message, as it is a fatal error.
.PP
\fRModel 4(p) KERMIT\fR is not a small program. It occupies memory starting
at 6000H, and extends up past 0D300H. If you have parts of TRSDOS resident
(Using the SYSTEM (SYSRES=....) command), or perhaps other filters or memory
resident modules, then you should make sure that they do not extend below
the maximum address used by the program.
The last memory address used by \fIModel 4(p) KERMIT\fR can
be obtained by using the command
.RS
.sp
LOCAL MEMORY
.RE
.sp
from within the \fIModel 4(p) KERMIT\fR program.
.sp 3
.NH
Installation
.PP
To install \fIModel 4(p) KERMIT\fR, you must obtain the two
files \fIM4BOO.BAS\fR and \fIM4MIT.HEX\fR. Because of the size of the
executable, the hex file could not be placed into a basic program as data
statements. Instead, the basic program
opens and reads the file \fIM4MIT.HEX\fR. This file is an \fIASCII\fR image of
the executable. All that needs to be done, is to run the \fIBASIC\fR program
which will convert the file back to its original binary format.
The resulting executable should probably be called \fIKERMIT/CMD\fR.
Follow the prompts of the BASIC program and there should not be any problems.
.NH
Building \fIModel 4(p) KERMIT\fR from the Source.
.PP
The Source for \fIModel 4(p) KERMIT\fR is in approximately 15 modules. The
names of the modules are:
.RS
.IP M4ADD/ASM 15
Code for miscellaneous routines.
.IP M4CMD/ASM
Command parser code.
.IP M4EQU/ASM
Mosts constants are defined here
.IP M4FILE/ASM
Additional logfile code such as the LOG command, and the CLOSE command.
.IP M4GET/ASM
Receive file routines + other miscellany.
.IP M4KEY/ASM
Code for handling the SET KEY functions
.IP M4LOG/ASM
INPUT, OUTPUT, PAUSE, PULSE commands.
.IP M4MAC/ASM
Macros used in the program
.IP M4MIT/ASM
Main entry and some command routines.
.IP M4PKT/ASM
New packet routines for encoding and decoding packets.
.IP M4RMT/ASM
The base of what will be the remote command.
.IP M4SEND/ASM
Send file routines.
.IP M4SET/ASM
Set options routines.
.IP M4SHOW/ASM
Show settings routines.
.IP M4STR/ASM
The majority of storage, prompts, and messages.
.IP M4TERM/ASM
Terminal Emulation, and I/O routines.
.IP M4WILD/ASM
Wild card file name processing.
.IP M4XFER/ASM
File processing, and some packet stuff.
.RE
.PP
\fIModel 4(p) KERMIT\fR was developed using the \fIEDAS\fR assembler from
Misosys. Other macro assemblers should be able to assemble the program
with minor conversions.
\fIM4MIT/ASM\fR is the main source module. It will call the other
source files into
the assembly (using the *GET directive) as needed.
If any system calls need to be changed, they are
all defined in \fIM4ADD/ASM\fR
for the most part. All of the SVC's are coded in
\fIM4ADD/ASM\fR as subroutines that are accessed by CALL Xaaaaa, where aaaaa is
the name of the \fITRSDOS\fR supervisor call (SVC) without the "@" sign.
.PP
If this version is moved to another OS, there are several things that you
should consider. The things that come to mind are:
.sp
.RS
.IP 1. 5
Consider the format of the TRSDOS directory structure. The wild card routines
depend on this structure for validating directory entries, and for retrieving
the file name.
.IP 2.
There are 2 places where real time counting is required. The delay specified
in a PAUSE statement can be handled with a counter, as all other processing
is halted (except the interrupt tasks) during the pause. Currently, the
Real Time Clock task is used to measure the appropriate delay. The other
use of a Real Time counter occurs in the Receive packet timeout. This must
be handled using asyncronous processes in order to be accurate.
.IP 3.
There exist code at the beginnning and end of the segment that accesses the
screen which outputs the bytes 14, and 15 to the *DO device. These are used
to force the cursor to be invisible before the screen is accessed, and to then
make it reappear after the screen access is completed.
.IP 4.
The interrupt driven receiver must also be delt with. The code in the
routine SETINT, establishes the interrupt vector that the *CL driver will
call when a "character received interrupt" is generated.
.IP 5.
In many instances, the characters having values 16, and 17 are used to
enable, and disable reverse video respectively. If the driver for *DO
does not recognize this convention, as the current one does, then these
characters must be handled in some manner. I.E. either removed from the
source, or filtered from the terminal output stream. The PRTSTR() routine
is a good place to mask these characters at, as it is the sole source of
output for strings containing these type of characters.
.RE
.sp
.PP
It should be noted that \fIKERMIT/CMD\fR loads into RAM at 6000H. This avoids
high memory filters and drivers, and also allows use of \fITRSDOS\fR library
commands that use low memory beyond 3000H, as FORMAT, and BACKUP do.
Exclusive use is made of the *DO device for screen output from the KERMIT
program, for informational messages and the like. During
connect mode, *SI and *SO are used as the input and output
devices to allow filters to be attached that will not effect the operation
of \fIModel 4(p) KERMIT\fR during command operations.
If you install a different driver or filter it must be compatible in
these areas.
.NH
Performance Specifics of Model 4(p) KERMIT
.PP
The \fIModel 4(p) KERMIT\fR has been tested and proven to work properly at
9600 BAUD with flow control on, transferring files between 2 Model 4's.
What makes the \fIModel 4(p) KERMIT\fR perform so well is
the idea of flow control, and the interrupt driven receiver. With out these
features, I expect that 2400 baud would be the reliable limit. Flow control
can be disabled at speeds less than or equal to ~2400 baud, but greater speeds
require that flow control be functional in order to protect the integrity of
data in the input buffer.
.sp 3
.NH
The Heath 19 Filter
.PP
The files \fIM4H191.ASM, M4H192.ASM, M4H19.MAC\fR, and \fIM4H19.EQU\fR
make up the sources for a Heath 19 terminal emulation filter for the
TRS-80 Models 4 and 4p. The assembler used was EDAS by Misosys.
To build the filter from sources, you need the above 4 files on a
disk. \fIM4H191.ASM\fR is the main source module, and it *GETs all the other
necessary files.
.PP
The structure of the program is pretty simple. Single character
(non escape) sequences, are passed to the
filtered device via the \fI@CHNIO\fR svc. This filter depends on the
\fITRSDOS *DO\fR driver being at the end of the chain. Several control
characters are merely translated, and then the new values are passed
to *DO.
.PP
A multi-character escape sequence is handled by remembering the previous
characters that the filter was passed. The previous characters are
remembered by the presence of a non-zero value in the contents
of \fISTATE\fR. The value in \fISTATE\fR represents the address of
the code to
handle the next character, given the previous string of characters.
.PP
The filter is relocatable, but \fIMUST\fR reside below screen memory because
it accesses it directly when performing several of the advanced terminal
functions. For this reason, it will never load \fIabove F3ffH\fR.
.NH
The SETH19 Program
.PP
The \fISETH19\fR program allows you to configure a few options
that are available to you when using the \fIH19 filter\fR.
The \fISETH19\fR program is created from the sources
\fIM4H19S.ASM, M4H19.EQU,\fR and \fIM4H19.MAC\fR. \fIM4H19S.ASM\fR
is the main source module, and will *GET the other 2 files.
The program supports a few parameters that are listed below.
.RS
.sp
.IP REMOVE 15
Remove and reclaim if possible.
.IP DURATION
Length of BELL tone.
.IP FREQUENCY
Frequency value (bigger value is lower tone) for BELL.
.IP BELL
Turn audible BELL ON or OFF.
.IP BLOCK
Block cursor character.
.IP CURSOR
Normal cursor character.
.IP STRIP8
Control display of 8 bit data.
.IP HELP
Displays information similiar to this.
.IP SHOW
Displays the current settings of the parameters, this is the default.
.LP
.RE
These options are specified when you invoke \fISETH19\fR, as per the usual
TRSDOS 6.x parameter list. An example is shown below:
.RS
.sp
SETH19 (BLOCK=191,CURSOR=23,BELL=ON,SHOW)
.RE
.PP
This command sets the normal CURSOR, and the edit mode CURSOR values, as
well as turning the audible bell on. The show parameter causes 2
lines similiar to those below to be printed on the screen.
.RS
.sp
Normal Cursor: 23, Block Cursor: 191
.br
Bell: ON, Frequency: 20, Duration: 120
.br
Strip8: ON
.sp
.RE
.PP
The REMOVE option takes several things for granted, as it tries to
thoroughly remove the device. It assumes that the H19 filter is
attached to the *HP device, and that this device is a filter hooked
to *SO. Further more, it assumes that *SO is routed to *DO.
.PP
This particular set up can be used easily if the following commands
are used to set up the filter:
.RS
.sp
SET *HP H19/FLT
FILTER *SO *HP
.RE
.sp
This is assuming that *SO is routed to *DO. The SETH19 command
will perform these very operations if you invoke it, and the memory
module, \fI$HEATH\fR, is not in place.
.PP
The other parameters to the SETH19 command can be used to control
certain preferable options to the filter. Setting \fIBELL\fR off causes
the filter to flash the screen when it receives an ASCII(7) character.
If BELL is set \fION\fR, then an audible bell is issued when an ASCII(7) is
received.
.PP
When BELL is ON, then the \fIDURATION,\fR and \fIFREQUENCY\fR parameters take
effect. These 2 parameters select the length and pitch, respectively,
of the BELL tone. The FREQUENCY value is used as a delay between
oscillations of the sound port, so the bigger the number, the lower the
tone will be.
.PP
The \fIdefault DURATION\fR is set to 20, and the FREQUENCY
is set to 125. You can adjust them as you please. The DURATION
is inversely proportional to the FREQUENCY, since the delay caused
by the FREQUENCY value is part of the overall DURATION of the sound.
This means that as you increase FREQUENCY, you must \fIdecrease\fR
DURATION to maintain the same length of BELL, and vice-versa.
.PP
The \fIBLOCK\fR and \fICURSOR\fR parameters are used to control
the characters that are used as the cursor by the H19 filter.
The H19 terminal has the
ability to use a visual mode cursor, or a line mode cursor. Since
the normal visual mode cursor is usually a block cursor, the parameter
BLOCK is used to set the ASCII value of the visual mode cursor. The
CURSOR parameter sets the normal line mode cursor.
.PP
The switch between cursors must be done by the HOST computer that is
attached to the Model 4's communications port. There is no magic
to when the BLOCK cursor is selected, see the description of the
recognized control sequences below.
.PP
The STRIP8 parameter controls whether or not data is printed on the
screen with the eighth bit set. Normally, the filter now trims the
eighth bit off so that parity can be ignored. The command
.RS
.sp
SETH19 (STRIP8=NO)
.RE
.sp
will cause the eighth bit to not be stripped. That is to say, data will be
used as it is received by the filter. Note that when this is done, some
control characters with parity bits attached may not be recognized.
.PP
.NH
Future modifications
.PP
It should be fairly straight forward to build extra states into the
filter so that it will recognize the ANSI 3.64 sequences for the
operations the filter knows how to perform. Full support of all
the ANSI 3.64 sequences would be a non-trivial investment in time. The
best bet here would, be a completely new device driver, since the
overhead of going to *DO is already costly, and trying to implement
scroll regions with *DO would be a HACK at best.
If somebody wants to do the conversion, I would like to have a
copy of the result.
.NH
HEATH-19 filter capabilities
.PP
The HEATH-19 terminal supports several advanced video capabilities
that make it an ideal source for a terminal emulation package. Below
is a list of the functions supported by the Model 4(p) H-19 emulator,
and the escape sequences that perform the operations.
.NH
Heath/Zenith-19 Control Codes
.PP
The Heath/Zenith-19 terminal is equivalent to the DEC VT52 with extensions for
line and character insertion and deletion. Items marked with an asterisk are
not currently supported by Model 4(p) H19 emulation.
.sp 2
.na
.nf
Cursor Functions
.sp
Sequence Mnemonic Definition
.br
ESC H HCUH Cursor Home
.br
ESC C HCUF Cursor Forward
.br
ESC D HCUB Cursor Backward
.br
ESC B HCUD Cursor Down
.br
ESC A HCUU Cursor Up
.br
ESC I HRI Reverse Index
.br
*ESC n HCPR Cursor Position Report
.br
ESC j HSCP Save Cursor Position
.br
ESC k HRCP Set Cursor to Previously Saved Position
.br
ESC Y HDCA Direct Cursor Addressing, 1-based:
.br
31+line# 31+col# (same as VT52)
.sp 3
Erasing and Editing
.sp
Sequence Mnemonic Definition
.br
ESC E HCD Clear Display (Shift Erase)
.br
ESC b HBD Erase Beginning of Display
.br
ESC J HEOP Erase to End of Page (Erase Key)
.br
ESC l HEL Erase Entire Line
.br
ESC o HEBL Erase Beginning of Line
.br
ESC K HEOL Erase to End of Line
.br
ESC L HIL Insert Line
.br
ESC M HDL Delete Line
.br
ESC N HDCH Delete Character
.br
ESC @ HEIM Enter Insert Character Mode
.br
ESC O HERM Exit Insert Character Mode
.sp 3
Configuration
.sp
Sequence Mnemonic Definition
.br
*ESC z HRAM Reset to Power-Up Configuration
.br
*ESC r Bn HMBR Modify Baud Rate: Bn=
.br
A=110, B=150, C=300, D=600, E=1200,
.br
F=1800, G=2000, H=2400, I=3600, J=4800,
.br
K=7200, L=9600, M=19200
.sp 2
ESC x Ps HSM Set Mode(s): Ps=
.br
* 1 = Enable 25th line
.br
* 2 = No key click
.br
* 3 = Hold screen mode
.br
4 = Block cursor
.br
5 = Cursor off
.br
* 6 = Keypad shifted
.br
* 7 = Alternate keypad mode
.br
8 = Auto line feed on CR
.br
9 = Auto CR on line feed
.sp 2
ESC y Ps HRM Reset mode(s): Ps=
.br
* 1 = Disable 25th line
.br
* 2 = Enable key click
.br
* 3 = Exit hold screen mode
.br
4 = Underscore cursor
.br
5 = Cursor on
.br
* 6 = Keypad unshifted
.br
* 7 = Exit alternate keypad mode
.br
8 = No auto line feed
.br
9 = No auto CR
.sp 2
*ESC < HEAM Enter ANSI Mode
.sp
Modes of Operation
.sp
Sequence Mnemonic Definition
.br
*ESC [ HEHS Enter Hold Screen Mode
.br
*ESC \\ HXHS Exit Hold Screen Mode
.br
ESC p HERV Enter Reverse Video Mode
.br
ESC q HXRV Exit Reverse Video Mode
.br
*ESC F HEGM Enter Graphics Mode
.br
*ESC G HXGM Exit Graphics Mode
.br
*ESC t HEKS Enter Keypad Shifted Mode
.br
*ESC u HXKS Exit Keypad Shifted Mode
.br
*ESC = HAKM Enter Alternate Keypad Mode
.br
*ESC > HXAM Exit Alternate Keypad Mode
.sp 3
Additional Operations
.sp
Sequence Mnemonic Definition
.br
*ESC } HDK Keyboard Disable
.br
*ESC { HEK Keyboard Enable
.br
*ESC v HEWA Wrap Around at End of Line
.br
*ESC w HXWA Discard at End of Line
.br
*ESC Z HID Identify as VT52 (ESC / K)
.br
*ESC ] HX25 Transmit 25th Line
.br
*ESC # HXMP Transmit Page
.sp 3
Enhanced Character Support
.sp
ESC [ p1 ; ... pn m Set Graphics Rendition
.br
where p1, ..., pn are chosen from the following:
.br
*0 Reset to normal character display.
.br
*1 Display characters in high intensity.
.br
*4 Display characters underlined.
.br
*5 Display characters blinking.
.br
*7 Display characters in reverse video.
.br
.fo
.ad
.sp 2
.PP
The Heath-19 transmits the following sequences, but
it will not respond to
them if they are received. Model 4(p) Kermit will transmit them
only if they are programmed with SET KEY.
.sp
.nf
.na
ESC S HF1 Function Key #1
.br
ESC T HF2 Function Key #2
.br
ESC U HF3 Function Key #3
.br
ESC V HF4 Function Key #4
.br
ESC W HF5 Function Key #5
.br
ESC P HF7 Function Key #7
.br
ESC Q HF8 Function Key #8
.br
ESC R HF9 Function Key #9
.fo
.PP
My thanks to Michael Carter and Roland Stolfa for their help in testing and
debugging this implementation.
.sp 2
.nf
Gregg Wonderly
.br
Department of Computing and Information Sciences
.br
Oklahoma State University
.sp 2
UUCP: {cbosgd, ea, ihnp4, isucs1, mcvax, uokvax}!okstate!gregg
.br
ARPA: gregg@A.CS.OKSTATE.EDU