public logout, bye, finish, remote, get, server include msdefs.h datas segment public 'datas' extrn data:byte, flags:byte, trans:byte, pack:byte, curchk:byte extrn fcb:byte remcmd db 0 ; Remote command to be executed. [21c] rempac db 0 ; Packet type: C (host) or G (generic). [21c] cmer05 db cr,lf,'?Filename must be specified$' ; [21a] ermes7 db '?Unable to receive initiate$' erms18 db cr,lf,'?Unable to tell host that session is finished$' erms19 db cr,lf,'?Unable to tell host to logout$' erms21 db cr,lf,'?Unable to tell host to execute command$' ; [21c] infms1 db 'Entering server mode',cr,lf,'$' remms1 db 'Kermit-MS: Unknown server command$' remms2 db 'Kermit-MS: Illegal file name$' remms3 db 'Kermit-MS: Unknown generic command$' pass db lf,cr,' Password: $' ; When change directory. [21c] crlf db cr,lf,'$' tmp db ?,'$' temp dw 0 oloc dw 0 ; Original buffer location. [21c] osiz dw 0 ; Original buffer size. [21c] inpbuf dw 0 ; Pointer to input buffer. [21c] cnt dw 0 delinp db BS,BS,BS,' ',BS,BS,BS,'$' ; When DEL key is used. [21d] clrspc db ' ',10O,'$' ; Clear space. srvchr db 'SRGIE' ; server cmd characters srvfln equ $-srvchr ; length of tbl srvfun dw srvsnd,srvrcv,srvgen,srvini,serv1 remhlp db cr,lf,'CWD connect to a directory' ; [21c start] db cr,lf,'DELETE a file' db cr,lf,'DIRECTORY listing' db cr,lf,'HELP' db cr,lf,'HOST command' db cr,lf,'SPACE in a directory' db cr,lf,'TYPE a file$' ; [21c end] remtab db 07H ; Seven entries. [21c start] mkeyw 'CWD',remcwd mkeyw 'DELETE',remdel mkeyw 'DIRECTORY',remdir mkeyw 'HELP',remhel mkeyw 'HOST',remhos mkeyw 'SPACE',remdis mkeyw 'TYPE',remtyp ; [21c end] remfnm db ' Remote Source File: $' lclfnm db ' Local Destination File: $' filhlp db ' File name to receive as$' filmsg db ' Remote file specification or confirm with carriage return $' frem db ' Name of file on remote system $' genmsg db ' Enter text to be sent to remote server $' rdbuf db 80H DUP(?) datas ends code segment public extrn comnd:near, serrst:near, spack:near, rpack5:near, init:near extrn read12:near, serini:near, read2:near, rpar:near, spar:near extrn rin21:near, rfile3:near, error1:near, clrfln:near extrn dodel:near, clearl:near, dodec: near, doenc:near extrn packlen:near, send11:near, errpack:near, init1:near extrn rpack:near,nak:near, rrinit:near, cmblnk:near extrn error:near, erpos:near, rprpos:near, clrmod:near extrn prompt:near assume cs:code,ds:datas ; LOGOUT - tell remote KERSRV to logout. LOGOUT PROC NEAR mov ah,cmcfm call comnd ; Get a confirm. jmp r call logo jmp rskp ; Go get another command whether we .... jmp rskp ; .... succeed or fail. LOGOUT ENDP LOGO PROC NEAR mov pack.numtry,0 ; Initialize count. mov pack.numrtr,0 ; No retries yet. call serini ; Initialize port. [14] mov ah,trans.chklen ; Don't forget the checksum length. mov curchk,ah mov trans.chklen,1 ; Use one char for server functions. logo1: cmp pack.state,'A' ; Did user type a ^C? je logo2x ; Yes just leave. mov ah,pack.numtry cmp ah,maxtry ; Too many times? js logo3 ; No, try it. logo2: mov ah,prstr mov dx,offset erms19 int dos logo2x: call serrst ; Reset port. [14] mov ah,curchk mov trans.chklen,ah ; Restore value. ret logo3: inc pack.numtry ; Increment number of tries. mov pack.argblk,0 ; Packet number zero. mov pack.argbk1,1 ; One piece of data. mov bx,offset data mov ah,'L' mov [bx],ah ; Logout the remote host. mov cx,1 ; One piece of data. call doenc ; Do encoding. mov ah,'G' ; Generic command packet. call spack jmp logo2 ; Tell user and die. nop call rpack5 ; Get ACK (w/o screen msgs.) jmp logo1 ; Go try again. nop push ax call dodec ; Decode packet. mov ah,curchk mov trans.chklen,ah ; Restore value. pop ax cmp ah,'Y' ; ACK? jne logo4 call serrst ; Reset port. [14] jmp rskp logo4: cmp ah,'E' ; Error packet? jnz logo1 ; Try sending the packet again. call error1 call serrst ; Reset port. [14] ret LOGO ENDP ; FINISH - tell remote KERSRV to exit. FINISH PROC NEAR mov ah,cmcfm ; Parse a confirm. call comnd jmp r mov pack.numtry,0 ; Initialize count. mov pack.numrtr,0 ; No retries yet. call serini ; Initialize port. [14] mov ah,trans.chklen ; Don't forget the checksum length. mov curchk,ah mov trans.chklen,1 ; Use one char for server functions. fin1: cmp pack.state,'A' ; ^C typed? je fin2x mov ah,pack.numtry cmp ah,maxtry ; Too many times? js fin3 ; Nope, try it. fin2: mov ah,prstr mov dx,offset erms18 int dos fin2x: call serrst ; Reset port. [14] mov ah,curchk mov trans.chklen,ah ; Restore value. jmp rskp ; Go home. fin3: inc pack.numtry ; Increment number of tries. mov pack.argblk,0 ; Packet number zero. mov pack.argbk1,1 ; One piece of data. mov bx,offset data mov ah,'F' mov [bx],ah ; Finish running Kermit. mov cx,1 ; One piece of data. call doenc ; Do encoding. mov ah,'G' ; Generic command packet. call spack jmp fin2 ; Tell user and die. nop call rpack5 ; Get ACK (w/o screen stuff). jmp fin1 ; Go try again. nop push ax call dodec ; Decode data. mov ah,curchk mov trans.chklen,ah ; Restore value. pop ax cmp ah,'Y' ; Got an ACK? jnz fin4 call serrst ; Reset port. [14] jmp rskp ; Yes, then we're done. fin4: cmp ah,'E' ; Error packet? jnz fin1 ; Try sending it again. call error1 call serrst ; Reset port. [14] jmp rskp FINISH ENDP ; BYE command - tell remote KERSRV to logout & exits to DOS. BYE PROC NEAR mov ah,cmcfm ; Parse a confirm. call comnd jmp r call logo ; Tell the mainframe to logout. jmp rskp ; Failed - don't exit. mov flags.extflg,1 ; Set exit flag. jmp rskp ; [8 end] BYE ENDP ; Tell remote server to send the specified file(s). get PROC NEAR mov flags.droflg,0 ; Reset flags from fn parsing. mov flags.nmoflg,0 ; Reset flags from fn parsing. mov flags.cxzflg,0 ; no ctl-c typed yet... mov bx,offset rdbuf ; Where to put text. [8 start] mov dx,offset filmsg ; In case user needs help. mov ah,cmtxt call comnd ; Get text or confirm. jmp r ; Fail. cmp ah,0 ; Read in any chars? jne get4 ; Yes, then OK. ; empty line, ask for file names get1: mov dx,offset remfnm ; ask for remote first call prompt mov bx,offset rdbuf mov dx,offset frem mov ah,cmtxt call comnd ; get a line of text jmp r cmp flags.cxzflg,'C' ; ctl-C typed? jne get2 ; no, continue jmp rskp get2: cmp ah,0 je get1 ; ignore empty lines mov bl,ah mov bh,0 mov byte ptr rdbuf[bx],'$' ; terminate name for printing mov cnt,bx ; remember length here mov dx,offset lclfnm call prompt mov ah,cmifi mov bx,offset filhlp mov dx,offset fcb call comnd jmp r mov ah,cmcfm call comnd jmp r cmp flags.cxzflg,'C' ; control-C typed? jne get3 ; no, keep going jmp rskp get3: mov flags.nmoflg,1 ; remember changed name jmp short get5 get4: mov al,ah mov ah,0 mov cnt,ax ; Remember number of chars we read. mov byte ptr [bx],'$' ; use for printing. get5: call ipack ; Initialize. jmp get8 ; Sorry can't do it. nop mov cx,cnt ; Get back filename size. mov pack.argbk1,cx ; Need it here to send packet. inc cx ; Don't forget "$" for printing. push es ; Prepare to put string into packet. mov ax,ds mov es,ax mov si,offset rdbuf ; Move from here mov di,offset data ; to here. rep movsb ; Perform the string move. pop es cmp flags.remflg,0 ; remote mode? jne get6 ; yes, don't print anything cmp flags.destflg,2 ; Receiving to screen? [27c] je get6 ; Yes skip screen stuff. [27c] call init ; Clear line and initialize buffers. call clrfln ; Prepare to print filename. mov ah,prstr mov dx,offset data ; Print file name. int dos get6: call init1 ; init buffers mov pack.numtry,0 ; Initialize count. mov pack.numrtr,0 ; No retries yet. mov pack.state,'R' ; this is what state will soon be... mov cx,pack.argbk1 ; Data size. call doenc ; Encode data. mov ah,trans.chklen ; Don't forget the checksum length. mov curchk,ah mov trans.chklen,1 ; Use one char for server functions. get7: cmp pack.state,'A' ; Did user type a ^C? je get9 ; Yes - just return to main loop. mov ah,pack.numtry cmp ah,maxtry ; Too many times? jbe get10 ; Nope, try it. get8: cmp flags.remflg,0 ; remote mode? jne get9 ; yes, no printing call erpos mov ah,prstr mov dx,offset ermes7 ; Can't get init packet. int dos get9: call serrst ; Reset port. mov ah,curchk mov trans.chklen,ah ; Restore value. jmp rskp ; Go home. get10: inc pack.numtry ; Increment number of tries. mov pack.argblk,0 ; Start at packet zero. mov ah,'R' ; Receive init packet. call spack ; Send the packet. jmp get8 ; Tell user we can't do it. nop call rpack5 ; Get ACK (w/o screen stuff). jmp get7 ; Got a NAK - try again. nop push ax mov ah,curchk mov trans.chklen,ah ; Restore value. pop ax mov pack.argbk2,ax ; this is where rinit wants pkt type if getting mov flags.getflg,1 ; "Get" as vs "Receive". jmp read12 ; go join read code get11: mov ah,prstr ; Complain if no filename. mov dx,offset cmer05 int dos jmp rskp GET ENDP ; server command server proc near mov ah,cmcfm call comnd jmp r push es mov ax,ds mov es,ax ; address data segment mov al,flags.remflg ; get remote flag push ax ; preserve for later mov flags.remflg,1 ; set remote if server call cmblnk ; clear screen mov ah,prstr mov dx,offset infms1 int dos ; should reset to default parms here... ; should increase timeout interval serv1: call serini ; init serial line (send & recv reset it) mov trans.chklen,1 ; checksum len = 1 mov pack.pktnum,0 ; pack number resets to 0 mov pack.numtry,0 ; no retries yet. call rpack ; get a packet jmp short serv2 ; no good, nak and continue nop jmp short serv3 ; try to figure this out serv2: cmp flags.cxzflg,'C' ; ctl-C? je serv5 ; yes, stop this. call nak ; nak the packet jmp serv1 ; and keep readiserv2 packets serv3: mov di,offset srvchr ; server characters mov cx,srvfln ; length of striserv2 mov al,ah ; packet type repne scasb ; hunt for it je serv4 ; we know this one, go handle it mov bx,offset remms1 ; else give a message call errpack ; back to local kermit jmp serv1 ; and keep lookiserv2 for a cmd serv4: sub di,offset srvchr+1 ; find offset, +1 for pre-increment shl di,1 ; convert to word index. call srvfun[di] ; call the appropriate handler jmp serv5 ; someone wanted to exit... ; should we reset serial line? jmp serv1 ; else keep goiserv2 for more cmds. serv5: ;** restore timer values pop ax ; get this off stack mov flags.remflg,al ; restore old flag call serrst ; reset serial handler pop es ; restore register jmp rskp ; and return server endp ; server commands. ; srvsnd - receives a file that the local kermit is sending. srvsnd proc near mov bx,offset data call spar ; parse the send-init packet call packlen ; figure max packet mov bx,offset data call rpar ; make answer for them mov al,ah ; length of packet mov ah,0 mov pack.argbk1,ax ; store length for spack mov ah,'Y' ; ack call spack ; answer them jmp rskp ; can't answer, forget this call rrinit ; init variables for init inc pack.pktnum ; count the send-init packet. mov pack.state,'F' ; expecting file name about now call read2 ; and join read code nop nop nop ; ignore errors jmp rskp ; and return for more srvsnd endp ; srvrcv - send a file that they're receiving. srvrcv proc near mov si,offset data ; this should be filename mov di,offset fcb ; this is where filename goes mov al,1 ; skip leading separators mov ah,prsfcb ; parse an fcb int dos ; let dos do the work cmp al,0ffh ; invalid? jne srvrc1 ; no, keep going mov bx,offset remms2 ; complain call errpack ; that we can't find it jmp rskp ; and return srvrc1: mov pack.state,'R' ; remember state. call send11 ; this should send it jmp rskp jmp rskp ; return in any case srvrcv endp ; srvgen - generic server commands. ; We only support Logout and Finish right now. srvgen proc near mov al,data ; get 1st packet char cmp al,'F' ; maybe finish? je srvge1 ; yup, handle cmp al,'L' ; logout? jne srvge2 ; no. srvge1: mov pack.argbk1,0 ; 0-length data mov ah,'Y' call spack ; ack it nop nop nop ; *** ignore error? ret ; and return to signal exit. srvge2: mov bx,offset remms3 call errpack jmp rskp srvgen endp ; srvini - init parms based on init packet srvini proc near mov bx,offset data call spar ; parse info call packlen ; this should really be part of spar, but... mov bx,offset data call rpar ; get receive info mov al,ah mov ah,0 mov pack.argbk1,ax ; set size of return info mov ah,'Y' call spack ; send the packet off jmp rskp jmp rskp ; and go succeed srvini endp ; This is the REMOTE command. [21c] REMOTE PROC NEAR mov dx,offset remtab ; Parse a keyword from the REMOTE table. mov bx,offset remhlp mov ah,cmkey call comnd jmp r call bx ; Call the appropriate routine. jmp r ; Command failed. jmp rskp REMOTE ENDP ; REMDIS - Get disk usage on remote system. [21c] REMDIS PROC NEAR mov remcmd,'U' ; Disk usage command. mov rempac,'G' ; Packet type = generic. jmp genric ; Execute generic Kermit command. REMDIS ENDP ; REMHEL - Get help about remote commands. [21c] REMHEL PROC NEAR mov remcmd,'H' ; Help...... mov rempac,'G' ; Packet type = generic. jmp genric ; Execute generic Kermit command. REMHEL ENDP ; REMTYP - Print a remote file. [21c] REMTYP PROC NEAR mov remcmd,'T' ; Type the file. mov rempac,'G' ; Packet type = generic. jmp genric REMTYP ENDP ; REMHOS - Execute a remote host command. [21c] REMHOS PROC NEAR mov remcmd,' ' ; Don't need one. mov rempac,'C' ; Packet type = remote command. jmp genric REMHOS ENDP ; REMDIR - Do a directory. [21c] REMDIR PROC NEAR mov remcmd,'D' mov rempac,'G' ; Packet type = generic. jmp genric REMDIR ENDP ; REMDEL - Delete a remote file. [21c] REMDEL PROC NEAR mov remcmd,'E' mov rempac,'G' ; Packet type = generic. jmp genric REMDEL ENDP ; REMCWD - Change remote working directory. [21c] REMCWD PROC NEAR mov remcmd,'C' mov rempac,'G' ; Packet type = generic. jmp genric REMCWD ENDP ; GENRIC - Send a generic command to a remote Kermit server. [21c] GENRIC PROC NEAR mov bx,offset rdbuf ; Where to put the text. cmp rempac,'C' ; Remote host command? je genra ; Yes, leave as is. add bx,2 ; Leave room for type and size. genra: mov ah,cmtxt ; Parse arbitrary text up to a CR. mov dx,offset genmsg ; In case they want text. call comnd jmp r mov al,ah ; Don't forget the size. mov ah,0 mov cnt,ax ; Save it here. cmp rempac,'C' ; Remote host command? jne genrb ; No, skip this part. call ipack jmp genr2 mov pack.numtry,0 mov ah,trans.chklen mov curchk,ah ; Save desired checksum length. mov trans.chklen,1 ; Use 1 char for server functions. mov pack.numrtr,0 ; No retries yet. jmp genr1 ; Send the packet. genrb: mov ax,cnt cmp ax,0 ; Any data? je genr0 ; Nope. mov ah,al ; Don't overwrite the real count value. add ah,32 ; Do the char function. mov temp,bx ; Remember where we are. mov bx,offset rdbuf+1 ; Size of remote command. mov [bx],ah mov ah,0 inc al ; For the size field. cmp remcmd,'C' ; Change working directory? jne genr0 ; No, so don't ask for password. mov cnt,ax ; Save here for a bit. mov ah,prstr mov dx,offset pass ; Send along an optional password. int dos mov bx,temp ; Where to put the password. push bx ; Is safe since subroutine never fails. inc bx ; Leave room for count field. call input ; Read in the password. mov temp,bx ; Remember end of data pointer. pop bx ; Where to put the size. cmp ah,0 ; No password given? jne genrc mov ax,cnt jmp genr0 ; Then that's it. genrc: mov al,ah add ah,32 ; Make it printable. mov [bx],ah ; Tell remote host the size. mov ah,0 push ax ; Remember the count. call clearl ; Clear to end-of-line. pop ax inc al ; For second count value. add ax,cnt ; Total for both fields of input. genr0: inc al ; For the char representing the command. mov pack.argbk1,ax ; Set the size. mov cnt,ax ; And remember it. mov pack.numtry,0 ; Initialize count mov bx,offset rdbuf ; Start of data buffer. mov ah,remcmd ; Command subtype. mov [bx],ah call ipack ; Send init parameters. jmp genr2 nop ; Make it 3 bytes long. mov ah,trans.chklen mov curchk,ah ; Save desired checksum length. mov trans.chklen,1 ; Use 1 char for server functions. mov pack.numrtr,0 ; No retries yet. genr1: cmp pack.state,'A' ; Did the user type a ^C? je genr2x mov ah,pack.numtry cmp ah,maxtry ; Too many tries? js genr3 ; Nope, keep trying. genr2: mov ah,prstr mov dx,offset erms21 ; Print error msg and fail. int dos genr2x: call serrst ; Reset the port. mov ah,curchk mov trans.chklen,ah ; Restore. jmp rskp genr3: push es ; Prepare to put string into packet. mov ax,ds mov es,ax mov si,offset rdbuf ; Move from here mov di,offset data ; to here. mov cx,cnt ; Move this many characters. rep movsb ; Perform the string move. pop es mov ax,cnt mov pack.argbk1,ax ; How much data to send. mov cx,ax ; Size of data. call doenc ; Encode it. inc pack.numtry ; Increment number of trials. mov pack.argblk,0 ; Packet number 0. mov ah,rempac ; Packet type. call spack ; Send the packet. jmp genr2 ; Tell user we can't do it. nop call rpack5 ; Get ACK (w/o screen stuff) jmp genr1 ; Got a NAK - try again. nop push ax mov ah,curchk mov trans.chklen,ah ; Restore. pop ax cmp ah,'Y' ; Is all OK? jne genr4 cmp pack.argbk1,0 ; Any data in the ACK? je genr31 ; Nope - just return. call dodec ; Decode data. mov ah,prstr mov dx,offset crlf ; First go to a new line. int dos mov di,offset data ; Where the reply is. mov cx,pack.argbk1 ; How much data we have. call prtscr ; Print it on the screen. genr31: jmp rskp ; And we're done. genr4: cmp ah,'X' ; Text packet? je genr5 cmp ah,'S' ; Handling this like a file? jne genr6 mov pack.state,'R' ; Set the state. mov bx,offset rin21 ; Where to go to. jmp genr51 ; Continue. genr5: mov pack.state,'F' call dodec ; Decode data. mov bx,offset rfile3 ; Jump to here. genr51: mov tmp,ah ; Save packet type. mov flags.xflg,1 ; Remember we saw an "X" packet. mov pack.numtry,0 mov pack.numrtr,0 mov pack.numpkt,0 mov pack.pktnum,0 mov flags.cxzflg,0 mov ah,tmp ; Packet type. call bx ; Handle it almost like filename. call read2 ; Receive the rest. jmp r ; Oops, we failed. jmp rskp ; Done OK. genr6: cmp ah,'E' ; Error packet? je genr6x jmp genr1 ; Try again. genr6x: call dodec ; Decode data. call error1 ; Print the error messge. call serrst jmp rskp ; And return. GENRIC ENDP ; Send "I" packet with transmission parameters. [21c] IPACK PROC NEAR mov ah,trans.chklen mov curchk,ah ; Initialize. call serini mov pack.pktnum,0 ; Use packet number 0. mov pack.numtry,0 ; Number of retries. ipk0: cmp pack.state,'A' ; Did user type a ^C? je ipk0x cmp pack.numtry,imxtry ; Reached our limit? jl ipk1 ipk0x: ret ; Yes, so we fail. ipk1: inc pack.numtry ; Save the updated number of tries. mov bx,offset data ; Get a pointer to our data block. call rpar ; Set up the parameter information. xchg ah,al mov ah,0 mov pack.argbk1,ax ; Save the number of arguments. mov pack.argblk,0 ; Use packet number 0. mov ah,trans.chklen mov curchk,ah ; Save real value. mov trans.chklen,1 ; One char for server function. mov ah,'I' ; "I" packet. call spack ; Send the packet. jmp ipk4 nop call rpack5 ; Get a packet. jmp ipk4 ; Try again. nop push ax mov ah,curchk mov trans.chklen,ah ; Reset. pop ax cmp ah,'Y' ; ACK? jne ipk3 ; If not try next. mov ax,pack.pktnum ; Get the packet number. cmp ax,pack.argblk ; Is it the right packet number? je ipk2 jmp ipk0 ; If not try again. ipk2: mov ax,pack.argbk1 ; Get the number of pieces of data. mov bx,offset data ; Pointer to the data. call spar ; Read in the data. mov ah,trans.chklen mov curchk,ah ; This is what we decided on. call packlen ; Get max send packet size. [21b] mov pack.numtry,0 ; Reset the number of tries. jmp rskp ipk3: cmp ah,'N' ; NAK? je ipk0 ; Yes, try again. cmp ah,'E' ; Is it an error packet. je ipk3x jmp ipk0 ; Trashed data. ipk3x: jmp rskp ; Other side doesn't know about "I" packet. ipk4: mov ah,curchk mov trans.chklen,ah ; Reset. jmp ipk0 ; Keep trying. IPACK ENDP ; Returns in AH the count of characters read in. ; in BX the updated pointer to the input buffer. INPUT PROC NEAR mov cl,0 ; Keep a count. mov inpbuf,bx ; Where to put data. input0: mov ah,conin ; Read in a char. int dos cmp al,CR ; Done with input? jne input1 mov ah,cl ; Return count in AH. jmp r input1: cmp al,BS ; Backspace? je inpt11 ; cmp al,DEL ; Or delete? jne input3 call dodel ; Erase weird character. inpt11: dec cl ; Don't include in char count. cmp cl,0 ; Backspaced too much? jns input2 ; No, is OK. push bx call clearl pop bx mov ah,conout mov dl,bell int dos mov cl,0 jmp input0 input2: dec bx ; 'Remove' from buffer. mov ah,prstr mov dx,offset clrspc int dos jmp input0 ; Go get more. input3: cmp al,'U'-64 ; Control-U? jne input4 mov ah,prstr mov dx,offset pass+1 int dos push bx push cx call clearl ; Blank out the line. pop cx pop bx mov cl,0 ; Reset count to zero. mov bx,inpbuf ; Start at head of buffer. jmp input0 input4: cmp al,0 ; Two character sequence? jne input5 mov ah,conin int dos ; Get second char. cmp al,83 ; Delete key? je inpt40 ; Yup. cmp al,75 ; Backarrow key? je inpt40 call dodel ; Erase weird character. jmp input0 ; And go on computing. inpt40: mov ah,prstr mov dx,offset delinp ; Erase weird character. int dos jmp inpt11 ; Remove the offending char. input5: mov [bx],al ; Add char to buffer. inc cl ; Include in count. inc bx jmp input0 INPUT ENDP ; Print data onto the screen. If text has no "$" in it, just print ; it. Else, do special output for the "$". ; Routine expects: DI = Start of buffer we are to print. ; CX = Number of characters to print. [21c] PRTSCR PROC NEAR mov al,'$' ; This is what we're looking for. mov oloc,di ; Remember original buffer address. mov osiz,cx ; And original size. push es mov bx,ds mov es,bx ; Have ES point to data area. prts0: repnz scasb ; Search for "$" in the buffer. cmp cx,0 ; Found one? je prts1 ; No, do a regular DOS call. mov ah,prstr mov dx,oloc ; Print up to the "$". int dos mov ah,dconio mov dl,'$' int dos ; Print the "$" mov oloc,di ; New starting location. mov osiz,cx ; New size. jmp prts0 prts1: mov bx,oloc ; The buffer location. add bx,osiz ; Point past the data. mov [bx],al ; Add "$" for printing. mov ah,prstr mov dx,oloc int dos pop es ret PRTSCR ENDP ; Jumping to this location is like retskp. It assumes the instruction ; after the call is a jmp addr. RSKP PROC NEAR pop bp add bp,3 push bp ret RSKP ENDP ; Jumping here is the same as a ret. R PROC NEAR ret R ENDP code ends end