IMD 1.16: 1/06/2007 9:46:04 FOGCPM.155 --FOGCPM155-01-00 87 -CPM155 DOCCP4CMD ASM CP4CMD ASM6CP4CPM ASM4 !"#$CP4DEF ASM<%&'()*+,CP4KER ASM-./0CP4LNK ASM912345678CP4MIT ASM9:;<=>?@ABCDEFGHCP4MIT ASMdIJKLMNOPQRSTUCP4TT ASMVWXYZ[\]^_`abcdeCP4TT ASM4fghijklCP4TYP ASMBmnopqrstuCP4UTL ASMvwxyz{|}~CP4UTL ASMoCP4WLD ASMLASM COM,LASM DOC'MLOAD COMThis is the disk name.  This is the release date of the disk. LASM DOC MLOAD COM CP4WLD .ASM 29 0F 3968 31 LASM .COM BE 32 5632 44 LASM .DOC E0 E9 4992 39 MLOAD .COM 6D 48 2816 22  Fog Library Disk FOG-CPM.155 Copyright (1987) by Fog International Computer Users Group to the extent not copyrighted by the original author for the exclusive use and enjoyment of its members. Any reproduction or distribution for profit or personal gain is strictly forbidden. For information, contact FOG, P. O. Box 3474, Daly City, CA. 94015-0474. as part of the description of a file indicates that the program is distributed on a "try first, pay if you like it" basis. If you find the program(s) meet your need, please refer to the author's documentation for information on becoming a registered user. Only by registering and paying for the programs you like and use will the authors of such programs continue development. Often, more complete documentation, additional modules, and new releases are available only to registered users. Disk 3 of 4. Kermit. Filename Description -01-00 .87 This is the release date of the disk. -CPM155 .DOC This is the description of the disk contents. CP4KER .ASM 1DF6 4K ver. 4.05 [Kermit 36 of 50] CP4CMD .ASM 09B0 23K ver. 4.05 [Kermit 37 of 50] CP4CPM .ASM C763 7K ver. 4.05 [Kermit 38 of 50] CP4DEF .ASM C0D0 8K ver. 4.05 [Kermit 39 of 50] CP4LNK .ASM 8BE0 8K ver. 4.05 [Kermit 40 of 50] CP4MIT .ASM 4027 29K ver. 4.05 [Kermit 41 of 50] CP4TT .ASM ABF8 23K ver. 4.05 [Kermit 42 of 50] CP4TYP .ASM 9E80 9K ver. 4.05 [Kermit 43 of 50] CP4UTL .ASM 3C3C 30K ver. 4.05 [Kermit 44 of 50] CP4WLD .ASM 290F 4K ver. 4.05 [Kermit 45 of 50] LASM .COM BE32 6K ver. 4.05 [Kermit 46 of 50] (Linking Assembler) Is like ASM but handles chaining multiple files together in one assembly. LASM .DOC E0E9 5K ver. 4.05 [Kermit 47 of 50] (Linking Assembler) documentation. MLOAD .COM 6D48 3K ver. 4.05 [Kermit 48 of 50] MLOAD24 so you have all needed pieces together. Full documentation of FOG-CPM.122 ion of the disk contents. CP4KER .ASM 1DF6 4K ver. 4.05 [Kermit 36 of 50] CP4CMD .ASM 09B0 23K ver. 4.05 [Kermit 37 of 50] CP4CPM .ASM C763 7K ver. 4.05 [Kermit 38 of 50] CP4DEF .ASM C0D0 8K ver. 4.05 [Kermit 39 of 50] CP4LNK .ASM 8BE0 8K ver. 4.05 [Kermit 40 of 50] CP4MIT .ASM 4027 29K ver. 4.05 [Kermit 41 of 50] CP4TT .ASM ABF8 23K ver. 4.05 [Kermit 42 of 50] CP4TYP .ASM 9E80 9K ver. 4.05 [Kermit 43 of 50] CP4UTL .ASM 3C3C 30K ver. 4.05 [Kermit 44 of 50] CP4WLD .ASM 290F 4K ver. 4.05 [Kermit 45 of 50] LASM .COM BE32 6K ver. 4.05 [Kermit 46 of 50] (Linking Assembler) Is like ASM but handles chaining multiple files together in one assembly. LASM .DOC E0E9 5K ver. 4.05 [Kermit 47 of 50] (Linking Assembler) documentation. MLOAD .COM 6D48 3K ver. 4.05 [Kermit 48 of 50] MLOAD24 so you have all needed pieces together. Full documentatio; CP4CMD.ASM ; KERMIT - (Celtic for "FREE") ; ; This is the CP/M-80 implementation of the Columbia University ; KERMIT file transfer protocol. ; ; Version 4.0 ; ; Copyright June 1981,1982,1983,1984,1985 ; Columbia University ; ; Originally written by Bill Catchings of the Columbia University Center for ; Computing Activities, 612 W. 115th St., New York, NY 10025. ; ; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben, ; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many ; others. ; ; This file provides a user oriented way of parsing commands. ; It is similar to that of the COMND JSYS in TOPS-20. ; ; revision history (latest first): ; edit 5: 6-Feb-85 by Charles Carvalho ; Make ffussy a runtime (rather than assembly-time) switch, to ; eliminate conditional assembly in system-independent module. ; Don't allow _%|()/\ in filenames if ffussy set; my CP/M manual ; disallows those, too. ; ; edit 4: 13-Jan-85 by Vanya J.Cooper Pima Commun. College Tel: 602-884-6809 ; ;pcc006 2-jan-85 VJC modules:cp4cmd,cp4utl ; Problems with "?" in filespecs. On reparse, may cause action ; flag to be reset at wrong point, requiring multiple 's ; to terminate the line or other weird stuff. Also need to ; check flag and complain if wild-cards illegal. ;pcc007 2-Jan-85 vjc modules:cp4def,cp4cmd ; Cmifil is too fussy about what characters to accept in a ; filespec. My CP/M manual says any printable character is ok ; except <>.,;:?*[], and lower case. In practice, even those work ; sometimes. Kermit itself uses '&' if file warning is on, ; and then won't let you reference the file. Allow all ; printable characters except those above. Add conditional ; ffussy, so that if not ffussy, all special characters will be ; allowed, just convert lower to upper-case. ; edit 3: July 8, 1984 (CJC) ; integrate Toad Hall changes for LASM compatibility: CP4CPM is linked ; by CP4WLD, and links CP4UTL. ; ; edit 2: June 5, 1984 (CJC) ; formatting and documentation; delete unnecessary code at cminb7; add ; module version string. ; ; edit 1: May, 1984 (CJC) ; extracted from CPMBASE.M80 version 3.9; modifications are described in ; the accompanying .UPD file. cmdver: db 'CP4CMD.ASM (5) 6-Feb-85$' ; name, edit number, date ; This routine prints the prompt in DE and specifies the reparse ; address. ; called by: kermit prompt: pop h ;Get the return address. push h ;Put it on the stack again. shld cmrprs ;Save it as the address to go to on reparse. lxi h,0 ;Clear out hl pair. dad sp ;Get the present stack pointer. shld cmostp ;Save for later restoral. xchg ;Save the pointer to the prompt. shld cmprmp xchg lxi h,cmdbuf shld cmcptr ;Initialize the command pointer. shld cmdptr xra a sta cmaflg ;Zero the flags. sta cmccnt mvi a,0FFH ;Try it this way (Daphne.) sta cmsflg call prcrlf ;Print a CR/LF [Toad Hall] jmp prprmp ;Print the prompt. [Toad Hall] ; ; This address is jumped to on reparse. ; here from: cmcfrm, cmkeyw, cmifil, cminbf repars: lhld cmostp ;Get the old stack pointer. sphl ;Make it the present one. lxi h,cmdbuf shld cmdptr mvi a,0FFH ;Try it this way (Daphne.) sta cmsflg lhld cmrprs ;Get the reparse address. pchl ;Go there. ; This address can be jumped to on a parsing error. ; here from: cmkeyw, cminbf prserr: lhld cmostp ;Get the old stack pointer. sphl ;Make it the present one. lxi h,cmdbuf shld cmcptr ;Initialize the command pointer. shld cmdptr xra a sta cmaflg ;Zero the flags. sta cmccnt mvi a,0FFH ;Try it this way (Daphne.) sta cmsflg call prcrlf ;Print a CR/LF [Toad Hall] call prprmp ;Print the prompt [Toad Hall] ;* Instead return to before the prompt call. lhld cmrprs pchl ; ; This routine parses the specified function in A. Any additional ; information is in DE and HL. ; Returns +1 on success ; +4 on failure (assumes a JMP follows the call) ; called by: log, setcom, read, send, xmit, dir, era, keycmd, cfmcmd  comnd: sta cmstat ;Save what we are presently parsing. call cminbf ;Get chars until an action or a erase char. cpi cmcfm ;Parse a confirm? jz cmcfrm ;Go get one. cpi cmkey ;Parse a keyword? jz cmkeyw ;Try and get one. cpi cmifi ;Parse an input file spec? jz cmifil ;Go get one. cpi cmifin ;Input file-spec silent? jz cmifil ;do as he wishes cpi cmofi ;Output file spec? jz cmofil ;Go get one. cpi cmtxt ;Parse arbitrary text? jz cmtext ;Go do it. lxi d,cmer00 ;"?Unrecognized COMND call" call prtstr ret ; ; This routine parses arbitrary text up to a CR. ; Accepts DE: address to put text ; Returns in A: number of chars in text (may be 0) ; DE: updated pointer ; called by: comnd cmtext: xchg ;Put the pointer to the dest in HL. shld cmptab ;Save the pointer. mvi b,0 ;Init the char count cmtxt1: call cmgtch ;Get a char. ora a ;Terminator? jp cmtxt5 ;No, put in user space. ani 7FH ;Turn off minus bit. cpi esc ;An escape? jnz cmtxt2 ;No. mvi c,conout mvi e,bell ;Get a bell. call bdos xra a sta cmaflg ;Turn off the action flag. lhld cmcptr ;Move the pointer to before the escape. dcx h shld cmcptr shld cmdptr lxi h,cmccnt ;Get the char count. dcr m ;Decrement it by one. jmp cmtxt1 ;Try again. cmtxt2: cpi '?' ;Is it a question mark? jz cmtxt3 ;If so put it in the text. cpi ff ;Is it a formfeed? cz clrtop ;If so blank the screen. mov a,b ;Return the count. lhld cmptab ;Return updated pointer in HL. xchg jmp rskp ;Return success. cmtxt3: lxi h,cmaflg ;Point to the action flag. mvi m,0 ;Set it to zero. cmtxt5: inr b ;Increment the count. lhld cmptab ;Get the pointer. mov m,a ;Put the char in the array. inx h shld cmptab ;Save the updated pointer. jmp cmtxt1 ;Get another char. ; ; This routine gets a confirm. ; called by: comnd cmcfrm: call cmgtch ;Get a char. ora a ;Is it negative (a terminator;a space or ;a tab will not be returned here as they ;will be seen as leading white space.) rp ;If not, return failure. ani 7FH ;Turn off the minus bit. cpi esc ;Is it an escape? jnz cmcfr2 mvi c,conout mvi e,bell ;Get a bell. call bdos xra a sta cmaflg ;Turn off the action flag. lhld cmcptr ;Move the pointer to before the escape. dcx h shld cmcptr shld cmdptr lxi h,cmccnt ;Get the char count. dcr m ;Decrement it by one. jmp cmcfrm ;Try again. cmcfr2: cpi '?' ;Curious? jnz cmcfr3 lxi d,cmin00 ;Print something useful. call prtstr call prcrlf ;Print a crlf. [Toad Hall] call prprmp ;Reprint the prompt [Toad Hall] lhld cmdptr ;Get the pointer into the buffer. mvi a,'$' ;Put a $ there for printing. mov m,a lhld cmcptr dcx h ;Decrement and save the buffer pointer. shld cmcptr lxi d,cmdbuf call prtstr xra a ;Turn off the action flag. sta cmaflg jmp repars ;Reparse everything. cmcfr3: cpi ff ;Is it a form feed? cz clrtop ;If so blank the screen. jmp rskp ; ; 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 # of entries in the table. ; db m ;M is the size of the keyword. ; db 'string$' ;Where string is the keyword. ; db a,b ;Where a & b are pieces of data ; ;to be returned. (Must be two of them.) ; ; 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. ; called by: comnd cmkeyw: shld cmhlp ;Save the help. xchg ;Get the address of the table. shld cmptab ;Save the beginning of keyword tab for '?'. mov b,m ;Get the number of entries in the table. inx h shld cmkptr lhld cmdptr ;Save the command pointer. shld cmsptr cmkey2: mov a,b ;Get the number of entries left. ora a ;Any left? rz ;If not we failed. lhld cmkptr mov e,m ;Get the length of the keyword. inx h cmkey3: dcr e ;Decrement the number of chars left. mov a,e cpi 0FFH ;Have we passed the end? jm cmkey5 ;If so go to the next. call cmgtch ;Get a char. ora a ;Is it a terminator? jp cmkey4 ;If positive, it is not. ani 7FH ;Turn off the minus bit. cpi '?' jnz cmky31 xra a sta cmaflg ;Turn off the action flag. lxi h,cmccnt ;Decrement the char count. dcr m ;* Must go through the keyword table and print them. lhld cmhlp ;For now print the help text. xchg call prtstr call prcrlf ;Print a crlf [Toad Hall] call prprmp ;Reprint the prompt [Toad Hall] lhld cmdptr ;Get the pointer into the buffer. mvi a,'$' ;Put a $ there for printing. mov m,a lhld cmcptr dcx h ;Decrement and save the buffer pointer. shld cmcptr lxi d,cmdbuf call prtstr jmp repars ;Reparse everything. cmky31: cpi esc ;Is it an escape? jnz cmky35 xra a sta cmaflg ;Turn off the action flag. push d push b push h call cmambg jmp cmky32 ;Not ambiguous. mvi c,conout mvi e,bell call bdos ;Ring the bell. lhld cmcptr ;Move the pointer to before the escape. dcx h shld cmcptr shld cmdptr lxi h,cmccnt ;Get the char count. dcr m ;Decrement it by one. pop h pop b pop d inr e ;Increment the left to parse char count. jmp cmkey3 cmky32: lhld cmcptr ;Pointer into buffer. dcx h ;Backup to the escape. xchg pop h push h cmky33: mov a,m ;Get the next char. cpi '$' ;Finished? jz cmky34 inx h xchg mov m,a ;Move it into the buffer. inx h xchg lda cmccnt ;Increment the char count. inr a sta cmccnt jmp cmky33 cmky34: lda cmccnt ;Get the character count. inr a ;Increment and save it. sta cmccnt xchg ;Put the command buffer pointer in HL. mvi a,' ' ;Get a blank. mov m,a ;Put it in the command buffer. inx h ;Increment the pointer shld cmcptr ;Save the updated pointer. shld cmdptr pop h push h xchg call prtstr ;Print the rest of the keyword. mvi c,conout mvi e,' ' call bdos ;Print a blank. pop h pop b pop d jmp cmky37 cmky35: push h push d call cmambg jmp cmky36 lxi d,cmer01 call prtstr ;Say its ambiguous. jmp prserr ;Give up. cmky36: pop d pop h cmky37: inr e ;Add one incase it is negative. mvi d,0 dad d ;Increment past the keyword. inx h ;Past the $. mov e,m ;Get the data. inx h mov d,m mov a,e jmp rskp cmkey4: cpi 'a' ;Is it less than a? jm cmky41 ;If so don't capitalize it. cpi 'z'+1 ;Is it more than z? jp cmky41 ;If so don't capitalize it. ani 137O ;Capitalize it. cmky41: mov d,m ;Get the next char of the keyword. inx h cmp d ;Match? jz cmkey3 ;If so get the next letter. cmkey5: mvi d,0 mov a,e ;Get the number of chars left. ora a ;Is it negative? jp cmky51 mvi d,0FFH ;If so, sign extend. cmky51: dad d ;Increment past the keyword. lxi d,0003H ;Plus the $ and data. dad d shld cmkptr dcr b ;Decrement the number of entries left. lhld cmsptr ;Get the old cmdptr. shld cmdptr ;Restore it. ;* check so we don't pass it. jmp cmkey2 ;Go check the next keyword. ; ; Test keyword for ambiguity. ; returns: nonskip if ambiguous, skip if OK. ; called by: cmkeyw cmambg: dcr b ;Decrement the number of entries left. rm ;If none left then it is not ambiguous. inr e ;This is off by one;adjust. mov c,e ;Save the char count. mov a,e ora a ;Any chars left? rz ;No, it can't be ambiguous. mvi d,0 dad d ;Increment past the keyword. mvi e,3 ;Plus the $ and data. dad d mov b,m ;Get the length of the keyword. inx h xchg lhld cmkptr ;Get pointer to keyword entry. mov a,m ;Get the length of the keyword. sub c ;Subtract how many left. mov c,a ;Save the count. cmp b jz cmamb0 rp ;If larger than the new word then not amb. cmamb0: lhld cmsptr ;Get the pointer to what parsed. cmamb1: dcr c ;Decrement the count. jm rskp ;If we are done then it is ambiguous. xchg ;Exchange the pointers. mov b,m ;Get the next char of the keyword inx h xchg ;Exchange the pointers. mov a,m ;Get the next parsed char. inx h cpi 'a' ;Is it less than a? jm cmamb2 ;If so don't capitalize it. cpi 'z'+1 ;Is it more than z? jp cmamb2 ;If so don't capitalize it. ani 137O cmamb2: cmp b ;Are they equal? rnz ;If not then its not ambiguous. jmp cmamb1 ;Check the next char. ; ; cmofil - parse output filespec ; cmifil - parse input filespec ; here from: comnd cmofil: mvi a,0 ;Don't allow wildcards. ; jmp cmifil ;For now, the same as CMIFI. cmifil: sta cmfwld ;Set wildcard flag xchg ;Get the fcb address. shld cmfcb ;Save it. mvi e,0 ;Initialize char count. mvi m,0 ;Set the drive to default to current. inx h shld cmfcb2 xra a ;Initialize counter. cmifi0: mvi m,' ' ;Blank the FCB. inx h inr a cpi 0CH ;Twelve? jm cmifi0 cmifi1: call cmgtch ;Get another char. ora a ;Is it an action character? jp cmifi2 ani 7FH ;Turn off the action bit. cpi '?' ;A question mark? jnz cmif12 lda cmfwld ;[pcc006] Wildcards allowed? ora a ;[pcc006] jz cmif11 ;[pcc006] complain if not lhld cmdptr ;[jd] Increment buffer pointer inx h ;[jd] that was decremented in cmgtch shld cmdptr ;[jd] since we want this chr lda cmcptr ;[pcc006] get lsb of real input pointer cmp l ;[pcc006] is this the last chr input? jnz cmif1a ;[pcc006] no, don't reset action flag xra a ;[pcc006] yes, reset action flag sta cmaflg ;[pcc006] cmif1a: mvi a,'?' ;[pcc006] get it back in A jmp cmifi8 ;Treat like any other character cmif12: cpi esc ;An escape? jnz cmif13 ;Try to recognize file-spec a'la TOPS-20 xra a sta cmaflg ;Turn off the action flag. lhld cmcptr ;Move the pointer to before the escape. dcx h shld cmcptr shld cmdptr lxi h,cmccnt ;Get the char count. dcr m ;Decrement it by one. mov a,e ;Save character count up to now. sta temp1 cpi 9 ;Past '.'? jm cmfrec ;No. dcr a ;Yes, don't count point. cmfrec: lhld cmfcb2 ;Fill the rest with CP/M wildcards. cmfrc1: cpi 11 ;Done? jp cmfrc2 ;Yes. mvi m,'?' inx h inr a jmp cmfrc1 cmfrc2: mvi c,sfirst ;Find first matching file? lhld cmfcb xchg call bdos cpi 0FFH jz cmfrc9 ;No, lose. lxi h,fcbblk ;Copy first file spec. call fspcop lxi h,fcbblk+10H ;Get another copy (in case not ambiguous). call fspcop mvi c,snext ;More matching specs? lhld cmfcb xchg call bdos cpi 0FFH jz cmfrc3 ;Only one. lxi h,fcbblk+10H ;Copy second file spec. call fspcop cmfrc3: lxi d,fcbblk ;Start comparing file names. lxi h,fcbblk+10H lda temp1 ;Bypass characters typed. cpi 9 ;Past '.'? jm cmfrc4 ;No. dcr a ;Yes, don't count point. cmfrc4: mvi c,0 cmfrl1: cmp c ;Bypassed? jz cmfrl2 ;Yes. inx d inx h inr c jmp cmfrl1 ;Repeat. cmfrl2: mov a,c ;Get file name characters processed. cpi 11 ;All done? jz cmfrc5 ;Yes. cpi 8 ;End of file name? jnz cmfrl3 ;No. lda temp1 ;Exactly at point? cpi 9 jz cmfrl3 ;Yes, don't output a second point. mvi a,'.' ;Output separator. call cmfput cmfrl3: ldax d ;Get a character from first file spec. inx d mov b,m ;Get from second file spec. inx h cmp b ;Compare. jnz cmfrc5 ;Ambiguous. inr c ;Same, count. cpi ' ' ;Blank? jz cmfrl2 ;Yes, don't output. call cmfput ;Put character into buffer. jmp cmfrl2 ;Repeat. cmfrc5: mov a,c ;Get count of characters processed. sta temp1 ;Save it. mvi a,'$' ;Get terminator. call cmfput ;Put it into buffer. lhld cmdptr ;Output recognized characters. xchg mvi c,prstr call bdos lhld cmcptr ;Remove terminator from buffer. dcx h shld cmcptr lxi h,cmccnt dcr m lda temp1 ;Characters processed. cpi 11 ;Complete file name. jz repars ;Yes, don't beep. cmfrc9: mvi c,conout mvi e,bell call bdos ;Ring the bell. jmp repars ; ; Continue file spec parsing. cmif13: mov a,e ;It must be a terminator. ora a ;Test the length of the file name. jz cmifi9 ;If zero complain. cpi 0DH jp cmifi9 ;If too long complain. jmp rskp ;Otherwise we have succeeded. cmifi2: cpi '.' jnz cmifi3 inr e mov a,e cpi 1H ;Any chars yet? jz cmifi9 ;No, give error. cpi 0AH ;Tenth char? jp cmifi9 ;Past it, give an error. mvi c,9H mvi b,0 lhld cmfcb dad b ;Point to file type field. shld cmfcb2 mvi e,9H ;Say we've gotten nine. jmp cmifi1 ;Get the next char. cmifi3: cpi ':' jnz cmifi4 inr e mov a,e cpi 2H ;Is it in the right place for a drive? jnz cmifi9 ;If not, complain. lhld cmfcb2 dcx h ;Point to previous character. mov a,m ;Get the drive name. sui '@' ;Get the drive number. shld cmfcb2 ;Save pointer to beginning of name field. dcx h ;Point to drive number. mov m,a ;Put it in the fcb. mvi e,0 ;Start character count over. jmp cmifi1 cmifi4: cpi '*' jnz cmifi7 lda cmfwld ;Wildcards allowed? cpi 0 jz cmif11 ;No,complain mov a,e cpi 8H ;Is this in the name or type field? jz cmifi9 ;If its where the dot should be give up. jp cmifi5 ;Type. mvi b,8H ;Eight chars. jmp cmifi6 cmifi5: mvi b,0CH ;Three chars. cmifi6: lhld cmfcb2 ;Get a pointer into the FCB. mvi a,'?' mov m,a ;Put a question mark in. inx h shld cmfcb2 inr e mov a,e cmp b jm cmifi6 ;Go fill in another. jmp cmifi1 ;Get the next char. cmifi7: cpi '!' ;[pcc007] control chr or space? jm cmifi9 ;[pcc007] yes, illegal mov h,a ;[5] stash input char for a bit lda ffussy ;[5] while we check the fussy flag ora a ;[5] set the flags accordingly mov a,h ;[5] restore the input character jz cmif7a ;[5] if ffussy=0, allow <>.,;:?*[] ;[5] So far, we've eliminated "action characters" (including question), ;[5] period, colon, asterisk, control characters, and space. ;[5] That leaves us %(),/;<=>[\]_| to check for. cpi '%' ;[5] jz cmifi9 ;[5] cpi '(' ;[5] jz cmifi9 ;[5] cpi ')' ;[5] jz cmifi9 ;[5] cpi ',' ;[pcc007] weed out comma jz cmifi9 ;[pcc007] cpi '/' ;[5] jz cmifi9 ;[5] cpi '9'+1 ;[pcc007] anything else 21H-39H is ok jm cmifi8 ;[pcc007] except '*' never gets here cpi '@' ;[pcc007] all of 3AH-3FH is illegal jm cmifi9 ;[pcc007] cpi '[' ;[pcc007] [\] also illegal jm cmifi8 ;[pcc007] cpi ']'+1 ;[pcc007] jm cmifi9 ;[pcc007] cpi '_' ;[5] jz cmifi9 ;[5] (If I was doing CP/M, I would have cpi '|' ;[5] just eliminated all them funny chars jz cmifi9 ;[5] instead of a random selection) cmif7a: ;[5] cpi 'a' ;[pcc007] if not lower case its ok jm cmifi8 ;[pcc007] (DEL never gets here) cpi 'z'+1 ;[pcc007] only convert letters jp cmifi8 ;[pcc007] ani 137O ;Capitalize. cmifi8: lhld cmfcb2 ;Get the pointer into the FCB. mov m,a ;Put the char there. inx h shld cmfcb2 inr e jmp cmifi1 cmifi9: lda cmstat cpi cmifin ;"silent"? jz r ;Yes,let him go w/o check lxi d,cmer02 cmif10: mvi c,prstr call bdos ret cmif11: lxi d,cmer03 ;Complain about wildcards. jmp cmif10 ; ; copy filename from buffer ; called with HL = destination, A = position (0-3) in buffer ; called by: cmifil fspcop: push psw ;Save A. lxi d,buff ;Get the right offset in the buffer. rlc rlc rlc rlc rlc add e inr a ;Bypass drive spec. mov e,a mvi b,11 ;Copy file name. fspcp1: ldax d inx d mov m,a inx h dcr b jnz fspcp1 pop psw ;Restore A. ret ; append character in A to command buffer ; called by: cmifil cmfput: push h ;Save H. lhld cmcptr ;Get buffer pointer. mov m,a ;Store in buffer. inx h shld cmcptr lxi h,cmccnt ;Count it. inr m pop h ;Restore H. ret ; ; Read characters from the command buffer. ; called by: cmtext, cmcfrm, cmkeyw, cmifil cmgtch: push h push b cmgtc1: lda cmaflg ora a ;Is it set. cz cminbf ;If the action char flag is not set get more. lhld cmdptr ;Get a pointer into the buffer. mov a,m ;Get the next char. inx h shld cmdptr cpi ' ' ;Is it a space? jz cmgtc2 cpi tab ;Or a tab? jnz cmgtc3 cmgtc2: lda cmsflg  ;Get the space flag. ora a ;Was the last char a space? jnz cmgtc1 ;Yes, get another char. mvi a,0FFH ;Set the space flag. sta cmsflg mvi a,' ' pop b pop h jmp cmgtc5 cmgtc3: push psw xra a sta cmsflg ;Zero the space flag. pop psw pop b pop h cpi esc jz cmgtc5 cpi '?' ;Is the user curious? jz cmgtc4 cpi cr jz cmgtc4 cpi lf jz cmgtc4 cpi ff rnz ;Not an action char, just return. cmgtc4: push h lhld cmdptr dcx h shld cmdptr pop h cmgtc5: ori 80H ;Make the char negative to indicate it is ret ;a terminator. ; ; Read characters from console into command buffer, processing ; editing characters (^H, ^M, ^J, ^L, ^U, ^X, ?, del). ; called by: comnd, cmgtch cminbf: push psw push d push h lda cmaflg ;Is the action char flag set? ora a jnz cminb9 ;If so get no more chars. cminb1: lxi h,cmccnt ;Increment the char count. inr m mvi c,conin ;Get a char. call bdos lhld cmcptr ;Get the pointer into the buffer. mov m,a ;Put it in the buffer. inx h shld cmcptr cpi 25O ;Is it a ^U? jz cmnb12 ;Yes. cpi 30O ;Is it a ^X? jnz cminb2 cmnb12: call clrlin ;Clear the line. call prprmp ;Print the prompt [Toad Hall] lxi h,cmdbuf shld cmcptr ;Reset the point to the start. lxi h,cmccnt ;Zero the count. mvi m,0 jmp repars ;Go start over. cminb2: cpi 10O ;Backspace? jz cminb3 cpi del ;or Delete? jnz cminb4 call delchr ;Print the delete string. cminb3: lda cmccnt ;Decrement the char count by two. dcr a dcr a ora a ;Have we gone too far? jp cmnb32 ;If not proceed. mvi c,conout ;Ring the bell. mvi e,bell call bdos jmp cmnb12 ;Go reprint prompt and reparse. cmnb32: sta cmccnt ;Save the new char count. call clrspc ;Erase the character. lhld cmcptr ;Get the pointer into the buffer. dcx h ;Back up in the buffer. dcx h shld cmcptr jmp repars ;Go reparse everything. cminb4: cpi '?' ;Is it a question mark. jz cminb6 cpi esc ;Is it an escape? jz cminb6 cpi cr ;Is it a carriage return? jz cminb5 cpi lf ;Is it a line feed? jz cminb5 cpi ff ;Is it a formfeed? jnz cminb1 ;no - just store it and get another character. call clrtop cminb5: lda cmccnt ;Have we parsed any chars yet? cpi 1 jz prserr ;If not, just start over. cminb6: mvi a,0FFH ;Set the action flag. sta cmaflg jmp cminb9 cminb9: pop h pop d pop psw ret ; ;Little utility to print the prompt. (We do a LOT of these.) [Toad Hall] ;Enters with nothing. ;Destroys HL (and I suppose B and DE and A). prprmp: lhld cmprmp ;Get the prompt. xchg call prtstr ret IF lasm LINK CP4UTL ENDIF ;lasm [Toad Hall] character. lhld cmcptr ;Get the pointer into the buffer. dcx h ;Back up in the buffer. dcx h shld cmcptr jmp repars ;Go reparse everything. cminb4: cpi '?' ;Is it a question mark. jz cminb6 cpi esc ;Is it an escape? jz cminb6 cpi  ; CP4CPM.ASM ; KERMIT - (Celtic for "FREE") ; ; This is the CP/M-80 implementation of the Columbia University ; KERMIT file transfer protocol. ; ; Version 4.0 ; ; Copyright June 1981,1982,1983,1984 ; Columbia University ; ; Originally written by Bill Catchings of the Columbia University Center for ; Computing Activities, 612 W. 115th St., New York, NY 10025. ; ; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben, ; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many ; others. ; ; This file duplicates the CP/M DIR and ERA functions so we don't have ; to exit. ; ; revision history: ; edit 3: July 8, 1984 (CJC) ; Merge modifications from Toad Hall: support LASM (linked by CP4TT, ; links to CP4WLD), use prcrlf where appropriate. ; ; edit 2: June 5, 1984 (CJC) ; documentation and formatting; delete unused code (dir13); add module ; version string. ; ; edit 1: May, 1984 (CJC) ; extracted from CPMBASE.M80 version 3.9; modifications are described in ; the accompanying .UPD file. ; cpmver: db 'CP4CPM.ASM (3) 8-Jul-84$' ; name, edit number, date npl EQU 04H ;Number of names per line for dir command. ; This is the DIR command. Display the name and size of all files ; matching the filespec. ; here from: kermit ; ; Note: This is abstracted from Keith Peterson's DIRF.ASM ; directory print function. Thanks again Keith. ; ; dir: lxi d,fcb ;Where to put the data, if any. mvi a,cmifin call comnd ;Parse a full or piece of file-spec jmp dir2 ;Didn't get a FULL file-spec jmp dir4 ;lets do it ; ; ;Make FCB all '?' to match any file dir2: lda fcb cpi ' ' ;CMIFIN leaves that as ' ' jnz dir2a ;he typed at least x: xra a sta fcb ;default drive dir2a: lxi h,fcb+1 mvi b,11 ;FN+FT count. dir3: mvi m,'?' ;Store '?'s in FCB. inx h dcr b jnz dir3 ;Print signon message and drive name dir4: lda fcb ora a ;if not zero, get default jnz dir4a lda curdsk ;get default dir4a: adi 'A'-1 ;Asciize it sta dnam14 ;Save it in message. call prcrlf lxi d,inms14 ;Point to message call prtstr ; ;Initialize number of names per line counter mvi a,npl ;Nr. names per line. sta nnams ;Init counter. ; call dir26 ;Get disk parameters dir5: call mfname ;get some names jnc dir6 ;got one jmp dir17 ;got none - do summary dir6: ;Check for console break mvi c,consta ;Ck status of kbd. call bdos ora a ;Any key pressed? jz dir6a ;nope, keep going mvi c,conin call bdos ;gobble key jmp dir17 ;and print summary only ;Print an entry dir6a: lxi h,fcb+1 ;point to Filename mvi b,8 ;File name length. call dir11 ;Type filename. mvi a,'.' ;Period after FN. call dir10 mvi b,3 ;Get the filetype. call dir11 call dir25 ;print size lxi h,nnams ;Point to names counter. dcr m ;One less on this line. push psw cnz dir7 ;No cr-lf needed, do fence. pop psw cz dir12 ;Cr-lf needed. jmp dir5 ;Print space, fence character, then space dir7: call dir9 mvi a,':' ;Fence character. call dir10 jmp dir9 ; dir8 - Print two spaces ; dir9 - Print one space ; dir10 - Type char in A register dir8: call dir9 dir9: mvi a,' ' dir10: push b push d push h mov e,a ;Char to E for CP/M. mvi c,conout ;Write char to console function. call bdos pop h pop d pop b ret ;Type (B) characters from memory (HL) dir11: mov a,m ani 7FH ;Remove CP/M 2.x attributes. call dir10 inx h dcr b jnz dir11 ret ;CR-LF routine. HL=NNAMS upon entry dir12: push b push d push h call prcrlf ;Print CR/LF [Toad Hall] pop h ;(did use call to dir10, but slooow) pop d pop b mvi m,npl ;Number of names per line. ret ;Exit - All done, return via jmp (as for all main commands) dir16: call prcrlf lda curdsk dcr a ;relative to 0 mov e,a mvi c,logdsk call bdos ;back to "logged in" disk jmp kermit ;...and return to kermit. ; ;Determines free space remaining ; dir17: xra a sta mfflg1 ;clean up MFNAME sta mfflg2 lda fcb ; get drive number from FCB ora a jz dir18 ; default? dcr a ; no, make requested drive current drive. mov e,a mvi c,logdsk call bdos dir18: call sysspc ; get space available for current drive push h lxi d,inms15 ;"Drive " call prtstr lda fcb ;If no drive, get ora a ;logged in drive jnz dir24 mvi c,rddrv call bdos inr a dir24: adi 'A'-1 sta inms16 lxi d,inms16 ;"x has " call prtstr pop h ;Get number of bytes available call nout lxi d,inms17 ;"K bytes free" call prtstr jmp dir16 ;all done ;Compute the size of the file dir25: mvi c,cflsz ;get file-size lxi d,fcb call bdos lda fcbrno ;shift least sign. part lxi b,0 ;init bc mov l,a ani 7 jz dir250 ;even K lxi b,1 ;save for later dir250: push b ;save 0 or 1 to add to size mvi b,3 ;shift 3 bits dir25a: xra a ;clear sign lda fcbrno+1 ;get most sig byte rar ;shift right sta fcbrno+1 ;put back lda fcbrno ;get least sig part rar sta fcbrno dcr b ;loop 3 times jn z dir25a mov l,a ;size in HL lda fcbrno+1 mov h,a pop b ;get 0 or 1 dad b ;round up to KB used lda bmask ;get (sectors/block)-1 rrc rrc ;get (K/block)-1 rrc ani 1FH mov c,a dad b ;add (K/block)-1 to size to round up cma ;make a mask ana l ;truncate after rounding up mov l,a push h lxi b,-10 ;subtract 10 dad b jc dir25d ;>= 10 call dir8 ; print a leading space jmp dir25e dir25d: pop h ;get size again push h lxi b,-100 ;subtract 100 dad b jc dir25e ;>= 100 call dir9 ; print another leading space dir25e: call dir9 ;a space pop h ;get size back call nout ;..go print it mvi a,'k' ;..and follow with K size call dir10 ret dir26: mvi c,gtdpar ;current DISK PARAMETER BLOCK call bdos inx h inx h mov a,m ;Get Block Shift Factor sta bshiftf inx h ;Bump to Block Mask mov a,m ;get it sta bmask inx h inx h mov e,m ;Get Max Block number inx h mov d,m xchg shld bmax ;Put it away ret ; ; ERA command - erase a CP/M file ; here from: kermit era: mvi a,cmifi ;Parse a file-spec lxi d,fcb ;into FCB call comnd jmp kermit ;bad parse lxi d,fcb mvi c,sfirst ;check if valid call bdos inr a ;0 if FILE not found jnz era1 ;found at least one lxi d,erms15 ;"unable to find file" call prtstr jmp kermit era1: lxi d,fcb mvi c,delf call bdos lxi d,inms18 ;" File(s) erased" call prtstr jmp kermit IF lasm LINK CP4WLD ENDIF;lasm [Toad Hall] dir25e ;>= 100 call dir9 ; print another leading space dir25e: call dir9 ;a space pop h ;get size back call nout ;..go print it mvi a,'k' ;..and follow with K size call dir10 ret dir26: mvi c,gtdpar ;current DISK PARAMETER BLOCK call bdos inx h inx h mov a,m ;Get Block Shift Factor sta bshiftf inx h ;Bump to Block Mask mov a,m ;get it sta bmask inx h inx h mov e,m ;Get Max Block number inx h mov d,m xchg shld bmax ;Put it away ret ; ; ERA comman; CP4DEF.ASM ; KERMIT - (Celtic for "FREE") ; ; This is the CP/M-80 implementation of the Columbia University ; KERMIT file transfer protocol. ; ; Version 4.0 ; ; Copyright June 1981,1982,1983,1984,1985 ; Columbia University ; ; Originally written by Bill Catchings of the Columbia University Center for ; Computing Activities, 612 W. 115th St., New York, NY 10025. ; ; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben, ; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many ; others. ; ; This file contains definitions used by both modules of Kermit. ; ; revision history: ; edit 4: 6-Feb-85 by Charles Carvalho ; modify pcc007: replace ffussy assembly switch with runtime test. ; add "getvnm" - get CP/M version number. ; ; edit 3: 13-Jan-85 by Vanya J.Cooper Pima Commun. College Tel: 602-884-6809 ; ;pcc007 2-Jan-85 vjc modules:cp4def,cp4cmd ; Cmifil is too fussy about what characters to accept in a ; filespec. My CP/M manual says any printable character is ok ; except <>.,;:?*[], and lower case. In practice, even those work ; sometimes. Kermit itself uses '&' if file warning is on, ; and then won't let you reference the file. Allow all ; printable characters except those above. Add conditional ; ffussy, so that if not ffussy, all special characters will be ; allowed, just convert lower to upper-case. ; ;pcc008 2-Jan-85 vjc modules:cp4def,cp4tt,cp4utl ; Keyboard input during CONNECT mode can get locked out if ; there is enough input from the modem port to keep prtchr ; busy. This can happen for example, if the printer is running ; at the same speed as the modem line, leaving you helpless to ; turn it off or abort the host. Add a fairness count, so that ; at least every prfair characters we look at console input. ; ; edit 2: July 10, 1984 (CJC) ; Remove defines for TRUE and FALSE, during reorganization for LASM ; compatibility. If we're using LASM, this file is linked by CP4KER ; or CP4TYP, and links to CP4MIT or CP4LNK. Also, push comments around ; a little. ; ; edit 1: May, 1984 (CJC) ; extracted from CPMBASE.M80 version 3.9; modifications are described ; in the accompanying .UPD file. ; ;Symbolic Definitions for some ASCII characters ; soh EQU 01O ;ASCII SOH (Control-A) ctrlc EQU 03O ;ASCII ETX (Control-C) bell EQU 07O ;ASCII BEL (Control-G) bs EQU 10O ;ASCII backspace (Control-H) 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 ;ASCII XON (Control-Q) xoff EQU 23O ;ASCII XOFF (Control-S) esc EQU 33O ;ASCII ESCape subt EQU 32O ;ASCII SUB (CTRL-Z) del EQU 177O ;ASCII DELete (rubout) ; ;BDOS calls bdos EQU 0005H ;BDOS entry point, for the following functions: ; ;Function Name Function Input Parameters Output Parameter ;============= ======== ================ ================ ; (ALL Function Numbers are passed in Register C) conin EQU 01H ;Read Console NONE ASCII Char in A conout EQU 02H  ;Write Console ASCII Char in E NONE auxin EQU 03H ;Auxiliary input rdrin EQU 03H ;Read Reader NONE ASCII Char in A lstout EQU 05H ;Write List ASCII Char in E NONE dconio EQU 06H ;Direct Con I/O ASCII Char in E I/O Status in A ; if E=0FEH, ; Input if E=0FFH prstr EQU 09H ;Print String String-Address NONE ; in DE (term=$) rdstr EQU 0AH ;Read Buffer Buffer-Address Read Buffer filled ; in DE ; Read Buffer Byte Function ; 1 Maximum Buffer Length ; 2 Current Buffer Length (returned value) ; 3-n Data (returned values) ; consta EQU 0BH ;Console Stat NONE LSB(A)=1 if char ready getvnm EQU 0CH ;Version Number NONE H=0 (CP/M), L=BDOS ver inbdos EQU 0DH ;Init BDOS NONE NONE logdsk EQU 0EH ;LOG-In disk Value in E NONE ; A=0,B=1,... openf EQU 0FH ;Open File FCB-Addr in DE Byte Addr.of FCB, ; or 0FFH if not closf EQU 10H ;Close File FCB-Addr in DE Byte Addr.of FCB, ; or 0FFH if not sfirst EQU 11H ;Search File FCB-Addr in DE Byte Addr.of FCB(0-3), ; or 0FFH if not snext EQU 12H ;Search next FCB-Addr in DE Byte Addr.of next FCB, ; or 0FFH if not delf EQU 13H ;Delete File FCB-Addr in DE Byte Addr.of FCB(0-3), ; or 0FFH if not readf EQU 14H ;Read Record FCB-Addr in DE 0=successful read ; 1=read past EOF ; 2=reading random data writef EQU 15H ;Write Record FCB-Addr in DE 0=successful write ; 1=ERROR extending ; 2=End of disk data ; 255=No more DIR space makef EQU 16H ;Make File FCB-Addr in DE 0-3= success, ; 255= no more dir space renam EQU 17H ;Rename File FCB-Addr in DE 0-3= success, ; 255= file not found rdlog EQU 18H ;Ret. Log Code NONE Login Vector in HL rddrv EQU 19H ;Read Drive # NONE # of logged in drive in ; (A=0,B=1,C=2....) setdma EQU 1AH ;Set DMA Addr. Addr. of 128 NONE ; byte buffer in DE wrtprt EQU 1CH ;Write prot dsk NONE NONE getrov EQU 1DH ;Get R/O Vect. NONE HL= R/O Vect. value setfat EQU 1EH ;Set File Attr. FCB-Addr.in DE Dir. code in A gtdpar EQU 1FH ;Get DSK par. NONE HL=DPB Address usrcod EQU 20H ;Get/Set Usr.Cd E=0FFH (get) A=current code (get) ; E-code (set) A=no value (set) rrand EQU 21H ;Read Random FCB-Addr in DE A=Return code wrand EQU 22H ;Write Random FCB-Addr in DE 1=read'g unwritten data ; 2=(not used) ; 3=can't close curr. ext ; 4=seek to unwr. ext. ; 5=dir overflow(write) ; 6=seek past End of DSK cflsz EQU 23H ;Comp File Sz. FCB Addr.in DE Rand.Rec.field set to ; File size setrar EQU 24H ;Set Rand. Rec. FCB-Addr.in DE Rand.Rec.field set ; CPM 2 only: punout EQU 04H ;Write Punch ASCII Char in E NONE gtiob EQU 07H ;Get I/O status NONE I/O Status in A ptiob EQU 08H ;Put I/O status I/O Status in E NONE getalv EQU 1BH ;Get All.Vect. NONE All.Vect in HL ; CPM 3 only: auxout EQU 04H ;Auxiliary output auxist EQU 07H ;Get AUXIN: status A=FF if character ; ready, A=0 if none auxost EQU 08H ;Get AUXOUT: status A=FF if ready, A=0 ; if not ready getfs EQU 2EH ;Get free space E=drive # rec free in dma addr ; parevn EQU 00H ;Even parity. parmrk EQU 03H ;Mark parity. parnon EQU 06H ;No parity (eighth bit is data). parodd EQU 09H ;Odd parity. parspc EQU 0CH ;Space parity. defpar EQU parnon ;Default parity. ibmpar EQU parmrk ;IBM COMTEN's parity. fcb EQU 5CH ;Location of File Control Block. fcbext equ fcb+12 fcbrno equ fcb+33 buff EQU 80H ;Location of file output buffer (DMA). bufsiz EQU 80H ;Size of DMA. maxpkt EQU '~'-' '+2O;Maximum size of a packet. maxtry EQU 05O ; Number of retries on a packet. imxtry EQU 20O ; Number of retries send initiate. prfair EQU 100 ;[pcc008] Prtchr fairness count ; opcodes for command parser cmkey EQU 01H ;Parse a keyword. cmifi EQU 02H ;Parse an input file spec (can be wild). cmofi EQU 03H ;Parse an output file spec. cmcfm EQU 04H ;Parse a confirm. cmtxt EQU 05H ;Parse text. cmifin EQU 10H ;Parse an input file spec (but no ;Error output ; ; If this is being assembled by LASM, we need to LINK to one of two modules; ; if we're not using LASM, no problem. ; CP4KER.ASM defines "cp4ker" TRUE, and CP4TYP.ASM defines it FALSE, so we can ; determine what's going on. IF lasm AND cp4ker ; building CP4KER with LASM? LINK CP4MIT ; yes, chain to next piece. ENDIF;lasm AND cp4ker IF lasm AND NOT cp4ker ; LASM, but not building CP4KER? LINK CP4LNK ; yes, chain to different piece. ENDIF;lasm AND NOT cp4ker 2O;Maximum size of a packet. maxtry EQU 05O ; Number of retries on a packet. imxtry EQU 20O ; Number of retries send initiate. prfair EQU 100 ;[pcc008] Prtchr fairness count ; opcodes for command parser cmkey EQU 01H ;Parse a keyword. cmifi EQU 02H ;Parse an input file spec (can be wild). cmofi EQU 03H ;Parse an output file spec. cmcfm EQU 04H ;Parse a confirm. cmtxt EQU 05H ;Parse text. cmifin EQU 10H ;Parse an input file spec (but no ;Error output ; ; If this is being assembled by LAS ; CP4KER.ASM ; KERMIT - (Celtic for "FREE") ; ; This is the CP/M-80 implementation of the Columbia University ; KERMIT file transfer protocol. ; ; Version 4.0 ; ; Copyright June 1981,1982,1983,1984 ; Columbia University ; ; Originally written by Bill Catchings of the Columbia University Center for ; Computing Activities, 612 W. 115th St., New York, NY 10025. ; ; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben, ; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many ; others. ; ; This is the header for the system-independent portion of KERMIT, which ; consists of the following files (in this order): ; CP4KER.ASM - this file ; CP4DEF.ASM - definitions for both KERMIT and KERSYS ; CP4MIT.ASM - initialization, main loop, miscellaneous commands ; (BYE, EXIT, LOG, SET, SHOW, and STATUS) ; CP4PKT.ASM - the KERMIT protocol handler (SEND, RECEIVE, LOGOUT, ; and FINISH commands) ; CP4TT.ASM - the transparent commands (TRANSMIT, CONNECT) ; CP4CPM.ASM - CP/M commands (DIR, ERA) ; CP4WLD.ASM - the wildcard handler ; CP4CMD.ASM - the command parser ; CP4UTL.ASM - utility routines and data ; ; When building the system-independent part with M80 or MAC80, CP4KER ; INCLUDEs the other files; when building with LASM, each file LINKs to ; the next file. ; ; For now, the system-dependent routines are all in CP4SYS.ASM, with ; the actual configuration defined in CP4TYP.ASM. ; ; revision history (latest first): ; edit 3: February 10, 1985 (CJC) ; Update for v4.05; add "verno" so CP4UTL doesn't have to change ; just because some other module did. ; ; edit 2: September 10, 1984 (CJC) ; Update for v4.03. ; ; edit 1: July 27, 1984 (CJC) ; Created to allow assembly of Kermit by LASM as well as MAC80 and M80. verno EQU 05 ; minor version number ; Version 4.05 of Kermit consists of the following edit levels: ; cp4ker.asm edit 3 ; cp4def.asm edit 4 ; cp4mit.asm edit 8 ; cp4pkt.asm edit 6 ; cp4tt.asm edit 4 ; cp4cpm.asm edit 3 ; cp4wld.asm edit 3 ; cp4cmd.asm edit 5 ; cp4utl.asm edit 6 ; cp4lnk.asm edit 5 (cp4lnk.asm is not assembled with cp4ker, but it ; defines the linkage area expected by cp4ker, and so must ; match the description in cp4utl.asm) ; ; Version 4.05 of Kermit has been tested with the following edit levels of ; the system-dependent files: ; cp4typ.asm edit 6 ; cp4sys.asm edit 12 ; FALSE equ 0 TRUE equ NOT FALSE cp4ker equ TRUE ; building system-independent part ; ; Assembler type. Define the appropriate one TRUE, the rest FALSE. (We can't ; use ASM, because it cannot handle multiple input files) mac80 EQU FALSE ; For assembly via MAC80 cross-assembler. m80 EQU FALSE ; For assembly via Microsoft's M80. lasm EQU TRUE ; For assembly via LASM, a public-domain ; assembler. ; ; Get the other modules... IF lasm ; If we're linking, go on to the next file. LINK CP4DEF ENDIF;lasm ; If we're still here, we must be using M80 or MAC80. M80 doesn't ; like ENDs inside conditionals, but the END statement has to be ; in CP4UTL for LASM (otherwise, we'd need a file containing just an ; END statement). So, we leave off the IF m80 OR mac80 conditional ; that ought to be around these INCLUDEs. No problem until the next ; incompatible assembler comes along... INCLUDE CP4DEF.ASM ; definitions INCLUDE CP4MIT.ASM ; initialization, main loop, some commands INCLUDE CP4PKT.ASM ; KERMIT protocol handler INCLUDE CP4TT.ASM ; transparent communication handler INCLUDE CP4CPM.ASM ; CP/M command support (DIR, ERA) INCLUDE CP4WLD.ASM ; wildcard handler INCLUDE CP4CMD.ASM ; command parser INCLUDE CP4UTL.ASM ; Various utilities and data, and END [ToadHall] END ; MAC80 ignores END's in included files... a public-domain ; assembler. ; ; Get the other modules... IF lasm ; If we're linking, go on to the next file. LINK CP4DEF ENDIF;lasm ; If we're still here, we must be using M80 or MAC80. M80 doesn't ; like ENDs inside conditionals, but; CP4LNK.ASM ; KERMIT - (Celtic for "FREE") ; ; This is the CP/M-80 implementation of the Columbia University ; KERMIT file transfer protocol. ; ; Version 4.0 ; ; Copyright June 1981,1982,1983,1984 ; Columbia University ; ; Originally written by Bill Catchings of the Columbia University Center for ; Computing Activities, 612 W. 115th St., New York, NY 10025. ; ; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben, ; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many ; others. ; ; This file describes the areas used to communicate between KERMIT ; and the customizing overlay. It is included by the overlay. ; This file should be changed only to reflect changes in the ; system-independent portion of Kermit (enhancements, I hope). ; ; revision history: ; edit 5: February 6, 1985 ; Added a storage variable, "PORT", for the port-in-use value ; required for the port status routine (same purpose as SPEED). ; Also moved the printer copy flag (PRNFLG:) into t he commun- ; ications storage area so machine dependant overlay can access it. ; [Hal Hostetler] ; Also, replace assembly-time conditional "ffussy" with run-time ; switch (CJC). ; ; edit 4: August 21, 1984 (CJC) ; Define a use for the third word of the linkage section: it points ; to the version string for CP4SYS.ASM. Add flsmdm, to flush comm line ; on startup. Add bufadr and bufsec for multiple-sector buffer support. ; Shift the entry section up two bytes so we can exit cleanly from DDT. ; ; edit 3: August 3, 1984 (CJC) ; put "mover" in CP4SYS, so we can do a Z80 block move if so inclined. ; ; edit 2: July 10, 1984 (CJC) ; integrate Toad Hall changes for LASM compatibility: CP4LNK is linked ; by CP4DEF, and links CP4SYS. ; ; edit 1: May, 1984 (CJC) ; extracted from CPMBASE.M80 version 3.9; modifications are described ; in the accompanying .UPD file. ; ; Define the entry section. These addresses contain jumps to ; useful routines in KERMIT. To show we know what we're doing, ; we store the length of this section (entsiz) in our linkage ; section. I didn't use ORG and DS because I don't want zeroes ; generated for all the space between here and the actual start ; of cp4sys. entry equ 105H ; start of entry section kermit equ entry+0 ; reentry address nout equ entry+3 ; output HL in decimal entsiz equ 2*3 ; 2 entries, so far. ; ; End of entry section. ; ; Linkage section. This block (through the definition of lnksiz) ; is used by Kermit to reach the routines and data in the overlay. ; The section length is stored at the beginning of the overlay ; area so Kermit can verify that the overlay section is (a) present, ; (b) in the right place, and (c) the same size as (and therefore ; presumably the same as) the linkage section Kermit is expecting. ; ASEG ORG OVLADR ; lnkflg: dw lnksiz ; linkage information for consistency check. dw entsiz ; length of entry table, for same. dw sysedt ; address of overlay revision level message ; ; hooks for system-dependent routines: ; ; Input/output routines. ; jmp selmdm ; select modem for I/O jmp outmdm ; output character in E to modem jmp inpmdm ; read character from modem. return character or 0 in A. jmp flsmdm ; flush pending input from modem jmp selcon ; select console for I/O jmp outcon ; output character in E to console jmp inpcon ; read char from console. return character or 0 in A jmp outlpt ; output character in E to printer ; ; screen formatting routines jmp clrlin ; erase current line jmp clrspc ; erase current position (after backspace) jmp delchr ; make delete look like backspace jmp clrtop ; erase screen and go home ; ; these routines are called to display a field on the screen. jmp scrend ; move to prompt field jmp screrr ; move to error message field jmp scrfln ; move to filename field jmp scrnp ; move to packet count field jmp scrnrt ; move to retry count field jmp scrst ; move to status field jmp rppos ; move to receive packet field (debug) jmp sppos ; move to send packet field (debug) ; jmp sysinit ; program initialization jmp sysexit ; program termination jmp syscon ; remote session initialization jmp syscls ; return to local command level jmp sysinh ; help text for interrupt (escape) extensions jmp sysint ; interrupt (escape) extensions, including break jmp sysflt ; filter for incoming characters. ; called with character in E. jmp sysbye ; terminate remote session jmp sysspd ; baud rate change routine. ; called with value from table in DE jmp sysprt ; port change routine. ; called with value from table in DE jmp sysscr ; screen setup for file transfer ; called with Kermit's version string in DE jmp csrpos ; move cursor to row B, column C jmp sysspc ; calculate free space for current drive jmp mover ; do block move ; ; Local parameter values ; pttab: dw ttab ; points to local equivalents to VT52 escape sequences spdtab: dw spdtbl ; address of baud rate command table, or zero spdhlp: dw sphtbl ; address of baud rate help table, or zero prttab: dw prttbl ; address of port command table, or zero prthlp: dw prhtbl ; address of port help table, or zero timout: dw fuzval ; Fuzzy timeout. vtflg: db vtval ; VT52 emulation flag escchr: db defesc ; Storage for the escape character. speed: dw 0FFFFH ; storage for the baud rate (initially unknown) port: dw 0FFFFH ; storage for port value (initially unknown) [hh] prnflg: db 0 ; printer copy flag [hh] dbgflg: db 0 ; debugging flag ecoflg: db 0 ; Local echo flag (default off). flwflg: db 1 ; File warning flag (default on). ibmflg: db 0 ; IBM flag (default off). cpmflg: db 0 ;[bt] file-mode flag (default is DEFAULT) parity: db defpar ; Parity. 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. squote: db dsquot ; Send quote char. rquote: db drquot ; Receive quote char. chktyp: db dschkt ; Checksum type desired tacflg: ; TACtrap status: IF tac db tacval ; when non-zero, is current TAC intercept character; ENDIF;tac IF NOT tac db 0 ; when zero, TACtrap is off. ENDIF;tac tacchr: db tacval ; Desired TAC intercept character (even when off) bufadr: dw buff ; Address of possibly multi-sector buffer for I/O bufsec: db 1 ; Number of sectors big buffer can hold (0 means 256) ffussy: db 1 ; if nonzero, don't permit <>.,;?*[] in CP/M filespec. ; space used by directory command; here because space calculation is ; (operating) system-dependent bmax: ds 2 ; highest block number on drive bmask: ds 1 ; (records/block)-1 bshiftf: ds 1 ; number of shifts to multiply by rec/block nnams: ds 1 ; counter for filenames per line lnksiz equ $-lnkflg ; length of linkage section, for consistency check. IF lasm ; If we're assembling with LASM, LINK CP4SYS ; get the next section. ENDIF;lasm  dschkt ; Checksum type desired tacflg: ; TACtrap status: IF tac db tacval ; when non-zero, is current TAC intercept character; ENDIF;tac IF NOT tac db 0 ; when zero, TACtrap is off. ENDIF;tac tacchr: db tacval ; Desired TAC intercept character (even when off) bufadr: dw buff ; Address of possibly multi-sector buffer for I/O bufsec: db 1 ; Number of sectors big buffer can hold (0 means 256) ffussy: db 1 ; if nonzero, don't permit <>.,;?*[] in CP/M filespec. ; space used by directory command; here because space calculation is ; (operating) system-dependent bmax: ds 2 ; highest block number on drive bmask: ds 1 ; (records/block)-1 bshiftf: ds 1 ; number of shifts to multiply by rec/block nnams: ds 1 ; counter for filenames per line lnksiz equ $-lnkflg ; length of linkage section, for consistency check. IF lasm ; If we're assembling with LASM, LINK CP4SYS; CP4MIT.ASM ; KERMIT - (Celtic for "FREE") ; ; This is the CP/M-80 implementation of the Columbia University ; KERMIT file transfer protocol. ; ; Version 4.0 ; ; Copyright June 1981,1982,1983,1984,1985 ; Columbia University ; ; Originally written by Bill Catchings of the Columbia University Center for ; Computing Activities, 612 W. 115th St., New York, NY 10025. ; ; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben, ; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many ; others. ; ; This file contains the system-independent initialization, the main ; loop, and the commands that don't have any place better to go ; (BYE, EXIT, HELP, LOG, SET, SHOW, and STATUS). ; ; revision history: ; edit 8: February 6, 1895 ; Add a PORT status/show routine for those machines that have more ; than one they can talk to. It also required a port storage variable ; a la SPEED and the necessary code to handle it in the SET routine. ; [Hal Hostetler] ; ; edit 7: 13-Jan-85 by Vanya J.Cooper Pima Commun. College Tel: 602-884-6809 ; ;pcc003-pcc005 2-Jan-85 vjc modules:cp4mit,cp4tt,cp4utl ; These edits must all be installed together and change the way ; logging is handled. The log file spec is moved to a separate ; fcb, and not opened until an actual CONNECT command is given. ; This takes care of a NASTY bug that if you used any other file ; command between the LOG and CONNECT, the log file would get ; written over the last file used. This also allows logging to ; be "permanently" enabled until an CLOSE (new command) for all ; CONNECT sessions, like most other kermits do. If a log file ; already exists, it will be appended to. Also add two new ; CONNECT mode commands Q to suspend logging and R to ; resume. R means something else during TRANSMIT, but ; logging is never on then, so there shouldn't be any conflict. ; I also changed the write code, so that it can handle one more ; character after the XOFF is send to stop the host. This allows ; a little "slop" for systems that don't stop immediately (such ; as TOPS10), but it didn't help much. ;pcc012 4-Jan-85 vjc modules:cp4mit,cp4tt,cp4utl ; Use the big buffer for the log file. Move the log file back ; into the common fcb and only save the drive, name, and ; extension between connects. Add new routines to cp4utl to ; create or append to an existing file, and to conditionally ; advance buffers only if in memory. Remove edit pcc003 that ; allows one more character after the xoff, since it didn't ; really work very well and does not fit in well with the way ; the buffer advancing routines are set up. If someone still ; thinks this would be useful, it could be put back in with a ; little more work. ; ; While testing this edit, I also noticed another bug that ; the command parsing routines do not limit or check the ; length of command lines or file specs, trashing what ever ; comes after them. Currently because of where the fcb and ; command buffer are located, this does not usually cause a ; problem, but could if an extremely long line was typed in, ; or in the future multiple fcbs defined elsewhere in memory ; were used. Maybe this should be put on the bug list ; somewhere. ;pcc013 8-Jan-85 vjc modules:cp4mit,cp4utl,cp4typ ; Replace CLOSE command to cancel session logging to SET ; LOGGING ON/OFF. This seems to fit in with the command ; structure better. Default the log file to KERMIT.LOG ; incase no previous LOG command. Logging is also enabled ; by LOG command, as before. ; edit 6: September 8, 1984 ; Add VERSION command, to display the internal version strings. ; Move command tables here from CP4UTL, and translate string ; lengths in them to decimal (how many fingers do YOU got?). ; Replace some jump tables with dispatch addresses in tables. ; Make help text for SET command consistent with top level help text. ; ; edit 5: August 21, 1984 ; Add word at 0100H to allow us to exit cleanly from DDT (shifting ; entry section by two bytes). ; ; edit 4: August 3, 1984 (CJC) ; Remove "mover" from entry section, as it now lives in CP4SYS. ; ; edit 3: July 27, 1984 (CJC) ; Merge LASM support from Toad Hall: most of CP4MIT is now in CP4UTL. ; When assembling with LASM, CP4MIT is linked by CP4DEF; it links to ; CP4PKT. Add SET TACTRAP command. Separate out display routines so ; we can eventually do "SHOW ". Save both bytes of baud ; rate in speed, and check both bytes when displaying baud rate. Move ; header info to CP4KER.ASM. Add onoff and chkkey routines to simplify ; SET command (Toad Hall) ; ; edit 2: June 8, 1984 ; formatting and documentation; delete unreferenced variables and some ; unnecessary labels; move setpar here from cp4pkt; add module version ; string; make this version 4.01. ; ; edit 1: May, 1984 ; extracted from CPMBASE.M80 version 3.9; modifications are described ; in the accompanying .UPD file. ; ASEG ORG 100H ; The CCP invokes programs with a CALL 100H, with the stack pointer set to ; 100H. When we exit to CP/M, we do so with a RET, avoiding a warm boot. ; Unfortunately, DDT starts programs with a jump, not a call, so when we ; attempt to return to CP/M, we blow the stack and use the word at 100H as ; the new PC. Put a 0 there so we reboot instead of dying horribly. ; (Fortunately, this happens to be two NOP's). dw 0 jmp start ; Bypass entry section ; ; Entry section for system-independent part. This contains ; jumps to routines needed by the system support module. ; entries: jmp kermit ; reentry address jmp nout ; output HL in decimal entsiz equ $-entries ; length of entry section ; ; End of entry section. As a consistency check, the expected ; length of this section is stored by the system-dependent ; module in the linkage section at the end of Kermit, and ; tested at initialization. mitver: db 'CP4MIT.ASM (8) 6-Feb-85$' ; name, edit number, date ; ; ; Initialization ; start: lxi h,0 ; Clear out hl pair dad sp ; and fetch the system stack pointer shld oldsp ; and save for later restoral lxi sp,stack ; move in our own stack. lxi d,version ; print Kermit version call prtstr ; before we do too much mvi c,rddrv ;Get our logged in drive call BDOS inr a ;relative 1 sta CURDSK ;and save it for later ; ; Make sure the overlay is in place... ; lhld lnkflg mov a,h ora l ; if lnkflg is still zero, jz start1 ; the configuration overlay is missing. lxi d,-lnksiz ; if it's not equal to lnksiz, dad d ; we've probably got the wrong mov a,h ; version of the configuration overlay. ora l jnz start2 lhld lnkent ; make sure the overlay knows how long lxi d,-entsiz ; our entry section is, so they don't miss. dad d mov a,h ora l jnz start2 ; might be ok. call sysinit ; do system-dependent initialization lxi d,inms26 ; offer some advice on getting help call prtstr jmp kermit ; Start main loop. start1: lxi d,erms20 ; "Kermit has not been configured" call prtstr ; print error message jmp exit2 ; and exit. start2: lxi d,erms21 ; "Consistency check on configuration failed" call prtstr ; print error message jmp exit2 ; and exit. ; ;This is the main KERMIT loop. It prompts for and gets the users commands. kermit: lxi sp,stack ; get new stack pointer, old one might be bad. call selcon ; make sure console is selected. xra a sta mfflg1 ;reset MFNAME sta mfflg2 ;ditto lda curdsk ; update the prompt adi 'A'-1 sta kerm1 lxi d,kerm call prompt ;Prompt the user. lxi d,comtab lxi h,tophlp call keycmd ; Get a keyword xchg ; Get result (dispatch address) into HL pchl ; Dispatch. ; here from: log, setcom, read, cfmcmd kermt3: lxi d,ermes3 ;"Not confirmed" call prtstr jmp kermit ;Do it again. ; Structure of command table: ; ; 1) Number of entries. ; 2) Each entry is arranged as follows: ; a) length of command in bytes. ; b) 'name of command and $-sign' ; c) address of routine to process command ; ; ---> Note this command table is in alphabetic order. ; comtab: db 17 ;[pcc013] 17 entries db 3, 'BYE$' dw bye db 7, 'CONNECT$' dw telnet db 9, 'DIRECTORY$' dw dir db 5, 'ERASE$' dw era db 4, 'EXIT$' dw exit db 6, 'FINISH$' dw finish db 3, 'GET$' dw read ;Same as RECEIVE db 4, 'HELP$' dw help db 3, 'LOG$' dw log db 6, 'LOGOUT$' dw logout db 7, 'RECEIVE$' dw read db 4, 'SEND$' dw send db 3, 'SET$' dw setcom db 4, 'SHOW$' dw show db 6, 'STATUS$' dw status db 8, 'TRANSMIT$' dw xmit db 7, 'VERSION$' dw shover ; top-level help message. Caps indicate keywords. ; this text is also printed by the HELP command. tophlp: db cr,lf,'BYE to host (LOGOUT) and exit to CP/M' db cr,lf,'CONNECT to host on selected port' db cr,lf,'ERASE a CP/M file' db cr,lf,'EXIT to CP/M' db cr,lf,'FINISH running Kermit on the host' db cr,lf,'HELP by giving this message' db cr,lf,'DIRECTORY of current used Micro-disk' db cr,lf,'LOG the terminal sessions to a file' db cr,lf,'LOGOUT the host' db cr,lf,'RECEIVE file from host' db cr,lf,'SEND file to host' db cr,lf,'SET a parameter' db cr,lf,'SHOW the parameters' db cr,lf,'STATUS of Kermit' db cr,lf,'TRANSMIT file to host (in connect state)' db cr,lf,'VERSION of Kermit running$' ;[pcc005] ; ; This is the BYE command. It tells the remote KERSRV to logout, ; then exits. bye: call cfmcmd call logo ;Tell the main frame to logout. jmp kermit ;If it fails, don't exit. call sysbye ; success. do system-dependent cleanup jmp exit1 ;Exit Kermit. ; This is the EXIT command. It leaves KERMIT and returns to CP/M. ; alternate entries: exit1, from BYE command; ; exit2, from initialization (if it fails) exit: call cfmcmd ; confirm... exit1: call sysexit ; do system-dependent termination exit2: lhld oldsp ;Get back the system stack sphl ;and restore it. ret ;Then return to system. ; This is the HELP command. It gives a list of the commands. help: call cfmcmd lxi d,tophlp ;The address of the help message. call prtstr jmp kermit ; ; This is the LOG command. It logs a session to a file. log: mvi a,cmofi ;[pcc005] Parse an output file spec. lxi d,fcb ;[pcc012] where to put it call comnd jmp kermt3 call cfmcmd lxi h,fcb ;[pcc012] copy file name and ext lxi d,lognam ;[pcc012] to a safe place lxi b,12 ;[pcc012] 12 bytes call mover ;[pcc012] zap ... mvi a,1 ;[pcc005] set flag for logging sta logflg ;[pcc005] jmp kermit ;[pcc005] ; ; This is the SET command. setcom: lxi d,settab ;Parse a keyword from the set table. lxi h,sethlp call keycmd xchg ; Get result (dispatch address) into HL pchl ; Dispatch. settab: db 16 ;[pcc013] 16 entries [Toad Hall] ; Value is address of processing routine. db 9, 'BAUD-RATE$' dw baud db 16, 'BLOCK-CHECK-TYPE$' dw blkset db 5, 'DEBUG$' dw setdbg db 12, 'DEFAULT-DISK$' dw setdisk db 6, 'ESCAPE$' dw escape db 9, 'FILE-MODE$' dw setcpm db 3, 'IBM$' dw ibmset db 10, 'LOCAL-ECHO$' dw locall db 7, 'LOGGING$' ;[pcc013] dw setlog ;[pcc013] db 6, 'PARITY$' dw parset db 4, 'PORT$' dw prtset db 7, 'PRINTER$' dw setprn ;* db 7, 'RECEIVE$' ;* dw kermt3 ;Not implemented yet. ;* db 4, 'SEND$' ;* dw setsnd ;Ditto db 7, 'TACTRAP$' dw settac db 5, 'TIMER$' dw settim db 14, 'VT52-EMULATION$' dw vt52em db 7, 'WARNING$' dw filwar ; help message for SET command. Caps indicate keywords sethlp: db cr,lf,'BAUD-RATE' db cr,lf,'BLOCK-CHECK-TYPE for error detection' db cr,lf,'DEBUG message control' db cr,lf,'DEFAULT-DISK to receive data' db cr,lf,'ESCAPE character during CONNECT' db cr,lf,'FILE-MODE for outgoing files' db cr,lf,'IBM mode: parity and turn around handling' db cr,lf,'LOCAL-ECHO (half-duplex)' db cr,lf,'LOGGING of terminal sessions' ;[pcc013] db cr,lf,'PARITY for communication line' db cr,lf,'PORT to communicate on' db cr,lf,'PRINTER copy control' ;* db cr,lf,'RECEIVE parameters' ;Not currently implemented ;* db cr,lf,'SEND parameters' ;Ditto db cr,lf,'TAC interface support' db cr,lf,'TIMER control' db cr,lf,'VT52-EMULATION' db cr,lf,'WARNING for filename conflicts' db '$' ; ;SET BLOCK-CHECK-TYPE command. blkset: lxi d,blktab ;Get the address of the block-check table lxi h,blkhlp ;And the address of the help text call chkkey ;Go check input (val returns in A). sta chktyp ;Save desired checksum type jmp kermit ;Go get another command blktab: db 3 ;Three entries. db 20, '1-CHARACTER-CHECKSUM$', '1','1' db 20, '2-CHARACTER-CHECKSUM$', '2','2' db 21, '3-CHARACTER-CRC-CCITT$', '3','3' blkhlp: db cr,lf,'1-CHARACTER-CHECKSUM' db cr,lf,'2-CHARACTER-CHECKSUM' db cr,lf,'3-CHARACTER-CRC-CCITT$' ;SET DEFAULT DISK command setdisk:lxi d,fcb mvi a,cmifin ;get "file-spec" silently call comnd jmp setdi1 setdi1: lda fcb ora a ;Was a drive specified? (if zero, no) jnz setdi2 ;he typed a drive-spec lda curdsk ;he didn't - give him default setdi2: sta curdsk mvi c,inbdos ;reset disks call bdos lda curdsk dcr a ;LOGDSK is relative 0 mov e,a mvi c,logdsk call bdos ;and "LOG" it jmp kermit ;all done ; ;SET SEND command. (not supported yet) setsnd: lxi d,stsntb ;Parse a keyword from the set send table. lxi h,stshlp call keycmd xchg ; Get dispatch address into HL pchl ; Go for it. stsntb: db 2 ;Two entries. db 8, 'PAD-CHAR$' dw stpdch db 7, 'PADDING$' dw stpad stshlp: db cr,lf,'PAD-CHAR' db cr,lf,'PADDING$' ; SET SEND PADDING command. does nothing. stpad: call cfmcmd jmp kermit ; SET SEND PAD-CHAR command. does nothing. stpdch: call cfmcmd jmp kermit ;[pcc013] ; This is the SET LOGGING ON/OFF subcommand setlog: call onoff ;[pcc013] Get on/off sta logflg ;[pcc013] Store flag jmp kermit ; ; This is the SET ESCAPE character subcommand. escape: call cfmcmd lxi d,escmes ;Get the address of the escape message. call prtstr mvi c,conin ;Get the char. call bdos sta escchr ;Store the new escape character. jmp kermit ; This is the SET LOCAL-ECHO subcommand. locall: call onoff ;Get on/off setting [Toad Hall] sta ecoflg ;Store local echo flag. jmp kermit ; This is the SET PRINTER ON/OFF subcommand setprn: call onoff ;Get on/off setting [Toad Hall] sta prnflg ;Store printer flag jmp kermit ; This is the SET DEBUG ON/OFF subcommand setdbg: call onoff ;Get on/off setting [Toad Hall] sta dbgflg ;Store debug flag jmp kermit ;[jd] this is the SET TIMER subcommand settim: call onoff ;Get on/off setting [Toad Hall] sta timflg ;Store timer flag value jmp kermit ;This is the SET FILE-WARNING subcommand filwar: call onoff ;Get on/off setting [Toad Hall] sta flwflg ;Store file-warning flag. jmp kermit ; This is the SET IBM command. ibmset: call onoff ;Get on/off setting [Toad Hall] sta ibmflg ;Store IBM flag. ora a ;Is it turned on? jz ibmst1 ;If not, set parity to the default. mvi a,ibmpar ;Get the IBM parity. mvi b,1 ;Set local echo on. jmp ibmst2 ibmst1: mvi a,defpar mvi b,0 ;Set local echo off. ibmst2: sta parity ;Save them. mov a,b sta ecoflg sta timflg ;[jd] timer is same as local echo jmp kermit ; ; SET FILE-MODE command. setcpm: lxi d,typtab lxi h,typhlp call chkkey ;Get and confirm keyword, or die trying sta cpmflg ;Set the CPM flag. jmp kermit typtab: db 3 ;Three entries db 5, 'ASCII$', 01H,01H db 6, 'BINARY$', 02H,02H db 7, 'DEFAULT$', 00H,00H typhlp: db cr,lf,'ASCII BINARY DEFAULT$' ; This is the SET PARITY subcommand. parset: lxi d,partab lxi h,parhlp call chkkey ;Get and confirm keyword, or die trying sta parity ;Set the parity flag. jmp kermit partab: db 5 ;Five entries. db 4, 'EVEN$', parevn,parevn db 4, 'MARK$', parmrk,parmrk db 4, 'NONE$', parnon,parnon db 3, 'ODD$', parodd,parodd db 5, 'SPACE$', parspc,parspc parhlp: db cr,lf,'EVEN MARK NONE ODD SPACE$' ; This is the SET TACTRAP subcommand. ; options are ON, OFF, or CHARACTER. (for CHARACTER, we request the ; new TAC Intercept character, and turn the TACtrap on) settac: lxi d,tactab lxi h,tachlp call chkkey ;Get and confirm keyword ora a ;Was it "OFF" (zero)? jz settc2 ;If so, go disable TACtrap. cpi 1 ;Was it "ON"? jz settc1 ;If so, go enable TACtrap. lxi d,tacmes ;"CHARACTER". request new TAC Intercept char. call prtstr mvi c,conin ;Get the char. call bdos sta tacchr ;Store the new TAC Intercept character. settc1: lda tacchr ;Copy tacchr to tacflg to enable TACtrap. settc2: sta tacflg ;Enable/disable TACtrap jmp kermit tactab: db 3 ;Three entries. db 9, 'CHARACTER$', 02H,02H db 3, 'OFF$', 00H,00H db 2, 'ON$', 01H,01H tachlp: db cr,lf,'ON to enable TAC trap' db cr,lf,'OFF to disable TAC trap' db cr,lf,'CHARACTER to enable TAC trap and' db ' specify intercept character$' ; This is the SET VT52-EMULATION subcommand. vt52em: lda vtflg ;get the flag value cpi 0ffH ;0ffH means not allowed - jz notimp ; say it's not implemented. call onoff ;Get keyword (ON or OFF) sta vtflg ;Set the VT52 emulation flag. jmp kermit ; ; Note: For the SET BAUD and SET PORT commands, which might not be ; supported for the current system, the command tables are stored in ; the overlay. We locate them through pointers in the linkage area: ; spdtab for SET BAUD, prttab for SET PORT. The contents of spdtab ; (or prttab) is the address of the beginning of the table (the table ; does NOT begin at spdtab). If the address is zero, the command is ; not supported. If the table address is nonzero, then there is a ; corresponding help message pointed to by (NOT starting at) spdhlp ; or prthlp. ; This is the SET BAUD command baud: lhld spdtab ; get pointer to speed table mov a,h ora l ; test for NULL (zero) jz notimp ; if so, say it's not implemented xchg ; move speed table address to DE lhld spdhlp ; get pointer to speed help text call keycmd push d ; save selected speed call cfmcmd ; confirm... pop h ; restore speed to HL shld speed ; save all 16 bits of speed value xchg ; move speed to DE call sysspd ; do system-dependent speed setting. jmp kermit ; return to command level ; This is the SET PORT command prtset: lhld prttab ; get pointer to port table mov a,h ora l ; test for NULL jz notimp ; not supported if pointer was null. xchg ; move port table address to DE lhld prthlp ; get pointer to port help text call keycmd push d ; save selected port entry call cfmcmd ; confirm... pop h ; restore table address to HL shld port ;[hh] save all 16 bits of port value call sysprt ; go do port stuff jmp kermit ; ; Subroutines for SET subcommands ; ontab - command table for onoff. ; onhlp - help text for onoff. ; onoff - accept "ON" or "OFF" keyword. ; returns: ; success: value in A (non-zero = ON) ; error: no return to caller. print error message and return to ; main loop. ontab: db 2 ;Two entries. db 3, 'OFF$', 00H,00H db 2, 'ON$', 01H,01H onhlp: db cr,lf,'OFF ON$' onoff: lxi d,ontab lxi h,onhlp ;Fall through to check input. [Toad Hall] ; chkkey - parse and confirm keyword. ; called with: ; DE/ address of keyword table ; HL/ address of help text ; returns: ; success: low byte of keyword value (from table) in A. ; error: no return to caller. print error message and return to ; main loop. (Since the main loop reloads the stack pointer, ; we don't have to attempt to clean up the stack here) chkkey: call keycmd ; Parse a keyword (might not return) sta temp1 ; Save the parsed value call cfmcmd ; Request confirmation (might not return) lda temp1 ; Get saved value ret ; Return ;[hh] fndkyw - find a keyword string from a table using ; it's associated value ; called with: ; HL/ address of keyword table ; A/ value associated with keyword string ; returns: ; success: HL points to first byte of keyword string ; CY flag is cleared ; error: HL points to error string (?Not found) ; CY flag is set fndkyw: mov d,m ;get count of entries inx h ;advance over count value fndkw1: mov b,m ;get string length inr b ;account for $ inx h ;advance over length value shld temp1 ;save string pointer fndkw2: inx h ;loop over string dcr b jnz fndkw2 mov c,m ;get keyword value from table cmp c ;do they match? jz fndkw3 ;Yup inx h ;bump to next keyword inx h ; dcr d ;decrement entry count jnz fndkw1 ;check the remaining keywords lxi h,kywdnf ;point to not found message stc ;give calling routine a not found flag ret fndkw3: ora a ;clear CY to tell caller we succeeded lhld temp1 ;restore the saved string pointer ret kywdnf: db cr,lf,'?Not found$' ;not found message ; ; This is the SHOW command. show: call cfmcmd ;* Reconcile this and status. call clrtop ;[hh] Clear screen first call stat01 ;For now just cop out. jmp kermit ; This is the STATUS command. status: call cfmcmd call clrtop ;[hh] Clear screen first call stat01 jmp kermit ; processor for SHOW, STATUS and S commands ; called by: show, status, intchr stat01: lda fileio ;Are we in transmit? ora a jz sta01b ;No lxi d,xmtst ;Yes,say so call prtstr sta01b: call staeco ; Tell about local echo flag lda vtflg ; Get the VT52 emulation flag cpi 0ffH ; Supported for this terminal? cnz stavt ; If so, tell whether it's on or off. call stafil ; Tell about file type call staibm ; Tell about IBM flag call stawrn ; Tell about file-warning flag call stalpt ; Tell about printer copy flag call stalog ; [pcc003] Tell about log file status call stapar ; Tell about parity lhld prttab ;[hh] Got a port table? (is pointer nonzero?) mov a,h ;[hh] ora l ;[hh] cnz stapor ;[hh] If so, tell which port we're using lhld spdtab ; Got a speed table? (is pointer nonzero?) mov a,h ora l cnz staspd ; If so, tell what speed we're running. call stabcc ; Tell current block check type call staesc ; Tell current escape character call statim ; Tell about timer flag call statac ; Tell about TAC flag/intercept character. ret ; Show the value of the LOCAL-ECHO flag (On or Off). staeco: lxi d,locst ;Get the address of the local echo string. call prtstr lda ecoflg ;Get the local echo flag. jmp staton ;Say ON or OFF, and return ; Show the value of the VT52-EMULATION flag (On, Off, or Not Supported). stavt: lxi d,vtemst ; Get the address of the VT52 emulation string. call prtstr lda vtflg ; Get the VT52 emulation flag. cpi 0ffH ; Is it supported? jnz staton ; If so, say ON or OFF, and return jmp notimp ; Not supported. print appropriate message. ; Show the value of the FILE-MODE flag (ASCII, Binary, or Default). stafil: lxi d,cpmst ; Get the address of the file mode message. call prtstr lda cpmflg ; Get the file mode flag. lxi d,defstr ; Assume Default (0). ora a ; Is it? jz prtstr ; If so, say so, and return. lxi d,ascstr ; Not default, assume ASCII cpi 1 ; Is it ASCII? jz prtstr ; Say ASCII, and return lxi d,binstr ; Not default or ASCII, must be binary jmp prtstr ; Print type, and return. ; Show the value of the IBM-MODE flag (On or Off). staibm: lxi d,ibmst ;IBM string. call prtstr lda ibmflg ; Get IBM flag. jmp staton ; Print its value and return ; Show the value of the FILE-WARNING flag (On or Off). stawrn: lxi d,filst ; File warning string. call prtstr lda flwflg ; File warning flag. jmp staton ; Say ON or OFF ; Show the value of the PRINTER flag (On or Off). stalpt: lxi d,prst ;Printer copy string call prtstr lda prnflg ;Printer ON/OFF flag jmp staton ; Say ON or OFF ; Show status of log file stalog: lxi d,logst ;[pcc003] Logging call prtstr ;[pcc003] lda logflg ;[pcc003] get the flag ani 7FH ;[pcc003] ignore open flag cpi 2 ;[pcc003] is it suspended? jnz staton ;[pcc003] no, must be on or off lxi d,susstr ;[pcc003] suspended jp prtstr ;[pcc003] print and return ; Show the value of the PARITY flag (Odd, Even, Mark, Space, or None). stapar: lxi d,parst ;Parity string. call prtstr lda parity ;Get the parity setting. lxi d,pnonst ;Assume parity is NONE cpi parnon ;Were we right? jz prtstr ;Yep, go say None, and return lxi d,pmrkst ;Get ready to say Mark cpi parmrk ;Is it mark? jz prtstr ;Yep, go say Mark, and return lxi d,pspcst ;Get ready to say Space cpi parspc ;Is it space? jz prtstr ;Yep, go say Space, and return lxi d,poddst ;Get ready to say Odd cpi parodd ;Is it odd? jz prtstr ;Yep, go say Odd, and return lxi d,pevnst ;Must be Even. jmp prtstr ;Say Even, and return. ;[hh] Show the current port (if known). stapor: lxi d,porst ;[hh] call prtstr ;[hh] lda port ;[hh] Get current port value lxi h,spdust ;[hh] Assume undefined (this error msg is fine) cpi 0FFH ;[hh] Is it? jz stat73 ;[hh] Yup. Say so lhld prttab ;[hh] Address of port keyword table call fndkyw ;[hh] Look for correct keyword string jnc stpr1 ;[hh] Found a match lxi h,spdust ;[hh] No match found - say it's undefined stpr1: jmp stat73 ;[hh] Print it and return ; Show the current line speed (if known). staspd: lxi d,spdst call prtstr lda speed ;Get current speed. lxi h,spdust ;Assume undefined. cpi 0FFH ;Is it? jz stat73 ;Yes. lhld spdtab ;Start scanning keyword table. mov d,m ; get count of entries inx h ; advance over it. stat70: mov b,m ;Get string length. inr b ;Account for $. inx h shld temp1 ;Save string pointer. stat71: inx h ;Loop over string. dcr b jnz stat71 mov c,m ;Get speed value cmp c ;Match? jz stat72 ;Yes. inx h ;Bump to next keyword. inx h dcr d ; decrement entry count jnz stat70 ; if more left, check them. lxi h,spdust ; can't find it. say it's undefined. jmp stat73 ; print the message. stat72: lhld temp1 ;Restore saved string pointer. stat73: xchg ;Set into DE for display. jmp prtstr  ; print it, and return. ; Show the current BLOCK-CHECK-TYPE (1-, 2-, or 3-character). stabcc: lxi d,bckst ;Get the string call prtstr ;Print "Block check type: " lda chktyp ;Get the type (character 1, 2, or 3) mov e,a ;Put into E mvi c,conout ;Want to print it call BDOS ;Do so lxi d,bckst1 ;Get rest of text ("-character") jmp prtstr ;Print it and return ; Print the current escape character staesc: lxi d,escst ;Escape string. call prtstr call escpr ;Print the escape char. jmp prcrlf ;Print CR/LF and return [Toad Hall] ; Show the value of the TIMER flag statim: lxi d,timmsg ;[jd] call prtstr ;[jd] lda timflg jmp staton ;Tell whether it's on or off. ; Show internal versions (edit strings) shover: call cfmcmd call prcrlf lxi h,vertab ; Get address of version list shovr1: mov e,m ; Get next word from list inx h mov d,m ; Next version string is in DE inx h mov a,d ; Test for zero (end of list) ora e jz shovr2 ; Done with list if zero  push h ; Save position in list call prtstr ; Not zero. Print it. call prcrlf ; Follow with crlf pop h ; Restore position in list jmp shovr1 ; and go see if there are any more. shovr2: lhld ovlver ; Get overlay version string xchg ; into DE call prtstr ; Print it call prcrlf ; Output crlf jmp kermit ; Return to main loop. ; table of pointers to version strings. vertab: dw mitver ; CP4MIT dw pktver ; CP4PKT dw ttver ; CP4TT dw cpmver ; CP4CPM dw wldver ; CP4WLD dw cmdver ; CP4CMD dw utlver ; CP4UTL dw 0 ; end of list ; Show TACTrap status (On or Off, and intercept character) statac: lxi d,tacst ;"Current TACTrap status/char: " call prtstr lxi d,offstr ;Assume set off lda tacflg ;Get the TACTrap char/flag ora a ;Is it off? jz prtstr ;Yep, go print OFF... mvi c,conout ;Display... mov e,a ;...the current intercept char call bdos jmp prcrlf ; Display current state of a boolean flag. ; called with A/ value (zero = Off, non-zero = On) staton: lxi d,onstr ; Assume it's on. ora a ; Is it on? jnz prtstr ; If so, say so, then return. lxi d,offstr ; No, say off. jmp prtstr ; Print the string, then return. ; Print "(not implemented)". ; here from vt52em, baud, prtset, stavt notimp: lxi d,inms12 ; Say it's not implemented. call prtstr jmp kermit ; Return to main loop. IF lasm ; If using LASM, chain to the next file. LINK CP4PKT ENDIF;lasm WLD dw cmdver ; CP4CMD dw utlver ; CP4UTL dw 0 ; end of list ; Show TACTrap status (On or Off, and intercept character) statac: lxi d,tacst ;"Current TACTrap status/char: " call prtstr lxi d,offstr ;Assume set off lda tacflg ;Get the TACTrap char/flag ora a ;Is it off? jz prtstr ;Yep, go print OFF... mvi c,conout ;Display... mov e,a ;...the current intercept char call bdos jmp prcrlf ; Display current state of a boolean flag. ; called with A/ value (zero = Off, non-ze; CP4TT.ASM ; KERMIT - (Celtic for "FREE") ; ; This is the CP/M-80 implementation of the Columbia University ; KERMIT file transfer protocol. ; ; Version 4.0 ; ; Copyright June 1981,1982,1983,1984,1985 ; Columbia University ; ; Originally written by Bill Catchings of the Columbia University Center for ; Computing Activities, 612 W. 115th St., New York, NY 10025. ; ; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben, ; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many ; others. ; ; This file contains the code for the TRANSMIT and CONNECT commands, ; which communicate with a host which is not running KERMIT. ; ; revision history: ; edit 4: 13-Jan-85 by Vanya J.Cooper Pima Commun. College Tel: 602-884-6809 ; ;pcc002 28-Dec-84 modules:cp4tt,cp4utl ; Add connect mode P command to toggle printer on ; and off. Conflicts with "official" recommended commands ; in protocol manual, but I don't think CP/M will ever get ; a PUSH command. ; ;pcc003-pcc005 2-Jan-85 vjc modules:cp4mit,cp4tt,cp4utl ; These edits must all be installed together and change the way ; logging is handled. The log file spec is moved to a separate ; fcb, and not opened until an actual CONNECT command is given. ; This takes care of a NASTY bug that if you used any other file ; command between the LOG and CONNECT, the log file would get ; written over the last file used. This also allows logging to ; be "permanently" enabled until an CLOSE (new command) for all ; CONNECT sessions, like most other kermits do. If a log file ; already exists, it will be appended to. Also add two new ; CONNECT mode commands Q to suspend logging and R to ; resume. R means something else during TRANSMIT, but ; logging is never on then, so there shouldn't be any conflict. ; I also changed the write code, so that it can handle one more ; character after the XOFF is send to stop the host. This allows ; a little "slop" for systems that don't stop immediately (such ; as TOPS10), but it didn't help much. ; ;pcc008 2-Jan-85 vjc modules:cp4def,cp4tt,cp4utl ; Keyboard input during CONNECT mode can get locked out if ; there is enough input from the modem port to keep prtchr ; busy. This can happen for example, if the printer is running ; at the same speed as the modem line, leaving you helpless to ; turn it off or abort the host. Add a fairness count, so that ; at least every prfair characters we look at console input. ; ;pcc012 4-Jan-85 vjc modules:cp4mit,cp4tt,cp4utl ; Use the big buffer for the log file. Move the log file back ; into the common fcb and only save the drive, name, and ; extension between connects. Add new routines to cp4utl to ; create or append to an existing file, and to conditionally ; advance buffers only if in memory. Remove edit pcc003 that ; allows one more character after the xoff, since it didn't ; really work very well and does not fit in well with the way ; the buffer advancing routines are set up. If someone still ; thinks this would be useful, it could be put back in with a ; little more work. ; ; While testing this edit, I also noticed another bug that ; the command parsing routines do not limit or check the ; length of command lines or file specs, trashing what ever ; comes after them. Currently because of where the fcb and ; command buffer are located, this does not usually cause a ; problem, but could if an extremely long line was typed in, ; or in the future multiple fcbs defined elsewhere in memory ; were used. Maybe this should be put on the bug list ; somewhere. ; ; edit 3: July 27, 1984 ; Allow assembly with LASM: to CP4TT is linked by CP4PKT, and links ; to CP4CPM; remove exclamation points so as not to confuse LASM. ; Add Toad Hall TACtrap to TRANSMIT command (TAC intercept character ; is only doubled if it's data; when typed by the user, they're not ; automatically doubled) ; ; edit 2: June 7, 1984 ; formatting and documentation; add module version number; make sure ; console is selected when leaving intchr. ; ; edit 1: May, 1984 ; extracted from CPMBASE.M80 version 3.9; modifications are described ; in the accompanying .UPD file. ttver: db 'CP4TT.ASM (4) 13-Jan-85$' ; This is the TRANSMIT command. It attempts to send a file, even ; though there is no KERMIT on the other side. ; here from: kermit xmit: mvi a,cmofi ;Parse an input file spec (non-wild). lxi d,fcb ;Give the address for the FCB. call comnd jmp kermit ;Give up on bad parse. call cfmcmd call getfil ;Open file. cpi 0FFH ;Succeed? jnz xmit1 lxi d,erms15 call prtstr ;Display error msg. jmp kermit xmit1: lxi d,inms19 ;Output start message. call prtstr call escpr ;Print the escape character. lxi d,inms20 ;Output 2nd part. call prtstr call escpr ;Print the escape character. lxi d,inms21 ;Print the rest. call prtstr mvi a,1 ;Start file I/O. sta fileio xra a ;Clear XOFF flag. sta xofflg ; fall through into xnext... ; ; assemble another line from the disk file. ; here from: previous page, rexmit xnext: call prtchr ; Copy characters from comm line to console mvi c,consta ; until user types anything on the console. call bdos ora a jz xnext ; nothing at console yet. lda eoflag ;EOF encountered? ora a jnz xend ;Yes, finish. xra a ;Reset line buffer counter. mov c,a sta cmaflg ;Reset carriage return flag. lxi d,cmdbuf ;Use comnd buffer as line buffer. lhld bufpnt ; Get current buffer pointer. lda chrcnt ; Get current byte count mov b,a ; in B xmit30: dcr b ; Assume there's a character there jp xmit2 ; If there was, proceed. call inbuf ; There wasn't. Try for another buffer. jmp xmit38 ; End of file. lhld bufpnt ; Got another buffer. Get new pointer in HL lda chrcnt ; and new byte count mov b,a ; in B xmit2: mov a,m ;Get a character from disk buffer. inx h ani 7FH ;Mask 7 bits. jz xmit30 ;Skip nulls. cpi cr ;Carriage return? jz xmit32 cpi subt ;CTRL-Z (substitute)? jz xmit37 cpi lf ;Line feed? jz xmit39 stax d ;Save to buffer. inx d lda cmaflg ;Carriage return seen? ora a jnz xmit31 ;Yes, don't count this character. inr c ;Count it. xmit31: jmp xmit30 ;Loop for next input byte. ; Carriage return seen. Start discarding characters until we see a line-feed. xmit32: sta cmaflg ;Mark return seen. jmp xmit30 ;And continue. ; Control-Z seen. Force end of file, and send the current line. xmit37: sta eoflag ;Mark EOF for next line. ; fall through... ; End of File encountered. eoflag has already been set; just send current line. xmit38: ; fall through... ; Linefeed seen. send the current line. xmit39: shld bufpnt ;Save next buffer pointer. mov a,b ;Save count of remaining characters. sta chrcnt mov a,c ;Save line length. sta filcnt ; fall through into rexmit... ; ; transmit the buffered line. ; here from: previous page, intchr rexmit: lda filcnt ;Set up line length. sta cmccnt lxi h,cmdbuf ;Set up line buffer pointer. shld cmcptr xmit40: call prtchr ;Receive comm. line & display. lda xofflg ;XOFF received? ora a jnz xmit40 ;Yes, wait for XON lda cmccnt ;Any characters left? dcr a jm xmit49 ;No, next state. sta cmccnt call selmdm ; select modem for outmdm lhld cmcptr ;Get the character to be sent mov a,m inx h ;Bump to next character. shld cmcptr call setpar ;Set parity (if any). mov e,a ;Save character (with parity) call outmdm ;Output it to the comm. line. ; TAC trap: If this character is the TAC intercept character, and the TAC ; trap is enabled, we have to output it twice. If the TAC trap is enabled, ; tacflg contains the intercept character. (The current character cannot ; be NUL, so we don't have to worry about doubling nulls in the message) lda tacflg ; get current intercept character, or zero. cmp m ; compare against current data character. jnz xmit41 ; if different, do nothing. call setpar ; match. set appropriate parity, mov e,a ; put it in the right register, call outmdm ; and output it a second time. xmit41: lda ecoflg ;Local echo? ora a jz xmit40 ;No, continue. mov a,e ;Get the character. ani 7FH ;Mask out parity. mov e,a ;Display on console. call selcon call outcon jmp xmit40 ;Continue. xmit49: xra a ;Reset last character seen. sta lstchr xmit50: call prtchr ;Receive comm. line & display. call conchr ;Read keyboard & send. jmp xendc ;CLOSE connection. lda lstchr ;Check last keyboard character. cpi cr ;Carriage return? jz xnext ;Yes, prepare to send next line. jmp xmit50 ;Continue, until carriage return. ; ; clean up. ; xend - end of file reached. close file, go to connect mode. ; here from: xnext. ; xendc - user wants out. close file, go to command mode. ; here from: rexmit. xend: call xmtoff ;Close file, etc. lxi d,inms22 ;Tell we're done with transmission jmp telnt1 ;Branch to CONNECT command. xendc: call xmtoff ;Close file, etc. jmp kermit ;Back to command loop. xmtoff: mvi c,closf  ;Close file. lxi d,fcb call bdos xra a ;Terminate file I/O. sta fileio ret ; ; telnet - the CONNECT command. ; here from: kermit ; telnt1 - entry to connect mode from TRANSMIT command ; here from: xend telnet: call cfmcmd lxi d,infms7 ;Output start of message ; enter here from TRANSMIT command. telnt1: call prtstr call escpr ;Print the escape char. lxi d,infms8 ;Output some more of the message call prtstr call escpr ;Print the escape char again. lxi d,inms8a ;Print the remainder of the message call prtstr call syscon ;do system-dependent stuff lda logflg ;[pcc005] Want a log? ora a ;[pcc005] cnz logopn ;[pcc005] Open if so chrlup: call prtchr ;See if char at port (send to console). call conchr ;See if char at console (send to port). jmp kermit ;requested to end session - go to command loop. jmp chrlup ;Go do it again. ; ; ; prtchr - copy characters from comm line to console ; returns: nonskip, console selected. ; called by: xnext, rexmit, telnet ; prtchr: call selmdm ; select modem port call inpmdm ; try to get a character from it ora a ; test character jnz prtch0 ; if non-zero, process it. sta prtcnt ;[pcc008] zero out prt fairness count call selcon ; select console ret ; return. prtch0: ani 7FH ; drop parity bit. jz prtchr ; ignore null (filler) cpi del ; ignore delete, too jz prtchr cpi xon ;Is it an XON? jz prtxon ;yes cpi xoff ;Is it an XOFF? jz prtxof ;yes mov e,a ;Set the char aside. lda vtflg ;Get the VT52 emulation flag. cpi 1 ;Is the flag set? jnz prtch1 ;If not, don't do this stuff. lda escflg ;Get the escape flag. ora a ;Are we working on an escape sequence? jz prtch2 ;If not, continue. call vt52 ;If so, work on it some more jmp prtchr ;try for more characters. prtch2: mov a,e ;normal text. cpi esc ;Is the char an escape? jnz prtch1 ;If not skip on. mvi a,1 sta escflg ;Set the escape flag: escape seen. jmp prtchr ;Get another char...  prtch1: call sysflt ; ok to print this character (in E)? ora a jz prtchr ; no, skip it. lda logflg ;Get the log flag. cpi 81H ;[pcc003] Are we logging cz logit ;[pcc003] Do so if needed call selcon ; select console lda prnflg ;Get Print parallel flag ora a cnz outlpt ; output to printer if flag set call outcon ; output to console. lxi h,prtcnt ;[pcc008] point to prt fairness count inr m ;[pcc008] bump mov a,m ;[pcc008] get it in a cpi prfair+1 ;[pcc008] time to be fair? jm prtchr ;[pcc008] no, go around again. mvi m,0 ;[pcc008] reset count ret ;[pcc008] and return ; I don't think we want to print xon/xoff - this should be ; flow control only across the link between us and the host. ; (besides, IBM host xon's don't make sense to most micros) ; remember xon/xoff state in xofflg (zero = xon, non-zero = xoff) prtxon: xra a ;Yes, reset XOFF flag prtxof: sta xofflg jmp prtchr ; look for another character ; ;[pcc005] Log file routines ;[pcc005] ; logopn - open the log file ; Open the log file and append to it if it already exists ; or create one if not. logopn: lxi h,lognam ;[pcc012] copy name lxi d,fcb ;[pcc012] to fcb lxi b,12 ;[pcc012] 12 bytes call mover ;[pcc012] copy it call appfil ;[pcc012] open file for appending jmp logerr ;[pcc012] error lxi h,logflg ;[pcc005] point to log flag mvi a,80H ;[pcc005] file open flag ora m ;[pcc005] or in contents of logflg mov m,a ;[pcc005] and store back lxi d,inms28 ;[pcc005] assume logging is on cpi 81H ;[pcc005] check jz prtstr ;[pcc005] print msg if true lxi d,inms27 ;[pcc005] no, must be suspended jmp prtstr ;[pcc005] print and return ; ; logit - output character in E to log file. ; we assume the host recognizes xon/xoff. (we probably shouldn't) ; modem port is selected. ; preserves de ; called by: prtchr logit: lxi h,chrcnt ;[pcc012] point to buffer count dcr m ;[pcc012] and decrement jp logit1 ;[pcc012] continue if ok push d ;[pcc012] save de call outadv ;[pcc012] advance buffer if in memory call logwrt ;[pcc012] sigh, time to write to disk pop d ;[pcc012] restore de lda logflg ;[pcc012] get logging flag ora a ;[pcc012] Did we quit because of an error rz ;[pcc012] return now if so logit1: lhld bufpnt ;[pcc012] get buffer pointer mov m,e ;Store the char. inx h shld bufpnt ret ;[pcc012] and return ;[pcc012] ; logwrt - write to log file with XON/XOFF since it may take a while. logwrt: mvi a,xoff ;^S to stop the host while we write the buffer. call setpar ; set correct parity... mov e,a call outmdm ; output it. call outbuf ;[pcc012] output the buffer and advance call logerr ;[pcc005] quit if error mvi a,xon ;^Q to restart the host call setpar ; set appropriate parity mov e,a call outmdm ; send it. ret ;[pcc012] ;[pcc005] ; logcls - Close the log file and reset the flag logcls: lxi d,infms6 ;[pcc005] Tell user we are closing file. call prtstr ;[pcc005] call clofil ;[pcc012] and do it jmp logerr ;[pcc005] jump if error lxi h,logflg ;[pcc005] point to flag mov a,m ;[pcc005] get it ani 7FH ;[pcc005] clear the open bit mov m,a ;[pcc005] and store back ret ;[pcc005] ;[pcc005] ; logerr - here on a variety of logging errors ; just close the file and disable logging ; called from logopn,logptr,logcls logerr: lxi d,erms22 ;[pcc005] Error message call prtstr ;[pcc005] print it mvi c,closf ;[pcc005] Close the file. lxi d,fcb ;[pcc012] call bdos ;[pcc005] xra a ;[pcc005] clear logflg sta logflg ;[pcc005] so don't try again ret ;[pcc005] ; ; ; VT52 emulation. ; called by: prtchr ; A/ contents of escflg (guaranteed non-zero) ; E/ current character ; modem is selected. ; vt52: cpi 1 ; first character after escape? jnz vt52y ; no, must be doing cursor positioning. ; ; E contains the character that followed the escape. ; valid characters are: ; A - cursor up ; B - cursor down ; C - cursor right ; D - cursor left ; F - enter graphics mode (hard to do on a non-vt52) ; G - exit graphics mode ; H - home ; I - reverse linefeed ; J - erase to end of screen ; K - erase to end of line ; Y - cursor positioning leadin ; Z - identify terminal as VT52 ; [ - enter hold-screen mode (not supported) ; \ - exit hold-screen mode (not supported) ; > - enter alternate-keypad mode? (not supported) ; = - exit alternate-keypad mode? (not supported) ; ; Invalid sequences are handled as the VT52 does - the escape and ; the following character are swallowed, never to be seen again. ; For E, the translation table may contain just '$' (no action), ; or may be used as clear-and-home, as in the Heath/Zenith H19. ; mov a,e ; get the second character of the sequence. cpi 'Y' ; if cursor lead-in handle it. jnz vt52a ; if not, go on. mvi a,2 ; state = 2: row follows. sta escflg ; update the flag. ret ; back for another character vt52a: cpi 'Z' ; VT52 ID query? jz vt52id ; yes. claim to be one. cpi 'A' ;Less than an 'A'? jm vtig ;Yes - ignore. cpi 'K'+1 ;Greater than 'K'? jp vtig ;Yes - ignore. sui 'A' ;Else make into index. rlc ;Multiply by four. rlc ;(Shift left twice.) lhld pttab ;Load base addr of table. mov e,a ;Move a into de pair. mvi d,00H ;Zero out high byte. dad d ;Double add index+offset. xchg ;Exchange de with hl. call selcon ; select console call prtstr ;and syscall. vtig: ;Ignore escape sequence. xra a ;Reset the ol' escape flag. sta escflg ret ;Return home. ; here for Z. Tell the host we're a VT52. (Sure we are...) vt52id: mvi a,esc ; response is escape... call setpar ; (need correct parity) mov e,a call outmdm ; (console already selected) mvi a,'/' ; ... slash ... call setpar ; (with parity) mov e,a call outmdm mvi a,'K' ; ... K. call setpar mov e,a call outmdm jmp vtig ; clear escape-sequence flag and return. ; here when escflg isn't 0 or 1 - processing cursor positioning sequence. vt52y: cpi 2 ; looking for row? (y-coordinate) jnz vt52x ; no, must be column. mov a,e ; yes. get coordinate sui (' '-1) ; convert from ascii (1 = top line) sta vtyval ; store for later mvi a,3 ; advance to next state (x coord) sta escflg ; store it ret ; try for another character ; here when escflag isn't 0, 1, or 2 - it must be 3. (right?) ; E holds the last character of the cursor positioning sequence. vt52x: xra a ; end of escape sequence, reset state. sta escflg mov a,e ; get column (' ' is left margin) sui (' '-1) ; make left margin be one mov c,a ; stash column in c lda vtyval ; get row number mov b,a ; in b call selcon ; select console call csrpos ; call system-dependent cursor positioner ret ; all through. ; ; ; conchr - copy character from console to comm line, processing ; (kermit's) escape sequences. ; Enter and exit with console selected. ; nonskip return: transparent mode terminated. ; skip return: still in transparent mode. ; called by: rexmit, telnet conchr: call inpcon ;Try to get a character from the console ani 07FH ;Keep only 7 bits jz rskp ;Null means nothing there. mov e,a ;Move the char for comparison. sta lstchr ;Save it lda escchr ;Get the escape char. cmp e ;Is it an escape char? jz intchr ;If so go process it. call selmdm ; select the modem mov a,e ;Get the char. call setpar ;Set parity (if any). mov e,a ;Restore it. call outmdm ;Output the char to the port. call selcon ; reselect console lda ecoflg ;Get the echo flag. ora a ;Is it turned on? jz rskp ;If not we're done here. mov a,e ;Get the char. ani 7FH ;Turn off the parity bit. mov e,a call outcon ; echo the character. jmp rskp ; use skip return ; ; transparent escape character has been typed. dispatch on second ; character. (console is still selected) ; here from: conchr intchr: call inpcon ; get another character from the console ora a ; zero means no character available yet. jz intchr ; If so, loop until we get a char. mov b,a ;Save the actual char. cpi ctrlc ;is it Control-C? jz contc ;yes ani 137O ;Convert to upper case. cpi 'C' ;Is it close? jnz intch0 ;If not proceed. contc: lxi d,infms9 ;Say we are back. call prtstr call syscls ; call system-dependent close routine lda logflg ;Get the log flag. ora a ;[pcc005] Check if open cm logcls ;[pcc005] Close if needed ret ;Here if not a 'C' or '^C' intch0: cpi 'S' ;Is it status? jnz inch01 ;If not, proceed. call stat01 ;Print out the status stuff. call prcrlf ;[pcc011] add a crlf jmp rskp ;return from conchr inch01: cpi 'R'-100O ;Control-R? jz inch02 ;Yes cpi 'R' ;(plain) R? jnz inch03 ;No inch02: lda fileio ;TRANSMIT in progress? ora a jz inch03 ;No,ignore pop b ;Remove return address (non-local goto) jmp rexmit ;Retransmit line inch03: mov a,b ;Get the char. cpi '?' ;Is it a help request? jnz intch1 ;If not, go to the next check. lda fileio ;TRANSMIT in progress? ora a jz inch3a ;[pcc003] No lxi d,xmthlp ;Tell about R too call prtstr inch3a: lda logflg ;[pcc003] Logging flag ora a ;[pcc003] see if active jp inch04 ;[pcc005] jump if no file open lxi d,loghlp ;[pcc003] yes, tell about R AND Q call prtstr ;[pcc003] inch04: lxi d,inthlp ;If so, get the address of the help message. call prtstr call sysinh ; print system-dependent help message lxi d,inhlp1 ; Tell about doubling the escape character call prtstr call escpr ;Print escape character lxi d,inhlp2 ;Print the rest call prtstr jmp intchr ;Get another char. intch1: mov a,b ;Get the character. cpi '0' ;Is it '0', to send a null? jnz intch3 ;No. xra a ;Yes, send an ASCII zero. call setpar ; with the correct parity mov e,a call selmdm ; (to the modem...) call outmdm call selcon ; return with console selected jmp rskp intch3: lda escchr ;Get the escape char. cmp b ;Is it the escape char? jnz intch4 ;[pcc002] jump if not mov a,b ;Get the char. call setpar mov e,a ;Restore it. call selmdm call outmdm ;Output it. call selcon ;We promised console would be selected... jmp rskp ;Return, we are done here. intch4: mov a,b ;[pcc002] get it again ani 137o ;[pcc002] in upper case cpi 'P' ;[pcc002] toggle printer? jnz intch5 ;[pcc003] nope lda prnflg ;[pcc002] get printer flag xri 01h ;[pcc002] complement it sta prnflg ;[pcc002] and put back jmp rskp ;[pcc002] intch5: lda logflg ;[pcc003] get log flag ora a ;[pcc003] See if open jp intch7 ;[pcc003] no, skip R and Q mov a,b ;[pcc003] get back chr ani 137o ;[pcc003] make upper case cpi 'R' ;[pcc003] Is it R jnz intch6 ;[pcc003] Jump if not mvi a,81H ;[pcc003] set flag for logging sta logflg ;[pcc003] put it back lxi d,inms28 ;[pcc003] message call prtstr ;[pcc003] jmp rskp ;[pcc003] done intch6: cpi 'Q' ;[pcc003] Quit logging? jnz intch7 ;[pcc003] no mvi a,82H ;[pcc003] flag for open, but suspended sta logflg ;[pcc003] store away lxi d,inms27 ;[pcc003] keep them informed call prtstr ;[pcc003] jmp rskp ;[pcc003] intch7: ;[pcc003] intchz: mov a,b ; not recognized. get saved copy back. call sysint ; interpret system-dependent sequences jmp rskp ; done. return (from conchr). mvi e,'G'-100O ;Otherwise send a beep. call outcon ; to the console. jmp rskp ; IF lasm LINK CP4CPM ENDIF;lasm [pcc003] See if open jp intch7 ;[pcc003] no, skip R and Q mov a,b ;[pcc003] get back chr ani 137o ;[pcc003] make upper case cpi 'R' ;[pcc003] Is it R jnz intch6 ;[pcc003] Jump if not mvi a,81H ;[pcc003] set flag for logging sta logflg ;[pcc003] put it back lxi d,inms28 ;[pcc003] message call prtstr ;[pcc003] jmp rskp ;[pcc003] done intch6: cpi 'Q' ;[pcc003] Quit logging? jnz intch7 ;[pcc003] no mvi a,82H ;[pcc003] flag for open, but suspended sta logflg ;[pcc003] stor; CP4TYP.ASM ; KERMIT - (Celtic for "FREE") ; ; This is the CP/M-80 implementation of the Columbia University ; KERMIT file transfer protocol. ; ; Version 4.0 ; ; Copyright June 1981,1982,1983,1984,1985 ; Columbia University ; ; Originally written by Bill Catchings of the Columbia University Center for ; Computing Activities, 612 W. 115th St., New York, NY 10025. ; ; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben, ; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many ; others. ; ; This is the header file for building the system-dependent overlay ; for KERMIT. It contains the definitions used to select the target ; system, and collects (via INCLUDE or LINK directives) the remaining ; code. If the target system is one of the supported systems ; described below, then this is the only file that needs to be ; edited. ; ; revision history: ; ; edit 6: 9-Feb-85 by CJC ; Merge Northstar Horizon, Lobo MAX, and Xerox 820 changes: ; 13-Dec-84 Add Northstar Horizon with SIO-4 board, port 5 at 1200 [CSM] ; 13-Jan-85 by Vanya J.Cooper Pima Commun. College Tel: 602-884-6809 ; ;pcc001 27-Dec-84 vjc modules: cp4sys,cp4typ ; Add conditional for Xerox 820. I thought at first I could ; live with the kaypro conditional, but it's enough of a pain ; that I added it back in. The clear-to-end-of-screen char ; is different, breaking many programs in VT52 mode, and the ; default escape char control-\, is not at all obvious how ; to type on the 820 keyboard. If you muddle through the ; key translation table, it turns out to be control-comma. ; Rather than OR xer820 all the occurances of kpII conditionals ; I added a bbI conditional for all common code for the big ; board I based machines that is automatically turned on by ; either kpII or xer820. This will also make it easier in ; the future if another flavor of bigboard is added. ; ;pcc010 2-Jan-85 vjc modules:cp4pkt,cp4typ ; Control-C during send or recieve clobbers some of the screen ; and doesn't look nice. Position the cursor to end of screen ; before returning to main loop. ; ;pcc013 8-Jan-85 vjc modules:cp4mit,cp4utl,cp4typ ; Replace CLOSE command to cancel session logging to SET ; LOGGING ON/OFF. This seems to fit in with the command ; structure better. Default the log file to KERMIT.LOG ; incase no previous LOG command. Logging is also enabled ; by LOG command, as before. ; ; edit 5: October 13, 1984 by L M Jones, JCC, for New York Botanical Garden ; Add support for CPT-85xx series of word processors when running CP/M. ; ; edit 4: August 29, 1984 by Bdale Garbee @ CMU ; Add support for Digicomp Delphi 100 and Netronics Smartvid terminal. ; ; edit 3: July 27, 1984 (CJC) ; Shuffle files around for easier assembly by both M80 and LASM. ; ; edit 2: June 4, 1984 [Toad Hall] ; Added Morrow Decision I (the big S100 bus sucker, not the ; little single motherboard one); added Toad Hall TACTrap to deal ; with those working through a TAC and its intercept character. ; ; edit 1: May, 1984 (CJC) ; extracted from CPMBASE.M80 version 3.9; modifications are described ; in the accompanying .UPD file. ; FALSE EQU 0 TRUE EQU NOT FALSE ; ; Assembler type. Define the appropriate one TRUE, the rest FALSE. (We can't ; use ASM, because it cannot handle multiple input files) mac80 EQU FALSE ; For assembly via MAC80 cross-assembler. m80 EQU FALSE ; For assembly via Microsoft's M80. lasm EQU TRUE ; For assembly via LASM, a public-domain ; assembler. ; ; Address at which the overlay should be loaded. This will not ; change often (no more than once per version of KERMIT); it should ; be updated when a new version of KERMIT is released. ovladr EQU 3700H ; [pcc013] value for KERMIT v4.04 ;Which CP/M system hardware are we building KERMIT-80 for? ;One of the following should be TRUE, the rest FALSE: ; ;We have basically three "classes" of systems: ;Systems supporting the IO-redirection via I/O-Byte robin EQU FALSE ;DEC VT180 = Generic + VT100 screen control gener EQU FALSE ;"Generic" Kermit-80, CP/M calls only. ; (terminal required) dmII EQU FALSE ;"Generic" KERMIT-80 for DECMATE II. mikko EQU FALSE ;"Generic" KERMIT-80 for MikroMikko IF robin OR dmII OR gener OR mikko iobyt EQU TRUE ;Short conditional for above inout EQU FALSE ENDIF;robin OR dmII OR gener ;.. and Systems supporting direct IN / OUT handling of ports brain EQU FALSE ;For Intertec SuperBrain. vector EQU FALSE ;For Vector Graphics. heath EQU FALSE ;For Heath/Zenith H89. z100 EQU FALSE ;For Z-100 under CP/M-85. trs80lb EQU FALSE ;For Lifeboat 2.25C CP/M Display trs80pt EQU FALSE ;For Pickles + Trout CP/M Display telcon EQU FALSE ;For TELCON Zorba portable kpII EQU FALSE ;Kaypro-II xer820 EQU FALSE ;[pcc001] Xerox 820 bbII EQU TRUE ;BigBoard II (terminal required) mmdI EQU FALSE ;Morrow Micro Decision I (terminal required) mdI EQU FALSE ;Morrow Decision I (the big sucker) ; (terminal required) [Toad Hall] delphi EQU FALSE ;Digicomp Delphi 100 (terminal required) cpt85xx EQU FALSE ;CPT-85xx word processor w/CPM (set ADM3A true) norths EQU FALSE ;[CSM] NorthStar Horizon with HSIO-4 board ; (terminal required) trs80 EQU trs80lb OR trs80pt ; if either, flag TRS-80 system. bbI EQU kpII OR xer820 ;[pcc001] flag for bigboard I IF brain OR vector OR heath OR z100 OR trs80 OR telcon OR bbI inout EQU TRUE ;Short conditional for above iobyt EQU FALSE ENDIF;brain OR vector OR heath OR z100 OR trs80 OR telcon OR kpII IF bbII OR mmdI OR mdI OR delphi OR cpt85xx OR norths ;running out of room inout EQU TRUE ;Short conditional for above iobyt EQU FALSE ENDIF;bbII OR mmdI OR mdI OR delphi OR cpt85xx OR norths ;.. and Systems doing neither... osi EQU FALSE ;For Ohio Scientific. osbrn1 EQU FALSE ;For Osborne 1 cpm3 EQU FALSE ;"Generic" Kermit-80 for CP/M 3.0 (CP/M Plus) ; (terminal required) lobo EQU FALSE ;Lobo Max-80 apmmdm EQU FALSE ;jb Micromodem II in slot 2 ap6551 EQU FALSE ;jb apple with 6551 ACIA in serial interface  IF ap6551 ;jb eg. Apple SSC, Videx PSIO, Basis 108 apslot EQU 2 ;jb set equal to slot containing serial card ;jb set to 1 for Basis built-in port ENDIF;jb ap6551 apple EQU apmmdm OR ap6551 ; flag apple system if either selected IF osi OR apple OR osbrn1 OR cpm3 OR lobo iobyt EQU FALSE inout EQU FALSE ENDIF;osi OR apple OR osbrn1 OR cpm3 OR lobo ;.. and for Micros, like the MDI, which have "terminals of choice", you must ;select one of these in addition to selecting the micro itself. ;Also select a terminal for "gener" and "cpm3": use "crt" for the true generic. crt EQU FALSE ;Basic CRT, no cursor positioning adm3a EQU FALSE ;Adm3a Display (or CPT built-in display) smrtvd EQU FALSE ;Netronics Smartvid terminal. tvi925 EQU FALSE ;TVI925 Display ; (works for Freedom 100 also) [Toad Hall] vt52 EQU TRUE ;VT52 or equivalent (or H19) vt100 EQU FALSE ;VT100 or equivalent ; Toad Hall TAC Trap: If you're going through a TAC, it will ; cough on its Intercept Character (usually a @ (* - 40H)). Sending it ; twice forces the TAC to recognize it as a valid ASCII character, ; and it'll send only one on to the host. If you've SET the TACTrap ; to OFF, it will be a null character, and nothing will happen. If you ; set it on, it will be your selected TAC intercept character (or will ; default to the common intercept char, '@'. ; If you never expect to have to work through such a beastie, just set ; TAC to false and forget all this mess. [Toad Hall] tac EQU FALSE ; gonna work through a TAC? tacval EQU '@' ;Typical TAC intercept character ; Processor speed in units of 100KHz (for bbII, kpII, & cpt85xx timing loop) ;cpuspd EQU 20 ; CPT-85xx: 2.0 MHz ('cause of integral video?) ;cpuspd EQU 25 ; original Kaypro II,Xerox 820: 2.5 MHz cpuspd EQU 40 ; bbII: 4.0 MHz [also Kaypro 10] cp4ker EQU FALSE ; building the system-dependent part... IF lasm LINK CP4DEF ENDIF;lasm [Toad Hall] ; If we're still here, must be M80 or MAC80. Collect the rest of ; the sources. INCLUDE CP4DEF.ASM ; common definitions INCLUDE CP4LNK.ASM ; linkage area description INCLUDE CP4SYS.ASM ; system-dependent code and tables END  it will be your selected TAC intercept character (or will ; default to the common intercept char, '@'. ; If you never expect to have to work through such a beastie, just set ; TAC to false and forget all this mess. [Toad Hall] tac EQU FALSE ; gonna work through a TAC? tacval EQU '@' ;Typical TAC intercept character ; Processor speed in units of 100KHz (for bbII, kpII, & cpt85xx timing loop) ;cpuspd EQU 20 ; CPT-85xx: 2.0 MHz ('cause of integral video?) ;cpuspd EQU 25 ; original Kaypro II,Xerox 820: 2.5 MHz cpuspd EQU 40 ; bbII: 4.0 MHz [also Kaypro 10] cp4ker EQU FALSE ; building the system-dependent part... IF lasm LINK CP4DEF ENDIF;lasm [Toad Hall] ; If we're still here, must be M80 or MAC80. Collect the rest of ; the s; CP4UTL.ASM ; KERMIT - (Celtic for "FREE") ; ; This is the CP/M-80 implementation of the Columbia University ; KERMIT file transfer protocol. ; ; Version 4.0 ; ; Copyright June 1981,1982,1983,1984,1985 ; Columbia University ; ; Originally written by Bill Catchings of the Columbia University Center for ; Computing Activities, 612 W. 115th St., New York, NY 10025. ; ; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben, ; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many ; others. ; ; Utility routines, pure and impure data. ; ; revision history: ; edit 6: February 6, 1985 ; Added a storage location for the port value (PORT, just below ; SPEED) which is used by the port status routine, and moved the ; printer copy flag (PRNFLG:) into the communications area so ; that the machine dependant overlay can toggle it. [Hal Hostetler] ; Added ffussy flag for filename checking. Generate the version ; string from 'verno', which is set in CP4KER, because CP4KER has the ; list of modules and their edit numbers. [Charles Carvalho] ; ; edit 5: 13-Jan-85 by Vanya J.Cooper Pima Commun. College Tel: 602-884-6809 ; ;pcc002 28-Dec-84 modules:cp4tt,cp4utl ; Add connect mode P command to toggle printer on ; and off. Conflicts with "official" recommended commands ; in protocol manual, but I don't think CP/M will ever get ; a PUSH command. ; ;pcc003-pcc005 2-Jan-85 vjc modules:cp4mit,cp4tt,cp4utl ; These edits must all be installed together and change the way ; logging is handled. The log file spec is moved to a separate ; fcb, and not opened until an actual CONNECT command is given. ; This takes care of a NASTY bug that if you used any other file ; command between the LOG and CONNECT, the log file would get ; written over the last file used. This also allows logging to ; be "permanently" enabled until an CLOSE (new command) for all ; CONNECT sessions, like most other kermits do. If a log file ; already exists, it will be appended to. Also add two new ; CONNECT mode commands Q to suspend logging and R to ; resume. R means something else during TRANSMIT, but ; logging is never on then, so there shouldn't be any conflict. ; I also changed the write code, so that it can handle one more ; character after the XOFF is send to stop the host. This allows ; a little "slop" for systems that don't stop immediately (such ; as TOPS10), but it didn't help much. ; ;pcc006 2-jan-85 VJC modules:cp4cmd,cp4utl ; Problems with "?" in filespecs. On reparse, may cause action ; flag to be reset at wrong point, requiring multiple 's ; to terminate the line or other weird stuff. Also need to ; check flag and complain if wild-cards illegal. ; ;pcc008 2-Jan-85 vjc modules:cp4def,cp4tt,cp4utl ; Keyboard input during CONNECT mode can get locked out if ; there is enough input from the modem port to keep prtchr ; busy. This can happen for example, if the printer is running ; at the same speed as the modem line, leaving you helpless to ; turn it off or abort the host. Add a fairness count, so that ; at least every prfair characters we look at console input. ; ;pcc012 4-Jan-85 vjc modules:cp4mit,cp4tt,cp4utl ; Use the big buffer for the log file. Move the log file back ; into the common fcb and only save the drive, name, and ; extension between connects. Add new routines to cp4utl to ; create or append to an existing file, and to conditionally ; advance buffers only if in memory. Remove edit pcc003 that ; allows one more character after the xoff, since it didn't ; really work very well and does not fit in well with the way ; the buffer advancing routines are set up. If someone still ; thinks this would be useful, it could be put back in with a ; little more work. ; ; While testing this edit, I also noticed another bug that ; the command parsing routines do not limit or check the ; length of command lines or file specs, trashing what ever ; comes after them. Currently because of where the fcb and ; command buffer are located, this does not usually cause a ; problem, but could if an extremely long line was typed in, ; or in the future multiple fcbs defined elsewhere in memory ; were used. Maybe this should be put on the bug list ; somewhere. ; ;pcc013 8-Jan-85 vjc modules:cp4mit,cp4utl,cp4typ ; Replace CLOSE command to cancel session logging to SET ; LOGGING ON/OFF. This seems to fit in with the command ; structure better. Default the log file to KERMIT.LOG ; incase no previous LOG command. Logging is also enabled ; by LOG command, as before. ; ; edit 4: September 9, 1984 ; Move command tables and associated help text to CP4MIT. Add ; makfil/clofil routines and modify outbuf to write files in big ; chunks. Update Kermit's version to 4.03. ; ; edit 3: August 21, 1984 ; Make inbuf read files in big chunks to minimize disk start/stop ; delays. Buffer size and address is specified by system-dependent ; overlay. ; ; edit 2: August 3, 1984 ; move "mover" to CP4SYS to allow use of Z80 block move instruction. ; ; edit 1: July 27, 1984 ; extracted from CP4MIT.M80 edit 2, as part of LASM support. This is ; the last file linked for the system-independent code. ; utlver: db 'CP4UTL.ASM (5) 13-Jan-85$' ; Set the parity for a character in A. ; called by: spack, rexmit, logit, vt52, conchr, intchr setpar: push h ;Save HL. push b lxi h,parity mov c,m ;Get the parity routine. mvi b,0 lxi h,parjmp ;Get the first address. dad b pchl parjmp: jmp even jmp mark jmp none jmp odd jmp space none: jmp parret ;Don't touch the parity bit. even: ani 7FH ;Strip parity. jpe parret ;Already even, leave it. ori 80H ;Make it even parity. jmp parret mark: ori 80H ;Turn on the parity bit. jmp parret odd: ani 7FH ;Strip parity. jpo parret ;Already odd, leave it. ori 80H ;Make it odd parity. jmp parret space: ani 7FH ;Turn off the parity bit. jmp parret parret: pop b pop h ;Restore HL. ret ; ; Print the escape char. ; called by: stat01, xmit, telnet, intchr escpr: lda escchr ;Get the escape char. cpi ' ' ;Is it a control char? jp escpr2 lxi d,inms10 ;Output "Control-". call prtstr lda escchr ori 100O ;De-controlify. escpr2: mvi c,conout ;Output the char mov e,a call bdos ret ; fetch keyword; if unsuccessful, return to command level. ; called by: kermit, setcom keycmd: mvi a,cmkey call comnd jmp keycm2 ;no match ret keycm2: lxi d,ermes1 ;"Unrecognized Command" call prtstr jmp kermit ;Do it again. ; request confirmation; if unsuccessful, return to command level ; called by: bye, exit, help, log, setcom, show, status, send, ; finish, logout, xmit, telnet cfmcmd: mvi a,cmcfm call comnd jmp kermt3 ;"Not confirmed" ret ; ; This routine prints the number in HL on the screen in decimal. ; Uses all ACs. ; called by: cp4sys, read, send, updrtr, dir nout: lxi b,-10 ;Get some useful constants. nout1: lxi d,-1 nout2: dad b ;Subtract as many 10s as possible. inx d ;Count them.  jc nout2 ;If some left keep going. push h ;save remainder - 10 xchg ;Swap the remainder and the quotient. mov a,h ;Get the number of 10s found. ora l ;check for quotient non zero cnz nout1 ;If non zero, recurse. pop h ;Get the remainder - 10 mov a,l ;in a adi '0'+10 ;Make the number printable and add the 10 back mov e,a ;Output the digit. mvi c,conout jmp bdos ; prcrlf - print a CR/LF. (Saves no registers.) [Toad Hall] ; prtstr - print string pointed to by DE ; called by: lots of places. prcrlf: lxi d,crlf ;Point to the CR/LF prtstr: mvi c,prstr ; output string jmp bdos ;a CALL followed by a RET becomes a JMP ; Jumping to this location is like retskp. It assumes the instruction ; after the call is a jmp addr. ; here from: many places. rskp: pop h ;Get the return address. inx h ;Increment by three. inx h inx h pchl ; Jumping here is the same as a ret. 'jmp r' is used after routines ; that have skip returns, where the non-skip instruction must be 3 bytes. ; here from: many places. r: ret ; ; Open a file for reading (with inbuf). The filename is already ; in fcb; upon return, the end of file flag is cleared and chrcnt ; is set to zero, so inbuf will be called to get a buffer when we ; next attempt to get a character. ; called by: sinit, seof, xmit getfil: xra a sta chrcnt ;Buffer is empty. sta seccnt ;No sectors buffered. sta eoflag ;Not the end of file. sta endsts ;No EOF/error pending. sta fcb+0CH ;Zero the extent. sta fcb+0EH ;Must be zero for MAKEF or OPENF. sta fcb+20H ;Zero the current record. mvi c,openf ;Open the file. lxi d,fcb call bdos ret ; Get next sector. If necessary, read some more from disk. ; preserves bc, de, hl ; returns nonskip if EOF or error; ; returns skip with chrcnt and bufpnt updated if success. ; called by: gtchr, xnext inbuf: lda eoflag ;Have we reached the end? ora a rnz ;Return if so. push b push d push h inbuf1: lda seccnt ; Do we have any sectors left? ora a jz inbuf3 ; If not, go get some more. inbuf2: lhld nxtbuf ; Yes. Get address of next sector shld bufpnt ; Update current buffer pointer lxi b,bufsiz ; Get number of bytes in sector dad b ; Update HL to point to next sector shld nxtbuf ; Save for next time dcr a ; Decrement count of buffered sectors sta seccnt ; Put it back mvi a,bufsiz-1 ; Number of bytes in buffer (pre-decremented) sta chrcnt ; Store for our caller pop h pop d pop b jmp rskp ; Return success ; We don't have any sectors buffered. If we've already hit an error or ; EOF, return that status to the user. inbuf3: lda endsts ; Check status from previous read ora a jz inbuf4 ; It was OK. Get some more sectors. sta eoflag ; End of file or error. Set the flag. xra a sta chrcnt ; Say no characters in buffer. pop h pop d pop b ret ; Return failure ; Read sectors until we fill the buffer or get an error or EOF, then return ; the first buffer to the user. (seccnt is zero) inbuf4: lhld bufadr ; Get address of big buffer shld nxtbuf ; Store as next buffer address to give user inbuf5: shld bufpnt ; Store as next buffer address to read into xchg ; Move buffer address to DE mvi c,setdma ; Tell CP/M where to put the data call bdos ; ... mvi c,readf ; Read a record. lxi d,fcb call bdos sta endsts ; Save ending status ora a ; 00H => read O.K jnz inbuf6 ; EOF/error: stop reading. lxi h,seccnt ; Success. Get addr of sector count inr m ; Bump sector count by one lda bufsec ; Get max number of sectors in buffer cmp m ; Are we there yet? jz inbuf7 ; Yes, can't read any more. lhld bufpnt ; No, try for another. Get buffer address, lxi d,bufsiz ; and size of sector, dad d ; giving next buffer address in HL jmp inbuf5 ; Go read another sector. ; We hit EOF or got an error. Put the DMA address back where it belongs, ; then go see if we have any sectors (before the one that got the error) ; to return to the caller. Nxtbuf points to the first good sector, if ; any; seccnt contains the count of good sectors. inbuf6: call rstdma jmp inbuf1 ; Go see if we have some data to return ; We've filled the big buffer. Reset the DMA address, then go return a ; sector to the caller. nxtbuf points to the beginning of the buffer; ; seccnt contains the number of sectors successfully read (except that ; if we've read 256 sectors, seccnt contains zero, so we can't just go ; to inbuf1). inbuf7: call rstdma ;[pcc012] lda seccnt ; Get sector count again. jmp inbuf2 ; Return a sector. ; ;[pcc012] ; appfil - Create or append to an existing file. File name is in FCB. ; Non-skip return if could not be done. Skip return with file ; open and bufpnt pointing to end of file. ; called by logopn appfil: xra a ;[pcc012] zero out stuff for open sta fcb+0CH ;[pcc012] extent sta fcb+0EH ;[pcc012] Must be zero for MAKEF or OPENF. sta fcb+20H ;[pcc012] Zero the current record. mvi c,openf ;[pcc012] Try to open the file lxi d,fcb ;[pcc012] call bdos ;[pcc012] cpi 0FFH ;[pcc012] Did we find it? jz makfi1 ;[pcc012] If not, go create it mvi c,cflsz ;[pcc012] Compute the file size lxi d,fcb ;[pcc012] call bdos ;[pcc012] lhld fcb+21H ;[pcc012] random record pointer mov a,h ;[pcc012] See if zero length file ora l ;[pcc012] jz makfi2 ;[pcc012] set up pointers if null file dcx h ;[pcc012] backup to last record written shld fcb+21H ;[pcc012] store rec ptr back lhld bufadr ;[pcc012] get buffer address xchg ;[pcc012] to DE mvi c,setdma ;[pcc012] set dma address call bdos ;[pcc012] for read mvi c,rrand ;[pcc012] read the last block lxi d,fcb ;[pcc012] call bdos ;[pcc012] ora a ;[pcc012] check results jnz rstdma ;[pcc012] reset dma and return if error lhld bufadr ;[pcc012] get address again lxi d,bufsiz ;[pcc012] and and size mvi a,'Z'-40H ;[pcc012] control-Z for comparison appcz: cmp m ;[pcc012] Is this the EOF? jz appxit ;[pcc012] Jump if yes inx h  ;[pcc012] no, bump dcr e ;[pcc012] and grind jnz appcz ;[pcc012] until find or buffer empty appxit: shld bufpnt ;[pcc012] store buffer pointer dad d ;[pcc012] compute next buffer adr shld nxtbuf ;[pcc012] and store mov a,e ;[pcc012] updated chr count sta chrcnt ;[pcc012] xra a ;[pcc012] reset sector count sta seccnt ;[pcc012] call rstdma ;[pcc012] reset normal dma jmp rskp ;[pcc012] and give good return ; Create a file, deleting any previous version. The filename is in ; fcb. ; Returns nonskip if file could not be created. ; If successful, takes skip return with bufpnt and chrcnt initialized ; for output; buffers should be output via outbuf. ; called by: gofil makfil: mvi c,delf ; delete the file if it exists. lxi d,fcb call bdos xra a sta fcb+0CH ; zero the extent. sta fcb+0EH ; must be zero for MAKEF or OPENF. sta fcb+20H ; zero the current record. ;[pcc012] here from appfil above if file does not exist makfi1: mvi c,makef ;[pcc012] now create it. lxi d,fcb call bdos cpi 0FFH ; is the disk full? rz ; take error return if so. ; success. set up pointers and counters for multisector buffering. ;[pcc012] also here from appfil if found zero length file makfi2: lhld bufadr ;[pcc012] find beginning of buffer space. shld bufpnt ; make it current buffer. lxi d,bufsiz ; get sector size. dad d ; find beginning of next buffer. shld nxtbuf ; store for later. mov a,e ; store buffer size sta chrcnt ; for caller. xra a sta seccnt ; no sectors stored yet. jmp rskp ; take success return. ;[pcc012] ; outadv - conditionally advance output buffer if disk write not needed. ; preserves BC ; skip return with with next output buffer set up ; non-skip return if memory buffer full and must write to disk. ; called by:logit outadv: push b ;[pcc012] save BC as advertised lxi h,seccnt ;[pcc012] point to sectors buffered inr m ;[pcc012] count this one lda bufsec ;[pcc012] how many we can hold cmp m ;[pcc012] check if full jnz outbf2 ;[pcc012] continue if not dcr m ;[pcc012] full, un-advance sector count pop b ;[pcc012] restore bc ret ;[pcc012] and give non-skip return ; get a fresh output buffer, flushing big buffer if necessary. ; returns nonskip if disk full. ; if successful, returns skip with bufpnt and chrcnt updated. Note ; that chrcnt holds one less than the buffer size. ; preserves BC. ; called by: ptchr,logwrt outbuf: push b lxi h,seccnt ; count another buffered sector inr m ; ... lda bufsec ; get number of sectors we can hold cmp m ; full? jnz outbf2 ; if not, set up pointers and return call outmbf ; flush the big buffer jmp outbf9 ; disk error. ;[pcc012] also here from outadv to advance buffer outbf2: lhld nxtbuf ; get pointer to fresh buffer shld bufpnt ; store for caller lxi d,bufsiz ; advance our pointer to next buffer dad d shld nxtbuf mvi a,bufsiz-1 ; get buffer size (pre-decremented) sta chrcnt ; store for caller pop b jmp rskp ; return success. outbf9: pop b ; clean up stack ret ; and take error return. ; flush incore output buffers. ; returns nonskip if disk full. ; if successful, returns skip with nxtbuf reset to start of buffer and ; seccnt zero. ; destroys all ac's. ; called by: outbuf, clofil. outmbf: lhld bufadr ; get start of buffer shld nxtbuf ; store for next fill cycle shld bufpnt ; store for empty loop outmb2: lhld bufpnt ; get address of current sector xchg ; into DE lxi h,bufsiz ; advance HL to next sector dad d ; ... shld bufpnt ; and store for later mvi c,setdma call bdos ; point CP/M at current sector lxi d,fcb mvi c,writef call bdos ; output the sector ora a ; test for error (A non-zero) jnz rstdma ;[pcc012] reset dma and take nonskip return if so lxi h,seccnt dcr m ; count down buffered sectors jnz outmb2 ; loop if more saved call rstdma ;[pcc012] restore normal dma jmp rskp ; return success. ; output current buffer, flush incore buffers, and close output file. ; returns nonskip if disk full; skip if successful. ; called by: rdata clofil: lda chrcnt ; get the number of chars left in the buffer. cpi bufsiz ; Virgin buffer? jz clofl3 ; yes, don't output it. lhld bufpnt ; get the buffer pointer. clofl1: dcr a ; lower the count. jm clofl2 ; if full then stop. mvi m,'Z'-100O ; put in a ^Z for EOF. inx h ; point to the next space. jmp clofl1 clofl2: call outbuf ; output the last buffer. jmp r ; give up if the disk is full. clofl3: lda seccnt ; any sectors buffered in memory? ora a jz clofl4 ; if not, don't try to flush. call outmbf ; flush buffers jmp r ; disk full. clofl4: mvi c,closf ; close up the file. lxi d,fcb call bdos jmp rskp ; return success. ; Reset DMA address to the default buffer ; called from inbuf,appfil,outmbf rstdma: lxi d,buff ;[pcc012] mvi c,setdma ;[pcc012] jmp bdos ;[pcc012] ; version:db 'Kermit-80 v4.' db (verno/10) + '0' ; tenth's digit of version number db (verno MOD 10) + '0' ; hundredth's digit db ' $' kerm: db 'Kermit-80 ' kerm1: db 'x:>$' ;'x' filled in at startup with DRIVE name crlf: db cr,lf,'$' ermes1: db cr,lf,'?Unrecognized command$' ermes3: db cr,lf,'?Not confirmed$' ermes4: db '?Unable to receive initiate',cr,lf,'$' ermes5: db '?Unable to receive file name',cr,lf,'$' ermes6: db '?Unable to receive end of file',cr,lf,'$' erms10: db '?Unable to receive data',cr,lf,'$' erms11: db '?Disk full',cr,lf,'$' erms14: db '?Unable to receive an acknowledgement from the host',cr,lf,'$' erms15: db cr,lf,'?Unable to find file',cr,lf,'$' erms16: db '?Unable to rename file$' erms17: db cr,lf,'?Disk full$' erms18: db cr,lf,'?Unable to tell host that the session is finished$' erms19: db cr,lf,'?Unable to tell host to logout$' erms20: db cr,lf,'?Kermit has not been configured for a target system$' erms21: db cr,lf,'?Consistency check on configuration failed$' erms22: db cr,lf,'?Error writing to log file',cr,lf,'$' ;[pcc005] infms3: db bell,'Completed$' infms4: db bell,'Failed$' infms5: db '%Renaming file to $' infms6: db cr,lf,'[Closing the log file]$' infms7: db cr,lf,'[Connected to remote host. Type $' infms8: db 'C to return;',cr,lf,' type $' inms8a: db '? for command list]',cr,lf,'$' infms9: db cr,lf,'[Connection closed, back at micro]$' inms10: db 'Control-$' inms12: db ' (Not implemented)',cr,lf,'$' inms13: db bell,'Interrupted$' inms14: db TAB,TAB,' Directory for drive ' dnam14: db 'x:',cr,lf,'$' ;filled in by dir routine. inms15: DB CR,LF,TAB,TAB,'Drive $' inms16: DB ' has $';filled in by summary code with drive letter inms17: DB 'K bytes free',CR,LF,'$' inms18: DB CR,LF,'File(s) erased$',CR,LF inms19: db cr,lf,'[Transmitting file to host:' db cr,lf,' 1. Type any character to send a line.' db cr,lf,' 2. Type RETURN to terminate the line ' db 'and to get the next line (go back to 1.)' db cr,lf,' (You may send other characters ' db 'before RETURN.),' db cr,lf,' or type $' inms20: db 'R to send the same line again,' db cr,lf,' or type $' inms21: db 'C to abort transmission.]',cr,lf,'$' inms22: db cr,lf,'[Transmission done. Connected normally ' db 'to remote host,' db cr,lf,' type $' inms23: db 'Sending...$' inms24: db 'Receiving...$' inms25: db bell,'Warning: eighth bit cannot be sent$' inms26: db cr,lf,'For help, type ? at any point in a command$' inms27: db cr,lf,'[Logging suspended]',cr,lf,'$' ;[pcc003] inms28: db cr,lf,'[Logging resumed]',cr,lf,'$' ;[pcc003] escmes: db cr,lf,'Type the new escape character: $' tacmes: db cr,lf,'Type the new TAC intercept character: $' xmthlp: db cr,lf,'R Send the same line again$' loghlp: db cr,lf,'Q Suspend logging' ;[pcc003] db cr,lf,'R Resume logging$' ;[pcc003] inthlp: db cr,lf,'? This message' db cr,lf,'C Close the connection' db cr,lf,'0 (zero) Transmit a NULL' db cr,lf,'P Toggle printer on/off' ;[pcc002] db cr,lf,'S Status of the connection$' inhlp1: db cr,lf,'Typing another $' inhlp2: db ' will send it to the host' db cr,lf,cr,lf,'Command>$' xmtst: db cr,lf,'Transmitting a file$' locst: db cr,lf,'Local echo$' onstr: db ' on$' offstr: db ' off$' vtemst: db cr,lf,'VT52 emulation$' cpmst: db cr,lf,'File Mode$' defstr: db ' default$' ascstr: db ' ASCII$' binstr: db ' binary$' ibmst: db cr,lf,'IBM flag$' filst: db cr,lf,'File warning$' prst: db cr,lf,'Printer copy$' logst: db cr,lf,'Logging is$' ;[pcc003] susstr: db ' suspended$' ;[pcc003] escst: db cr,lf,'Escape char: $' bckst: db cr,lf,'Block check type: $' bckst1: db '-character$' parst: db cr,lf,'Parity: $' pnonst: db 'none$' pmrkst: db 'mark$' pspcst: db 'space$' poddst: db 'odd$' pevnst: db 'even$' porst: db cr,lf,'Port in use is: $' spdst: db cr,lf,'Current baud rate is: $' spdust: db 'indeterminate (not SET)$' timmsg: db 'Timer$' tacst: db cr,lf,'Current TACTrap Status/Intercept Character: $' cmer00: db cr,lf,'?Program error: Invalid COMND call$' cmer01: db cr,lf,'?Ambiguous$' cmer02: db cr,lf,'?Illegal CP/M file specification$' cmer03: db cr,lf,'?Wild-cards not allowed in file specification$' ;[pcc006] cmin00: db ' Confirm with carriage return$' ; ;Impure data ;COMND storage cmstat: ds 1 ;What is presently being parsed. cmaflg: ds 1 ;Non-zero when an action char has been found. cmccnt: ds 1 ;Non-zero if a significant char is found. cmsflg: ds 1 ;Non-zero when the last char was a space. cmostp: ds 2 ;Old stack pointer for reparse. cmrprs: ds 2 ;Address to go to on reparse. cmprmp: ds 2 ;Address of prompt. cmptab: ds 2 ;Address of present keyword table. cmhlp: ds 2 ;Address of present help. cmdbuf: ds 80H ;Buffer for command parsing. cmfcb: ds 2 ;Pointer to FCB. cmfcb2: ds 2 ;Pointer to position in FCB. cmfwld: ds 1 ;Wildcard flag cmcptr: ds 2 ;Pointer for next char input. cmdptr: ds 2 ;Pointer into the command buffer. cmkptr: ds 2 ;Pointer to keyword. cmsptr: ds 2 ;Place to save a pointer. ; oldsp: ds 2 ;Room for old system stack. ds 40H ;Room for 32 levels of calls. stack: ds 2 eoflag: ds 1 ;EOF flag;non-zero on EOF. curdsk: db 0 ;holds "logged" disk prtcnt: db 0 ;[pcc008] prtchr fairness count timflg: db 0 ;[jd] timer flag: 0 -> no timer timval: dw 0 ;[jd] timer value wrn8: db 0 ;[jd] non-zero if 8-bit-lost warning sent qbchr: db '&' ;[jd] binary quote character. quot8: db 0 ;[jd] non-zero if doing 8-bit quoting logflg: db 0 ;Flag for a log file. ;[pcc005] 0 = no log ;[pcc005] x1 = logging on ;[pcc005] x2 = suspended ;[pcc005] 8xH (bit 7) = file open lognam: db 0 ;[pcc013] File to use for session logging db 'KERMIT ' ;[pcc013] db 'LOG' ;[pcc013] escflg: db 0 ;Escape flag (start off). fileio: db 0 ;Line-by-line from file (default off). xofflg: db 0 ;X-OFF (=^S) received from COMM-line ; ;X-ON (=^Q) received resets this vtyval: ds 1 ; holds row number for VT52 cursor positioning chrcnt: ds 1 ;Number of chars in the file buffer. filcnt: ds 1 ;Number of chars left to fill. outpnt: ds 2 ;Position in packet. bufpnt: ds 2 ;Position in file buffer. fcbptr: ds 2 ;Position in FCB. datptr: ds 2 ;Position in packet data buffer. cbfptr: ds 2 ;Position in character buffer. pktptr: ds 2 ;Position in receive packet. size: ds 1 ;Size of data from gtchr. curchk: ds 1 ;Current checksum type inichk: ds 1 ;Agreed upon checksum type czseen: ds 1 ;Flag that control-Z was typed pktnum: ds 1 ;Packet number. numpkt: ds 2 ;Total number of packets sent. numrtr: ds 2 ;Total number of retries. numtry: ds 1 ;Number of tries on this packet. oldtry: ds 1 ;Number of tries on previous packet. state: ds 1 ;Present state of the automaton. packet: ds 4 ;Packet (data is part of it). data: ds 5AH ;Data and checksum field of packet. recpkt: ds 65H ;Receive packet storage (use the following). recpkx: db cr,'$' ;= = = buffer limit filbuf: ds 65H ;Character buffer. fnbuf: ds 20h ;[jd] file name buffer ;** Temp 1 & 2 must be in order temp1: ds 1 ;Temporary storage. lstchr EQU temp1 ;Last console input character. temp2: ds 1 temp3: ds 1 temp4: ds 1 argblk: ds 20H ;Used for subroutine arguments maxfil EQU 2 ; currently, only two names used. fcbblk: ds maxfil*10H ;Used for a list of FCB's ; Bookkeeping storage for multiple-sector buffering. The actual buffer ; is somewhere in the system-dependent overlay. (at the end, I hope). nxtbuf: ds 2 ; Pointer to next sector seccnt: ds 1 ; Number of sectors buffered endsts: ds 1 ; Status for last read into buffer patch: ds 100 ; Guarantee some patch space ORG ($ + 0ffH) AND 0ff00H ; move to start of next page ; ; hooks for system-dependent routines: ; This area is overwritten by the system-dependent overlay. ; lnkflg: dw 0 ; linkage information for consistency check. lnkent: dw 0 ; more of the same. ovlver: dw 0 ; pointer to overlay's version string ; ; Input/output routines. Note that outmdm and outcon may actually be the ; same routine if selmdm and selcon do anything. (the same is true ; of inpmdm and inpcon). ; selmdm: jmp $-$ ; select modem for I/O outmdm: jmp $-$ ; output character in E to modem inpmdm: jmp $-$ ; read character from modem. return character or 0 in A. flsmdm: jmp $-$ ; flush pending input from modem selcon: jmp $-$ ; select console for I/O outcon: jmp $-$ ; output character in E to console inpcon: jmp $-$ ; read char from console. return character or 0 in A outlpt: jmp $-$ ; output character in E to printer ; ; screen formatting routines clrlin: jmp $-$ ; erase current line clrspc: jmp $-$ ; erase current position (after backspace) delchr: jmp $-$ ; make delete look like backspace clrtop: jmp $-$ ; erase screen and go home ; ; these routines are called to display a field on the screen. scrend: jmp $-$ ; move to prompt field screrr: jmp $-$ ; move to error message field scrfln: jmp $-$ ; move to filename field scrnp: jmp $-$ ; move to packet count field scrnrt: jmp $-$ ; move to retry count field scrst: jmp $-$ ; move to status field rppos: jmp $-$ ; move to receive packet field (debug) sppos:  jmp $-$ ; move to send packet field (debug) ; sysinit: jmp $-$ ; program initialization sysexit: jmp $-$ ; program termination syscon: jmp $-$ ; remote session initialization syscls: jmp $-$ ; return to local command level sysinh: jmp $-$ ; help text for interrupt (escape) extensions sysint: jmp $-$ ; interrupt (escape) extensions, including break sysflt: jmp $-$ ; filter for incoming characters. ; called with character in E. sysbye: jmp $-$ ; terminate remote session sysspd: jmp $-$ ; baud rate change routine. ; called with value from table in DE sysprt: jmp $-$ ; port change routine. ; called with value from table in DE sysscr: jmp $-$ ; screen setup for file transfer ; called with Kermit's version string in DE csrpos: jmp $-$ ; move cursor to row B, column C sysspc: jmp $-$ ; calculate free space for current disk mover: jmp $-$ ; block move ; ; Data initialized by system-dependent overlay: ; pttab: ds 2 ; points to local equivalents to VT52 escape sequences spdtab: ds 2 ; address of baud rate command table, or zero spdhlp: ds 2 ; address of baud rate help table, or zero prttab: ds 2 ; address of port command table, or zero prthlp: ds 2 ; address of port help table, or zero timout: ds 2 ; Initial value for fuzzy timeout vtflg: ds 1 ; VT52 emulation flag escchr: ds 1 ; Storage for the escape character. speed: ds 2 ; storage for the baud rate port: ds 2 ; storage for port value prnflg: ds 1 ;[hh] printer copy flag (overlay may need it) dbgflg: ds 1 ; debugging flag ecoflg: ds 1 ; Local echo flag (default off). flwflg: ds 1 ; File warning flag (default on). ibmflg: ds 1 ; IBM flag (default off). cpmflg: ds 1 ; File mode flag (ascii/binary/default) parity: ds 1 ; Current parity. spsiz: ds 1 ; Send packet size. rpsiz: ds 1 ; Receive packet size. stime: ds 1 ; Send time out. rtime: ds 1 ; Receive time out. spad: ds 1 ; Send padding. rpad: ds 1 ; Receive padding. spadch: ds 1 ; Send padding char. rpadch: ds 1 ; Receive padding char. seol: ds 1 ; Send EOL char. reol: ds 1 ; Receive EOL char. squote: ds 1 ; Send quote char. rquote: ds 1 ; Receive quote char. chktyp: ds 1 ; Checksum type desired tacflg: ds 1 ; TACTrap flag (zero=off, nonzero=on; when non-zero, ; contains current TAC intercept character) tacchr: ds 1 ; TAC intercept character bufadr: ds 2 ; Pointer to big buffer for multiple-sector I/O bufsec: ds 1 ; Number of sectors big buffer can hold (0 means 256) ffussy: ds 1 ; if nonzero, don't permit <>.,;?*[] in CP/M filespec. ; space used by directory command; here because space calculation is ; (operating) system-dependent bmax: ds 2 ; highest block number on drive bmask: ds 1 ; (records/block)-1 bshiftf: ds 1 ; number of shifts to multiply by rec/block nnams: ds 1 ; counter for filenames per line lnksiz equ $-lnkflg ; length of linkage section, for consistency check. END START rpad: ds 1 ; Receive padding. spadch: ds 1 ; Send padding char. rpadch: ds 1 ; Receive padding char. seol: ds 1 ; Send EOL ch; CP4WLD.ASM ; KERMIT - (Celtic for "FREE") ; ; This is the CP/M-80 implementation of the Columbia University ; KERMIT file transfer protocol. ; ; Version 4.0 ; ; Copyright June 1981,1982,1983,1984 ; Columbia University ; ; Originally written by Bill Catchings of the Columbia University Center for ; Computing Activities, 612 W. 115th St., New York, NY 10025. ; ; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben, ; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many ; others. ; ; Multi-file access subroutine. Allows processing of multiple files ; (i.e., *.ASM) from disk. This routine builds the proper name in the ; FCB each time it is called. This command would be used in such pro- ; grams such as modem transfer, tape save, etc. in which you want to ; process single or multiple files. ; Note that it will fail if more than 256 entries match the wildcard. ; ; revision history: ; edit 3: July 27, 1984 ; support LASM: remove exclamation points, link to CP4CMD. ; ; edit 2: June 7, 1984 (CJC) ; formatting and documentation; add module version string; redo movfcb, ; in preparation for moving DMA buffer (later...). ; ; edit 1: May, 1984 (CJC) ; extracted from CPMBASE.M80 version 3.9; modifications are described ; in the accompanying .UPD file. ; wldver: db 'CP4WLD.ASM (3) 27-Jul-84$' ; The FCB will be set up with the next name, ready to do normal ; processing (OPEN, READ, etc.) when routine is called. ; ; Carry is set if no more names can be found ; ; MFFLG1 is count/switch [0 for first time thru, pos for all others] ; MFFLG2 is counted down for each successive GETNEXT file call ; ; Technique used is to repeat SFIRST/SNEXT sequence N+1 times for each ; successive call, till sequence fails. CP/M does NOT allow disk-handling ; between SFIRST and SNEXT. ; called by: send, seof, dir mfname: ora a ; clear carry push b ;Save registers push d push h mvi c,setdma ;Init DMA addr, FCB lxi d,80H call bdos xra a ;A = 0 sta f!cbext ;clear extension lda mfflg1 ;find out if "second" call in row ora a jnz mfn01 ;Were here before sta mfflg2 lxi h,fcb lxi d,mfreq lxi b,12 call mover ;.from FCB to MFREQ mvi c,SFIRST ;Search first lxi d,fcb call bdos jmp mfn02 ;and check results mfn01: dcr a sta mfflg2 ;store down-counter lxi h,mfreq ;SFIRST REQ name lxi d,fcb lxi b,12 call mover ;.from MFREQ to FCB mvi c,sfirst ;Search first old one,we got it before lxi d,fcb call bdos ;no error's expected -we got that before mfn01a: mvi c,snext ;Search next call bdos mfn02: push psw lda mfflg2 ;get "repeat file counter" ora a jz mfn02a ;if zero, check if SNEXT had ERROR dcr a ;count down sta mfflg2 ;store back pop psw ;no error-check, we got it before jmp mfn01a ;next SNEXT mfn02a: pop psw ora a jm mffix2 ;No (more) found call movfcb ;move data to fcb lda mfreq ;the original disk-designator sta fcb ;back into fcb lda mfflg1 ;get file-flag inr a ;increment sta mfflg1 ;and store for next go-around mvi a,0 ;Setup FCB sta fcbext ;clean up FCB for OPEN etc sta fcbrno mffix1: pop h ;restore registers pop d pop b ret ;and return mffix2: stc ;set carry jmp mffix1 ;return with CARRY set ; copy directory entry to FCB ; called with A/ entry number in directory (0-3) ; directory block in DMA buffer (buff) movfcb: add a add a add a add a add a ;* 32 mov c,a ; copy offset to bc mvi b,0 ; (high byte is zero) lxi h,buff ; get start of disk buffer dad b ; calculate start of directory entry lxi d,fcb lxi b,12 call mover ret ; Data storage for MFNAME (multi-file access) mfreq: DS 12 ;Requested name mfflg1: DB 0 ;First time thru flag for MFNAME mfflg2: DB 0 ;Down counter for MFNAME ; IF lasm LINK CP4CMD ENDIF;lasm ove data to fcb lda mfreq ;the original disk-designator sta fcb ;back into fcb lda mfflg1 ;get file-flag inr a ;incr1MÚLINKASM AS OF 7/06/81 RESEARCH SIDXREF1D00 $10 !~=W!xe ~M4M4z~#o}o҃.ASMg> >ک!PRNq*DM͡:͆ ͆2:`!HEX!:*&!w_#~ A:~J~# > J\ ?!w#J0> J> J! ! !6 ::::! :l2:] !2!d222!!̓͌fk:ʢ!͓fkâ!"22|-!I z{**|!" !Msw# dMҖ6# xM*#"~ ̑!` G:ʽx¶JýͿ*!M'w#"!*͌!"!M'~~#  !w  *!M+w#"!*͓!"!M+_O͟: :yJ:!ʁG~W#x=r2> W> W!>x6 #=“G!~ p̓ʻ*}ʻ>͟ë::p*f"n*}>̓͌U:͓U:=2!22͌fk!"! C͜A Wx[H!O4gy͍Z:c:d~O#~zʅ+}|#͓T]͓##x G###* |~_##N#~y~͵#½> ͵> ͵##~#foß> õ*}>͌͟UƐ'@'õSYMBOLS ! No source file present No directory space Source file name error Source file read error Output file write error Cannot close files End of assembly G:x!p~*f*nO {z*f"n!p^4!qwWƐ'@'>:!p^Ww*n{|}{N!q~#E> > 0 ʅ ʅ:x҅_<2!w͞2_2> 2^l>2ɯ2 2`! ~@ڴ6z ^4#:_w~$w:_0 :_A:_A:_a{_2_a2_: !ɯ2͞:_ P;=*I:^ IV= V#a>Õl>Õ:_'}2_>Õ “:el!6 >2>2:_2^Ħ:!_:ͿʘØ^ Ϳʘ˜:_OQ>H>2`2_ :^B > D>  ! 52`!"! N#~#A. 00 7O!`t ~*!S M )D " " :_ z '˜'Ø>VÀ >OÀ ͛!M3w#w# !"l! F#¤ 2 G*l##~w*l##~<*l}͟ ! ~ 6! ^!M3^#fk"l ͼ !  G#*l### # *l^#V ! ^*c"l*{zo "c*l! N!M3 N#Fr+sq#p ] >G=#w#wa #w#w!x åSymbol table overflow G*l##~w*l##~ͼ *l_###ͭ s#rͭ ^#V  4   z ()*+,-/ABCDEHLMDBDIDSDWEIIFINORSPACIADCADDADIANAANDANICMACMCCMPCPIDAADADDCRDCXENDEQUHLTINRINXJMPLDALXIMODMOVMVINOPNOTORAORGORIOUTPOPPSWRALRARRETRLCRRCRSTSBBSBISETSHLSHRSTASTCSUBSUIXORXRAXRICALLLDAXLHLDLINKPCHLPUSHSHLDSPHLSTAXXCHGXTHLENDIFMACROTITLE  PF FP! ( 2/?'  v:P@< !  PP27 ( *"  NZZ NCC POPEP M x _BH!¿ !# { Kë Cë <:!JCR: "0  0 !#6  !"( #  ɯ<: O=_} ! F! V#fjQͦ h ! ^#Vo&)~#F xGyѯ<*}|̈́ ":N!̈́ ! ~ڷ ͚6~44O! s#r! ~ 6͚^4! w! p! ~ ͚!55N! N#fi o&)^#fk z<{͚>ɯo>g"!6ů{_zW5>)D*OxGy !?[DM!xGyOڗØ)È̓è Jè Jè 0ʨ )=÷0ʨ |g}o=è B Bè #zg{oè zg{oè zg{oè ::! ;,!ɯ2 2 =2 !"ar! ~]5_! ~ E: Ě: * "a: ”:ž: ̚Ԛ!!^#=ʚVÆ©*Æ3 F; O: ̚>2 y#: _! ~! s! ~ y ! ~=w_! ~ ͚ >2 Ôyʔ3P͛ Ã͠ >Ư : ̚2 ͨ ?>E͛ɯ2e͊ ͇! 2p!""f"h"::!*ªͲ3 <  :eĉ͠ ͕*}ď*l"::!:PX!O^#fkg!$ Gͼ:˜: =ʘG!!ʒF#Âç.*a|ăEͫ3,jêͼXJ*h"h"fêͼJEDͫ3,êͼX: ªJ: "> 2::! J!!: qG> qOw#= O6 #E:_q O p# =O!} l++ERROR IN LINK OPERAND++ Ͳ*hJ"hͼ[!6="hêͼJ: ª}ڪ::!>B̛3 xJ͕êJ: ª"h"fͼXêͲ͠ ď>͎ JͲͻ !"ê͕ê!_!d^#fk*u͐͊*u*k8ʪoy0'͊*kG͐`'k͐̈́*̈́*k(oy'͊*`'k'koy0'k'̈́*ͼͫê:ă:!,; ă.*aJ|y}Vy`8Okoy0VJ&:¢:!,ʧ>C͛ͼ::! ;ͼ::! !!>S͛{ozg!e~4ʩX!6 ! *c*j**j\M[!O]w#DH use factor ! *"f!x#~ l å input lines read :e> !~~0 60+Û*f"h*"l Ͳ!":e͠ ď͎ *hͻ ͠ ̉ *h*ĉG:exͲ: *h[:xH*f#"fED0:0!^4!w88*h!6zH{H4>R͛>V͛>DØ>PØ>LØ>N͕͛êJ: ª"h"fͼXêͲ͠ ď>͎ JͲͻ !"ê͕ê!_!d^#fk*u͐͊*u*k8ʪoy0'͊*kG͐`'k͐̈́*̈́*k(oy'͊*`'k'koy0'k'̈́*ͼͫê:ă:!,; ă.*aJ|y}Vy`8Okoy0VJ&:¢:!,ʧ>C͛ͼ::! ;ͼ::! !!>S͛{o***************************************************************** * * * 10/01/81 * * * * LASM is an update of LINKASM, with the minor change that * * it prints the name of each linked file before it is opened. * * This helps track progress, and helps find misspelled names. * * * * -Ward Christensen * * * ***************************************************************** LINKASM.COM 01/07/80 by Ward Christensen OVERVIEW: LINKASM is based on CP/M assembler 1.0, and is compatible with 1.0, 1.3, and 1.4 assemblers. (2.0? Dunno.) ---------------- LINKASM is a rewrite of CP/M 1.0 ASM.COM, incorporating: * A new pseudo-op code, LINK. * Smaller .COM file size (6K vs 8K). * Faster execution via larger ASM, HEX, and PRN buffers * Corrections to properly handle lower case DB values. * Prints the number of source lines read * Produces a symbol table for use under SID The LINK pseudo-op allows a file to "chain" to the next .ASM file, thereby allowing very large source files to be processed without having to PIP them together. RESTRICTIONS: All the linked .ASM files must be on the same disk. Nested IFs are not handled (ASM.COM didn't either) Note that you can use IF to conditionally link to the next module: IF CLOCK LINK CLOCKRTN ENDIF ; IF NOT CLOCK LINK OTHERRTN ENDIF For example, if CLOCK is true, then LINK CLOCKRTN (i.e. CLOCKRTN.ASM) will take place, and the assembler will never see the ENDIF. This is not a problem as the next encountered IF will be handled properly. ---------------- USAGE: LINKASM is totally compatible with ASM.COM, and you may therefore replace ASM. Its performance will be slig#htly better than ASM.COM, and it takes less space on disk (6K vs 8K). Execute it just like ASM.COM, i.e. LINKASM name.p1p2p3 where: p1 is the .ASM file disk (A, B, ...) p2 is the .HEX file disk (A, B, ... or Z for none) p3 is the .PRN file disk (A, B, ... or Z for none, or X for the console) The default is the logged in disk for all 3. If you wish to write a symbol table file, follow the command line with the disk to be written to (A, B, ...) then a colon. For example, to assemble FOO from the A: disk, put the .HEX on the A: disk, send the .SYM file to B:, and the listing to the console: LINKASM FOO.AAX B: To assemble it doing everything on the A: disk (assuming A: is the logged in disk): LINKASM FOO A: The ":" must be specified after the .SYM disk. The .SYM file is "partially" sorted, i.e. all Axxxx then all Bxxxx etc. SID fully scans the symbol table anyway, so sorting it is not necessary, so I did this quick sort hack just to make it eaiser for YOU to find a symbol. ---------------- The LINK pseudo ops take a single operand: the name of an .ASM file to be processed next. For example: ---------------- A:TEST1.ASM: ORG 100H LXI H,MSG MVI C,9 CALL BDOS RET LINK TEST2 ---------------- A:TEST2.ASM: MSG DB 'Linked' BDOS EQU 5 ---------------- Then assemble it: A>LINKASM TEST1.AZX LINKASM AS OF 7/13/79 0100 ORG 100H 0100 210901 LXI H,MSG 0103 0E09 MVI C,9 0105 CD0500 CALL BDOS 0108 C9 RET LINK TEST2 0109 4C696E6B65MSG DB 'Linked' 0005 = BDOS EQU 5 010F 000H use factor 8 input lines read End of assembly ---------------- I will make one apology for LINKASM - I neglected to put in an error message saying the name of the missing file, if you should accidentally LINK to a non-existant file. It just says the source file is not present. If necessary, you can find the name which was being searched for. It's in memory at 186H. If you have a PROM monitor, you can examine it. If not, do the following BEFORE executing any more COM programs following the LINKASM: SAVE 1 BADNAME.COM Save 100-1ff to disk DDT BADNAME.COM Bring in under DDT (or SID) D186,190 Dump the name ^C Reboot (some people use G0) ERA BADNAME.COM ERA the temporary file. Sorry for that hack, but I thought it better to put LINKASM in the CP/M UG with that problem, rather than holding it back "trying to make it perfect". ---------------- I have not encountered any problems using LINKASM as my main assembler for about the last 6 months. Among other things, I use it to assemble CBBS.ASM which, with its 14 or so LINKed files, is over 6000 lines. It takes about 5 1/2 minutes, as I recall (HEX and SYM, no PRN). Ward Christensen nt. If necessary, you can find the name which was being searched for. It's in memory at 186H. If you have a PROM monitor, COM!9" 1I ͇MLOAD ver. 2.4 Copyright (C) 1983, 1984, 1985 by NightOwl Software, Inc. ͏ s͋zdͿͽ : ! * !  &<* !~#ʏG<6#" *}O| G6# x¿* +Fʏ#~ FUi~#Ui" ))))_* \ =A: i: i<2 –#![  < ,K6L#" x–2 ] 7ͽ <!e~ ½6H#6E#6X`^ ! ~4! ~d* 1:˜2 W _° g o: ̖ +: : " *  " :9 * " *   w# ØG! ~wx1N1N: R_!~! 4\ͽ 2 <4!͖ * * !:9ͽ \ͽ ѷ£*  " v+" * * " ͽ \ !  <~ !<ͽ ͽ <* * {OzGxr\!ͽ ͽ * #" yրOxGz͇Loaded * ͇ bytes (͇H)͇ to file %: ʚ͇ Over a * ͇ byte binary file͇ Start address: * ͇H Ending address: * ͇H Bias: * ͇H ͇Saved image size: * )͇ bytes (͇H, - ͇ records) * }G|͇ ++ Warning: program origin NOT at 100H ++ \ͽ <(͍~#%ʜ/Í:\©͋ <@/:[} o&>:/!]>./Í~ #/#  |{0/> /> /|}'Ɛ'@'_ͽ ~#=#~ FUX0:fAG?͇ Command line syntax error Ï͉ Ambiguous file name: % not allowed.͉ File % not found.͉ Disk full.͉ Directory full.͉ Premature end-of-file in %͉ Checksum error in %͉ Can't close %͉ Memory full while loading %͉ Format error in file %͉ Writing %, nothing loaded͉ MLOAD syntax: MLOAD [=] [,...] [] (brackets denote optional items) is the optional output filename are input file(s) is a hex load offset within the output file may be an optional non-HEX file to be patched by subsequently named HEX files (specifying The filetype enables this f$unction). Note that ZCPR2-style drive/user notation may be used in all file specifications (e.g., "B3:MYFILE.COM, "A14:MDM7.HEX"). ͍v>2 " " * }o|g"   !]<: ! } w#͋ 2  % x _ } 6# 6 # 6# ͨ # ͨ #( :~U AC @#~#:+xG~0G#~:K #{ ~.#yu  k { ͨ #*ʗ ?‹ U  { à >? ™ ͨ #à ~/., :=ȷ/  " 2 = go : *  y "    go\ ] y!"#$a{ e!z #v i HEX ͽ ͽ I I UTFIL> is the optional output filename are input file(s) is a hex load offset within the output file may be an optional non-HEX file to be patched by subsequently named HEX files (specifying The filetype enables this f%&'