PAGE 59, 132 TITLE MSCMD -- COMND module for MS-Kermit ; Update 22 Jan 86 IF1 %OUT >> Starting pass 1 ELSE %OUT >> Starting pass 2 ENDIF ; This version has machine-dependent code for both IBM PCs and DEC Rainbows PUBLIC comnd, cmcfrm, prserr, repars, cmgtch, drives, comand, fcbcpy INCLUDE MsDefs.H DataS SEGMENT PUBLIC 'DataS' extrn flags:byte, trans:byte, fcb:byte, DTA:byte extrn taklev:byte, takadr:word, dosnum:byte, OldStk:WORD EXTRN PC_Type:BYTE, In_menu_mode:BYTE comand cmdinfo <> cmer00 DB '? Program error Invalid COMND call',cr,lf,'$' cmer01 DB '? Ambiguous',cr,lf,'$' cmer02 DB '? Illegal input file spec',cr,lf,'$' cmer03 DB '? Invalid command',cr,lf,'$' cmer04 DB '? Invalid command or operand',cr,lf,'$' cmer06 DB '? Wildcard not allowed',cr,lf,'$' cmer07 DB '? Invalid drive specificaton',cr,lf,'$' cmin00 DB ' Confirm with carriage return$' cmin01 DB ' One of the following:',cr,lf,'$' F5_str DB '',cr,lf,'$' DO_str DB '',cr,lf,'$' cmthlp DW 0 ; Text of help message for random input drives DB 0 ; How many drives we have. [21a] crlf DB cr,lf,'$' ctcmsg DB '^C', Cr, Lf, '$' prsp DB ' $' ; Print a space hlpmsg DW 0 ; Address of help message spchar DB 24H,26H,23H,40H,21H,25H,27H,28H,29H,2DH DB 3CH,3EH,7BH,7DH,5FH,5CH,5EH,7EH,7CH,60H spclen equ $-spchar spchar2 DB 24H,26H,23H,40H,21H,25H,27H,28H,29H,2DH DB 7BH,7DH,5FH,5EH,7EH,60H spc2len equ $-spchar2 escspc DB 10O,' ',10O,'$' ; Clear escape clrspc DB ' ',10O,'$' ; Clear space filbuf DB 60H DUP(?) ; Character buffer tbuff DB 80 DUP(?) cmdstk DW ? ; Parallel tables used to turn keypad function keys into binary ASCII values Sensible_func_keys db 2fh,32h,35h,38h,3bh,3eh,41h,44h,47h,4ah,4dh,50h,53h,56h To_ASCII_scan_codes db 30h,31h,32h,33h,34h,35h,36h,37h,38h,39h,2dh,2ch,2eh,0dh Func_table_length EQU $ - To_ASCII_scan_codes DataS ENDS Code SEGMENT PUBLIC extrn dodel:near, ctlu:near, cmblnk:near, locate:near, takrd:near extrn clearl:near, KrmRet:NEAR, Telnet2:NEAR, Beep:NEAR EXTRN Quick_Push:NEAR, Quick_Menu:NEAR assume cs:code,ds:datas,es:datas ; This routine parses the specified function in AH. Any additional ; information is in DX and BX ; Returns +1 on success ; +4 on failure (assumes a JMP follows the call) CMND PROC NEAR comnd: mov comand.cmstat,ah ; Save what we are presently parsing mov cmdstk,sp ; save stack ptr locally call cminbf ; Get chars until an action or a erase char mov ah,comand.cmstat ; Restore 'ah' for upcoming checks cmp ah,cmcfm ; Parse a confirm? jz cmcfrm ; Go get one cmp ah,cmkey ; Parse a keyword? jnz cm1 jmp cmkeyw ; Try and get one cm1: cmp ah,cmifi ; Parse an input file spec? jnz cm2 jmp cmifil ; Go get one cm2: cmp ah,cmofi ; Output file spec? jnz cm3 jmp cmofil ; Go get one cm3: cmp ah,cmtxt ; Parse arbitrary text. [8] jnz cm4 jmp cmtext cm4: mov ah,prstr ; Else give error mov dx,offset cmer00 ; "?Unrecognized COMND call" int dos ret ; This routine gets a confirm cmcfrm: call cmgtch ; Get a char cmp ah,0 ; Is it negative (a terminator; a space or ; a tab will not be returned here as they ; will be seen as leading white space.) js cmcfr0 ret ; If not, return failure cmcfr0: and ah,7FH ; Turn off the minus bit cmp ah,esc ; Is it an escape? jne cmcfr2 mov ah,conout mov dl,bell ; Get a bell int dos mov ah,0 mov comand.cmaflg,ah ; Turn off the action flag mov bx,comand.cmcptr ; Move the pointer to before thee scape dec bx mov comand.cmcptr,bx mov comand.cmdptr,bx dec comand.cmccnt ; Decremrnt the char count jmp cmcfrm ; Try again cmcfr2: cmp ah,'?' ; Curious? jne cmcfr3 mov ah,prstr ; Print something useful mov dx,offset cmin00 int dos mov ah,prstr mov dx,offset crlf ; Print a crlf int dos mov ah,prstr mov dx,comand.cmprmp ; Reprint the prompt int dos mov bx,comand.cmdptr ; Get the pointer into the buffer mov ah,'$' ; Put a $ there for printing mov [bx],ah mov bx,comand.cmcptr dec bx ; Decrement & save the buffer pointer mov comand.cmcptr,bx mov ah,prstr mov dx,offset comand.cmdbuf int dos mov ah,0 ; Turn off the action flag mov comand.cmaflg,ah jmp repars ; Reparse everything cmcfr3: cmp ah,ff ; Is it a form feed? jne cmcfr4 call cmblnk ; If so blank the screen cmcfr4: jmp rskp ; This routine parses a keyword from the table pointed ; to in DX. 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 ; DW ab ; Where ab is data to be returned ; ; The keywords must be in alphabetical order cmkeyw: mov comand.cmhlp,bx ; Save the help mov comand.cmptab,dx ; Save the beginning of keyword table mov bx,dx mov ch,[bx] ; Get number of entries in table inc bx mov dx,comand.cmdptr ; Save command pointer mov comand.cmsptr,dx ; Save pointer's here cmky1: cmp ch,0 ; Any commands left to check? jne cmky2 jmp cmky41 ; no, go complain cmky2: dec ch mov cl,0 ; Keep track of how many chars read in so far call cmgtch ; Get a char cmp ah,0 ; Do we have a terminator? jns cmky2x jmp cmky4 ; Negative number means we do cmky2x: inc bx ; Point to first letter of keyword inc cl ; Read in another char mov al,[bx] cmp ah,'a' ; Less than a? jl cmky21 ; If so, don't capitalize cmp ah,'z'+1 ; More than z? jns cmky21 and ah,137O ; Capitalize the letter cmky21: cmp ah,al je cmky3 jg cmky2y jmp cmky41 ; Fail if ah preceeds al alphabetically cmky2y: jmp cmky6 ; Not this keyword - try the next cmky3: inc bx ; We match here, how 'bout next char? mov al,[bx] cmp al,'$' ; End of keyword? jne cmky3x jmp cmky7 ; Succeed cmky3x: mov dl,al ; Save al's char here call cmgtch inc cl ; Read in another char mov al,dl cmp ah,'a' jl cmky31 cmp ah,'z'+1 jns cmky31 and ah,137O cmky31: cmp ah,esc+80H ; Escape Recognition (escape w/minus bit on)? je cmky3y cmp ah,'?'+80H ; A question mark? [3] je cmky3y cmp ah,' '+80H ; A space? je cmky3y cmp ah,cr+80H ; Carriage return? je cmky3y jmp cmky38 cmky3y: mov comand.cmkptr,bx ; Save bx here mov comand.cmsiz,cx ; Save size info mov comand.cmchr,ah ; Save char for latter call cmambg ; See if input is ambiguous or not jmp cmky32 ; Succeeded (not ambiguous) mov ah,comand.cmchr cmp ah,esc+80H ; Escape? je cmky3z cmp ah,'?'+80H ; maybe question mark? je cmkyj1 ; yes, go handle jmp cmky41 ; Else fail cmky3z: mov ah,conout ; Ring a bell mov dl,bell int dos mov bx,comand.cmcptr ; Move pointer to before the escape dec bx mov comand.cmcptr,bx mov comand.cmdptr,bx dec comand.cmccnt ; Decrement char count mov bx,comand.cmkptr ; Failed - pretend user never typed ... mov cx,comand.cmsiz ; ... in a char dec cl ; Don't count the escape dec bx mov comand.cmaflg,0 ; Reset the action flag jmp cmky3 ; Keep checking ; ambiguous. Print out all the keywords that match cmkyj1: mov dx,offset cmin01 mov ah,prstr int dos mov bx,comand.cmkptr ; this is current keyword mov cx,comand.cmsiz ; we are cl chars into it mov ch,0 sub bx,cx ; back up to beginning inc bx ; not counting ? mov comand.cmkptr,bx ; save beginning of kw cmkyj2: mov dl,tab ; put a tab before each keyword mov ah,conout int dos mov dx,comand.cmkptr ; get current keyword mov ah,prstr int dos ; print it mov bx,comand.cmkptr ; get keyword back dec bx mov al,[bx] ; get length mov ah,0 add ax,5 ; skip length, $, value, next length add bx,ax ; this is next keyword mov si,bx mov di,comand.cmkptr ; compare with last keyword mov comand.cmkptr,bx ; update this mov cx,comand.cmsiz dec ch ; are we at end of table? jl cmkyj3 ; yes, don't go on mov comand.cmsiz,cx ; else update count mov ch,0 dec cl ; this includes ? jcxz cmkyj2 ; empty, just print it repe cmpsb ; compare to previous string je cmkyj2 ; same, go print this one cmkyj3: jmp cmky50 ; else go finish up cmky32: mov cx,comand.cmsiz ; Restore info mov bx,comand.cmkptr ; Our place in the keyword table cmp comand.cmchr,0A0H ; Space? je cmky35 cmp comand.cmchr,0BFH ; Question mark? [3] je cmky35 cmp comand.cmchr,8DH ; Carriage return? je cmky35 dec comand.cmcptr ; Pointer into buffer of input mov dx,comand.cmcptr cmky33: mov ah,[bx] ; Get next char in keyword cmp ah,'$' ; Are we done yet? jz cmky34 mov di,dx mov [di],ah inc bx inc dx inc comand.cmccnt jmp cmky33 cmky34: mov ah,' ' mov di,dx mov [di],ah ; Put a blank in the buffer inc dx mov cx,comand.cmcptr ; Remember where we were mov comand.cmcptr,dx ; Update our pointers mov comand.cmdptr,dx mov ah,'$' mov di,dx mov [di],ah ; Add '$' for printing mov ah,prstr mov dx,cx ; Point to beginning of filled in data int dos inc bx ; Point to address we'll need mov bx,[bx] mov comand.cmaflg,0 ; Turn off action flag jmp rskp cmky35: inc bx mov ah,[bx] ; Find end of keyword. cmp ah,'$' jne cmky35 inc bx mov bx,[bx] ; Address of next routine to call ; mov comand.cmaflg,0 ; Zero the action flag jmp rskp cmky38: cmp ah,al je cmky39 jmp cmky6 ; Go to end of keyword and try next cmky39: jmp cmky3 ; Check next letter cmky4: and ah,7FH ; Turn off minus bit cmp ah,'?' ; Need help? je cmky5 cmp ah,' ' ; Just a space - no error je cmky51 cmp ah,cr je cmky51 cmp ah,tab je cmky51 cmp ah,esc ; Ignore escape? je cmky43 cmky41: mov ah,prstr mov dx,offset cmer03 int dos jmp prserr ; Parse error - give up cmky43: mov ah,conout ; Ring a bell mov dl,bell int dos mov bx,comand.cmcptr dec bx mov comand.cmcptr,bx mov comand.cmdptr,bx dec comand.cmccnt ; Don't count the escape mov comand.cmaflg,0 ; Reset action flag inc ch ; Account for a previous 'dec' jmp cmky1 ; Start over cmky5: inc bx ; point to actual keyword mov comand.cmkptr,bx ; remember current kw mov cl,1 ; code above expects to count ? mov comand.cmsiz,cx ; and size mov dx,comand.cmhlp or dx,dx ; was any help given? jnz cmky5a ; yes, use it jmp cmkyj1 ; else make our own message cmky5a: mov ah,prstr int dos cmky50: mov ah,prstr mov dx,offset crlf int dos mov dx,comand.cmprmp ; Address of prompt int dos mov bx,comand.cmdptr ; Get pointer into buffer mov al,'$' mov [bx],al ; Add dollar sign for printing mov dx,offset comand.cmdbuf int dos dec comand.cmcptr ; Don't keep it in the buffer dec comand.cmccnt ; Don't conut it mov comand.cmaflg,0 ; Turn off the action flag jmp repars cmky51: cmp comand.cmcr,1 ; Are bare CR's allowed? je cmky52 ; Yes mov ah,prstr mov dx,offset cmer04 ; Complain int dos cmky52: jmp prserr cmky6: inc bx ; Find end of keyword mov al,[bx] cmp al,'$' jne cmky6 inc bx ; Beginning of next command inc bx inc bx mov dx,comand.cmsptr ; Get old cmdptr mov comand.cmdptr,dx ; Restore mov comand.cmsflg,0FFH jmp cmky1 ; Keep trying cmky7: call cmgtch ; Get char cmp ah,0 js cmky71 ; Ok if a terminator dec bx jmp cmky6 ; No match - try next keyword cmky71: inc bx ; Get necessary data mov bx,[bx] cmp ah,9BH ; An escape? jne cmky72 mov ah,prstr mov dx,offset prsp ; Print a space int dos mov di,comand.cmcptr dec di mov ah,20H mov [di],ah ; Replace escape char with space mov comand.cmaflg,0 mov comand.cmsflg,0FFH ; Pretend they typed a space cmky72: jmp rskp ; See if keyword is unambiguous or not from what the user has typed in cmambg: cmp ch,0 ; Any keywords left to check? jne cmamb0 ret ; If not then not ambiguous cmamb0: inc bx ; Go to end of keyword .. mov al,[bx] ; So we can check the next one cmp al,'$' jne cmamb0 add bx,4 ; Point to start of next keyword dec cl ; Don't count escape mov dx,comand.cmsptr ; Buffer with input typed by user cmamb1: mov ah,[bx] ; Keyword char. mov di,dx mov al,[di] ; Input char cmp al,'a' ; Do capitalizing jl cmam11 cmp al,'z'+1 jns cmam11 and al,137O cmam11: cmp ah,al ; Keyword bigger than input (alphabetically)? jle cmamb2 ; No - keep checking ret ; Yes - not ambiguous cmamb2: inc bx ; Advance one char inc dx dec cl jnz cmamb1 jmp rskp ; Fail - it's ambiguous cmifil: mov hlpmsg,bx ; Address of help message mov bx,dx ; Get the fcb address in bx mov comand.cmfcb,bx ; Save it mov ch,0 ; Initialize char count mov ah,0 mov [bx],ah ; Set the drive to default to current inc bx mov comand.cmfcb2,bx mov cl,' ' cmifi0: mov [bx],cl ; Blank the FCB inc bx inc ah cmp ah,0BH ; Twelve? jl cmifi0 cmifi1: call cmgtch ; Get another char cmp ah,0 ; Is it an action character js cmif1x ; Jump out of range. [21a] jmp cmifi2 ; Ditto. [21a] cmif1x: and ah,7FH ; Turn off the action bit. [21a] cmp ah,'?' ; A question mark? jne cmif12 mov al,0 mov comand.cmaflg,al ; Blank the action flag dec comand.cmcptr ; Decrement the buffer pointer dec comand.cmccnt ; Decrement count mov ah,prstr mov dx,hlpmsg ; Help message int dos mov dx,offset crlf int dos mov dx,comand.cmprmp int dos mov bx,comand.cmdptr mov al,'$' mov [bx],al ; Put in dollar sign for printing mov dx,offset comand.cmdbuf int dos jmp repars cmif12: cmp ah,esc ; An escape? je cm12x jmp cmif13 cm12x: mov comand.cmaflg,0 ; Turn off the action flag dec comand.cmcptr ; Move pointers to before the escape dec comand.cmdptr dec comand.cmccnt ; Decrement char count mov comand.cmchr,ch ; Save current character count cmp ch,9 ; Past '.'? jl cmf120 ; No dec ch ; Yes, don't count point cmf120: mov di,comand.cmfcb2 ; Fill the rest with CP/M wildcards mov ah,'?' cmf121: cmp ch,11 ; Done? jge cmf122 ; Yes mov [di],ah inc di inc ch jmp cmf121 cmf122: mov ah,sfirst ; Find first matching file? mov dx,comand.cmfcb ;[jd] use pointer to PASSED fcb int dos cmp al,0FFH ; Any found? jne cmf123 ; Yes jmp cmf12b ; No, lose cmf123: mov di,offset filbuf ; Copy first file spec from DTA to buffer mov bx,offset DTA+1 mov cl,11 call fcbcpy mov di,offset filbuf+10H ; Get another copy (if not ambiguous) mov bx,offset DTA+1 mov cl,11 call fcbcpy mov ah,snext ; More matching specs? mov dx,comand.cmfcb ;[jd] use PASSED fcb.. int dos cmp al,0FFH je cmf124 ; Only one mov di,offset filbuf+10H ; Copy second file spec mov bx,offset DTA+1 mov cl,11 call fcbcpy cmf124: mov si,offset filbuf ; Start comparing file names mov bx,offset filbuf+10H mov di,comand.cmcptr ; Command buffer pointer mov cl,comand.cmchr ; Bypass characters typed cmp cl,9 ; Past '.'? jl cmf125 ; No dec cl ; Yes, don't count point cmf125: mov ch,0 ; Adjust pointers add si,cx add bx,cx mov ch,cl ; Update character count cmf126: cmp ch,11 ; All done? jne cmf127 ; No jmp cmf12a ; Yes cmf127: cmp ch,8 ; End of file name? jne cmf128 ; No cmp comand.cmchr,9 ; Exactly at point? je cmf128 ; Yes, don't output a second point mov ah,'.' ; Output separator mov [di],ah inc di inc comand.cmccnt cmf128: mov ah,[si] ; Get a character from first file spec inc si mov al,[bx] ; Get another from second spec inc bx cmp ah,al ; Compare jne cmf12a ; Ambiguous inc ch ; Same, count cmp ah,' ' ; Blank? je cmf129 ; Yes, don't output mov [di],ah inc di inc comand.cmccnt cmf129: jmp cmf126 ; Repeat %OUT >> About half way through source file cmf12a: mov comand.cmchr,ch ; Save count of characters processed mov ah,'$' ; Put terminator into buffer mov [di],ah mov comand.cmcptr,di ; Save pointer for recognized characters mov ah,prstr mov dx,comand.cmdptr int dos mov ch,comand.cmchr ; Characters processed cmp ch,11 ; Complete file name je cmf12c ; Yes, don't beep cmf12b: mov ah,conout ; Beep, if not recognized mov dl,bell int dos ; Ring the bell cmf12c: jmp repars cmif13: mov ah,ch ; It must be a terminator cmp ah,0 ; Test the length of the file name jnz cmf3x cmp comand.cmcr,1 ; Is zero length OK? [21a] je cmf3z ; Return successfully. [21a] jmp cmifi9 ; If zero complain cmf3x: cmp ah,0DH js cmf3y jmp cmifi9 ; If too long complain cmf3y: jmp rskp ; Otherwise we have succeeded cmf3z: push es mov ax,ds mov es,ax mov di,comand.cmfcb inc di mov cx,11 mov al,'?' repne stosb pop es mov flags.wldflg,0FFH ; Remember we had a wildcard jmp rskp cmifi2: cmp ah,'.' jne cmifi3 inc ch mov ah,ch cmp ah,1H ; Any chars yet? jnz cmf2x jmp cmifi9 ; No, give error cmf2x: cmp ah,0AH ; Tenth char? js cmf2y jmp cmifi9 ; Past it, give an error cmf2y: mov dl,9H mov dh,0 mov bx,comand.cmfcb add bx,dx ; Point to file type field mov comand.cmfcb2,bx mov ch,9H ; Say we've gotten nine jmp cmifi1 ; Get the next char cmifi3: cmp ah,':' jne cmifi4 inc ch cmp ch,2H ; Is it in right place for a drive? je cmif3x jmp cmifi9 ; If not, complain cmif3x: mov ch,0 ; Reset char count mov flags.droflg,1 ; Override default drive. [21a] mov flags.nmoflg,0 ; Not so fast. [21a] mov bx,comand.cmfcb2 mov al,':' ; Use for parsing drive name mov [bx],al dec bx ; Point to drive spec mov si,bx push es mov ax,ds mov es,ax mov di,offset tbuff ; Borrow this buffer mov ah,prsfcb int dos pop es cmp al,0 ; OK return code? je cmif3y ; Yes, keep going ; mov ah,[bx] ; Get the drive name ; sub ah,'@' ; Get the drive number ; cmp ah,drives ; Did user specify a non-existant drive? [21a] ; jle cmif3y ; Nope, so continue. [21a] mov dx,offset cmer07 ; Fail with this error message. [21a] jmp cmif9x ; [21a] cmif3y: mov comand.cmfcb2,bx ; Put rest of filename starting here. [21a] mov ah,[bx] ; Pick up drive specified sub ah,'@' ; Get real value mov bx,comand.cmfcb mov [bx],ah ; Put it in the fcb push bx mov al,' ' ; Overwrite the drive and ":" inc bx mov [bx],al inc bx mov [bx],al pop bx jmp cmifi1 cmifi4: cmp ah,'*' jne cmifi7 cmp comand.cmrflg,1 ; In receive mode? [21a] jne cmif4x ; Jump out of range. [21a] mov dx,offset cmer06 ; Set the error message. [21a] jmp cmif9x ; Fail - no wildcard allowed. [21a] cmif4x: mov ah,ch ; [21a] cmp ah,8H ; Is this in the name or type field? jns cmifi5 ; Type mov cl,8H ; Say we have eight chars js cmifi6 ; Name field jmp cmifi9 ; If its where the dot should be give up cmifi5: mov cl,0CH ; Three chars cmifi6: mov flags.wldflg,0FFH ; Remember we had a wildcard mov bx,comand.cmfcb2 ; Get a pointer into the FCB mov ah,'?' mov [bx],ah ; Put a question mark in inc bx mov comand.cmfcb2,bx inc ch mov ah,ch cmp ah,cl jl cmifi6 ; Go fill in another jmp cmifi1 ; Get the next char cmifi7: cmp ah,03DH ; Equals sign (wildcard)? jne cmif7x cmp comand.cmrflg,1 ; In receive mode? [21a] jne cmif7y ; No, so it's ok. [21a] mov dx,offset cmer06 ; Set the error message. [21a] jmp cmif9x ; Fail - no wildcard allowed. [21a] cmif7y: mov ah,'?' ; New label. [21a] mov flags.wldflg,0FFH ; Say we have a wildcard jmp cmifi8 ; Put into FCB cmif7x: cmp ah,'0' jl cmif8x cmp ah,'z'+1 jns cmif8x cmp ah,'A' ; Don't capitalize non-alphabetics jl cmifi8 and ah,137O ; Capitalize cmifi8: mov bx,comand.cmfcb2 ; Get the pointer into the FCB mov [bx],ah ; Put the char there inc bx mov comand.cmfcb2,bx mov flags.nmoflg,1 ; Overriding name from host. [21a] inc ch jmp cmifi1 cmif8x: push es mov cx,ds mov es,cx ; Scan uses ES register mov di,offset spchar ; Special chars mov cx,spclen ; How many of them cmp dosnum,0 ; Under version 2.0 je cmif8y mov di,offset spchar2 mov cx,spc2len cmif8y: mov al,ah ; Char is in al repnz scasb ; Search string for input char cmp cx,0 ; Was it there? pop es jnz cmifi8 cmifi9: mov dx,offset cmer02 cmif9x: mov ah,prstr int dos mov flags.droflg,0 ; Not overriding drive. [21a] mov flags.nmoflg,0 ; Or name to save file under. [21a] mov comand.cmrflg,0 ; Reset this flag too. [21a] ret cmofil: jmp cmifil ; For now, the same as CMIFI ; Parse arbitrary text up to a CR. Put chars into data buffer sent to ; the host (pointed to by BX). Called with text of help message in DX ; Return updated pointer in BX and input size in AH cmtext: mov comand.cmptab,bx ; Save pointer to data buffer. [8 start] mov cmthlp,dx ; Save the help message mov cl,0 ; Init the char count cmtxt1: mov comand.cmsflg,0 ; Get all spaces. [25] call cmgtch ; Get a char test ah,80H ; is high-order bit on? jz cmtxt5 ; Nope, put into the buffer and ah,07FH cmp ah,' ' je cmtxt5 cmp ah,esc ; An escape? jne cmtxt2 mov ah,conout mov dl,bell ; Ring a bell int dos mov comand.cmaflg,0 ; Reset action flag dec comand.cmcptr ; Move pointer to before the escape dec comand.cmdptr dec comand.cmccnt ; Decrement count jmp cmtxt1 ; Try again cmtxt2: cmp ah,'?' ; Asking a question? jz cmtx30 cmp ah,ff ; Formfeed? jne cmtx2x call cmblnk cmtx2x: mov ah,cl ; Return count in AH mov bx,comand.cmptab ; Return updated pointer jmp rskp cmtx30: mov comand.cmaflg,0 ; Reset action flag to zero inc comand.cmdptr ; count the ? cmp cl,0 ; Is "?" first char? jne cmtxt5 ; No, just add to buffer mov ah,prstr ; Else, give some help mov dx,cmthlp ; Address of help message int dos mov ah,prstr mov dx,offset crlf ; Print a crlf int dos mov ah,prstr mov dx,comand.cmprmp ; Reprint the prompt int dos dec comand.cmcptr ; Don't keep it in the buffer dec comand.cmccnt ; Don't conut it dec comand.cmdptr ; don't count if printing help mov bx,comand.cmdptr ; Get the pointer into the buffer mov byte ptr [bx],'$' mov ah,prstr mov dx,offset comand.cmdbuf ;[fjj] RE-display command buffer int dos ; [fjj] AFTER adjusting pointers!!! jmp cmtxt1 ; And keep going cmtxt5: inc cl ; Increment the count mov bx,comand.cmptab ; Pointer into destination array mov [bx],ah ; Put char into the buffer inc bx mov comand.cmptab,bx jmp cmtxt1 ; [8 end] cmgetc: cmp taklev,0 jne cmget1 jmp cmge10 ; no take file, get from keyboard cmget1: push bx push si mov bx,takadr mov ax,[bx].takcnt or ax,[bx].takcnt+2 jnz cmget5 cmget2: mov al,byte ptr [bx].takfcb ; get first byte of fcb cmp al,0ffh ; is it really a macro? je cmget4 ; yes, better not try to close it cmp al,0feh ; or maybe a file handle? je cmget3 ; yes, close w/2.0 call mov ah,closf lea dx,[bx].takfcb int dos jmp short cmget4 ; skip over alternate close cmget3: mov bx,word ptr [bx].takfcb+1 ; this is where file handle is stored mov ah,close2 ; use 2.0 close int dos cmget4: dec taklev sub takadr,size takinfo pop si pop bx mov al,cr ; end with carriage return.. ret cmget5: cmp [bx].takchl,0 ; Any chars left in buffer? jne cmget6 call takrd cmget6: dec [bx].takchl sub [bx].takcnt,1 ; DEC doesn't set carry!! sbb [bx].takcnt+2,0 mov si,[bx].takptr lodsb mov [bx].takptr,si cmp al,ctlz ; maybe control-z? je cmget2 ; yes, close take file (has to be before pops) pop si pop bx cmp al,lf ; linefeed? jne cmget7 cmp flags.takflg,0 je cmgetc ; yes, ignore it cmget7: cmp flags.takflg,0 ; Echo contents of take file? je cmget8 push dx mov dl,al mov ah,conout int dos pop dx cmget8: ret ; else just return.. cmge10: cmp In_menu_mode, 0 ; Are we in menu mode? je KER_1 ; No ; In menu mode and not reading from a take file, so it must be time ; to redisplay the menu .. call Quick_menu ; Display the menu nop nop nop mov ah, PrStr ; Type string mov dx, OFFSET CrLf ; CRLF int Dos ; Makes screen look nicer jmp CmGetC ; Go get the first character from the newly ; created Pseudo-Macro KER_1: cmp PC_Type, 2 ; Running on a DEC Rainbow jNE IBMpcs ; No - skip Rainbow code ; Machine-specific code for DEC Rainbow cmge10_b: push es ; Firmware eats this one Mov di, 6 Int 18h ; Get level 1 char pop es ; Restore register cmp cl, 0ffh ; Did we get a char? jE Check_for_DO ; Yes - go check it cmp cl, 0 ; No - jE cmge10_b ; keep looking for one cmp cl, 1 ; Level 2 char around? (probably type-ahead) jE IBMpcs ; Yes - go handle it jmp cmge10_b ; No - we've checked all possibilities, ; something fishy goin' on - try again Check_for_DO: test ah, 1 ; Function flag on? jZ No_DO ; No - this can't be the DO key cmp al, 1 ; Yes - ; but is this really the DO key? jE Quick_Term ; Yes - it was the DO key, go into ; terminal emulation mode ; No - some other function key was pressed Call Check_for_sensible_func_keys ; If Keypad number or '-', ',' ; '.', or ENTER ; translate to sensible scan code jmp No_DO ; If normal return, a sensible key was found Call Beep ; Else if skip return some nonsensible ; function key was pressed - make a beep jmp cmge10_b ; and try again Quick_Term: mov ah, PrStr ; Code to type a string mov dx, OFFSET DO_str ; Mark that the user hit the DO key int Dos jmp Enter_TE_mode ; Enter Terminal Emulation mode No_DO: mov ah, coninq ; Make it look like a generic DOS function call jmp cmge11_A0 ; and join common code with char in al ; Assume at this point that we are an IBM PC or close clone IBMpcs: mov ah,coninq ; Get a char cmp flags.debug,0 ; in debug mode? je cmge11 ; yes, go on mov ah,8 ; else use read that recognizes ^C cmge11: int dos cmge11_A0: push ax ; save the char ; See if what we have is a special character or al, al ; Is this char a zero? jnz cmge11_a ; No, continue mov ah, 8 ; Get another char int dos ; to see what we really got the first time ; Maybe quick entry into Terminal Emulation mode cmp al, 63 ; Is it the code for F5? je Is_F5 ; Yes cmp al, 108 ; Is it the code for ALT F5? je Is_F5 ; Yes cmp al, 110 ; ALT F7 (exit) ? je Is_ALT_F7 ; Yes cmp al, 111 ; ALT F8 (push) ? je Is_ALT_F8 ; Yes jmp Ignore_key ; Not a key we work with Is_F5: mov ah, PrStr ; Code to type a string mov dx, OFFSET F5_str ; Mark that the user hit the F5 key int Dos Enter_TE_mode: mov sp, OldStk ; Pick up the value SP had before COMND ; was called mov ax, OFFSET KrmRet ; The return addr that would have been set push ax ; Put it on the stack jmp Telnet2 ; Jump quickly into terminal emulation mode Is_ALT_F7: mov sp, OldStk ; Pick up the value SP had before COMND ; was called mov flags.extflg, 0FFh ; Flag that we are leaving mov ax, OFFSET KrmRet ; The return addr that would have been set push ax ; Put it on the stack jmp RSkp ; Exit the program Is_ALT_F8: mov sp, OldStk ; Pick up the value SP had before COMND ; was called mov ax, OFFSET KrmRet ; The return addr that would have been set push ax ; Put it on the stack jmp Quick_Push ; Push out of the program Ignore_key: pop ax ; Fix up stack jmp cmge10 ; Then go get a new key cmge11_a: cmp al,bs ; backspace? je cmge13 ; yes, skip echo cmp al,' ' ; printable? jae cmge12 ; yes, no translation needed cmp al,cr ; this is printable jne cmge11_b mov dl, al ; Hit CR, first echo it mov ah, conout int Dos mov al, Lf ; Then type a LF jmp SHORT cmge12 cmge11_b: cmp al,lf je cmge12 cmp al,tab je cmge12 mov al,' ' ; else echo a space cmge12: mov dl,al ; put char here mov ah,conout int dos ; echo it ourselves.. cmge13: pop ax ; and return it cmp al,'C'-40H ; control-C? je cmge15 ; yes, go handle cmp al,tab jne cmge14 mov al,' ' cmge14: ret PUBLIC cmge15 cmge15: mov dx,offset ctcmsg mov ah,prstr int dos mov flags.cxzflg,'C' ; remember ^C'd mov sp,cmdstk ; restore command stack ptr ret ; and fail ; Come here is user types ^W when during input cntrlw: mov ah,prstr mov dx,offset escspc int dos dec comand.cmccnt ; Don't include it in the count dec comand.cmcptr ; Back up past the ^W mov cl,comand.cmccnt mov ch,0 jcxz ctlw2 pushf push es std ; Scan backwards mov ax,ds mov es,ax ; Point to the data area mov di,comand.cmcptr ; Looking from here dec di mov al,' ' repe scasb ; Look for non-space je ctlw1 ; All spaces, nothing else to do inc di ; move back to non-space inc cx repne scasb ; look for a space jne ctlw1 ; no space, leave ptrs alone inc di inc cx ; skip back over space ctlw1: inc di mov comand.cmccnt,cl ; update count mov cx,comand.cmcptr ; remember old ptr mov comand.cmcptr,di ; update pointer sub cx,di ; this is characters moved mov al,bs ; backspace cld mov di,offset tbuff ; temporary buffer rep stosb ; put enough spaces in mov byte ptr [di],'$' ; end buffer mov dx,offset tbuff mov ah,prstr int dos ; back up cursor call clearl ; clear line pop es popf ret ; and return ctlw2: mov ah,conout mov dl,bell int dos ret cminbf: push dx push bx mov cx,dx ; Save value here too mov ah,comand.cmaflg ; Is the action char flag set? cmp ah,0 je cminb1 jmp cminb9 ; If so get no more chars cminb1: inc comand.cmccnt ; Increment the char count call cmgetc mov ah,al ; Keep char in 'ah' mov bx,comand.cmcptr ; Get the pointer into the buffer mov [bx],ah ; Put it in the buffer inc bx mov comand.cmcptr,bx cmp ah,'W'-64 ; Is it a ^W? jne cmnb11 call cntrlw ; Kill the previous word jmp repars cmnb11: cmp ah,25O ; Is it a ^U? jne cminb2 cmnb12: call ctlu ; Clear out the line mov ah,prstr mov dx,comand.cmprmp ; Print the prompt int dos mov bx,offset comand.cmdbuf mov comand.cmcptr,bx ; Reset the point to the start mov comand.cmccnt,0 ; Zero the count mov dx,cx ; Preserve original value of dx jmp repars ; Go start over cminb2: cmp ah,bs ; Or backspace? jz cminb3 cmp ah,del ; Delete? jne cminb4 cminb3: call dodel ; Delete a character mov ah,comand.cmccnt ; Decrement the char count by two dec ah dec ah cmp ah,0 ; Have we gone too far? jns cmnb32 ; If not proceed mov ah,conout ; Ring the bell mov dl,bell int dos jmp cmnb12 ; Go reprint prompt and reparse cmnb32: mov comand.cmccnt,ah ; Save the new char count mov ah,prstr ; Erase the character mov dx,offset clrspc int dos mov bx,comand.cmcptr ; Get the pointer into the buffer dec bx ; Back up in the buffer dec bx mov comand.cmcptr,bx jmp repars ; Go reparse everything cminb4: cmp ah,'?' ; Is it a question mark jz cminb6 cmp ah,esc ; Is it an escape? jz cminb8 cmp ah,cr ; Is it a carriage return? jz cminb5 cmp ah,lf ; Is it a line feed? jz cminb5 cmp ah,ff ; Is it a formfeed? jne cminb7 call cmblnk call locate cminb5: mov ah,comand.cmccnt ; Have we parsed any chars yet? cmp ah,1 jnz cminb6 jmp prserr ; If not, just start over cminb6: mov ah,0FFH ; Set the action flag mov comand.cmaflg,ah jmp cminb9 ; Got a non-action char, see if it would be the last in the buffer . ; If so, we trash it and beep, since we need to get an action char and ; there wouldn't be room for it otherwise cminb7: mov ah, comand.cmccnt ; Get current char count cmp ah, cmdlen-1 ; Max'ed out? jnl cminb71 ; Yeah, bomb it jmp cminb1 ; No sweat, go get another cminb71: dec comand.cmccnt ; About to blow buffer, back up by 1 char dec comand.cmcptr ; Back up ptr too . mov ah, PrStr ; Print the string mov dx, OFFSET ESCSpc ; String containing BS, space, BS int DOS mov ah, conout ; Then ring the bell mov dl,bell int DOS jmp cminb1 ; Get another char cminb8: mov ah,prstr ; Don't print the escape char mov dx,offset escspc int dos jmp cminb6 cminb9: pop bx pop dx ret cmgtch: push cx push bx push dx cmgtc1: mov ah,comand.cmaflg cmp ah,0 ; Is it set jne cmgt10 call cminbf ; If the action char flag is not set get more cmgt10: mov bx,comand.cmdptr ; Get a pointer into the buffer mov ah,[bx] ; Get the next char inc bx mov comand.cmdptr,bx cmp ah,' ' ; Is it a space? jz cmgtc2 cmp ah,tab ; Or a tab? jne cmgtc3 cmgtc2: mov ah,comand.cmsflg ; Get the space flag cmp ah,0 ; Was the last char a space? jne cmgtc1 ; Yes, get another char mov ah,0FFH ; Set the space flag mov comand.cmsflg,ah mov ah,' ' pop dx pop bx jmp cmgtc5 cmgtc3: mov al,0 mov comand.cmsflg,al ; Zero the space flag pop dx pop bx cmp ah,esc jz cmgtc5 cmp ah,'?' ; Is the user curious? jz cmgtc4 cmp ah,cr jz cmgtc4 cmp ah,lf jz cmgtc4 cmp ah,ff je cmgtc4 pop cx ret ; Not an action char, just return cmgtc4: dec comand.cmdptr cmgtc5: or ah,80H ; Make the char negative to indicate pop cx ret ; it is a terminator CMND ENDP ; This address is jumped to on reparse PARSE PROC NEAR repars: mov sp,comand.cmostp ; new sp <-- old sp mov bx,offset comand.cmdbuf mov comand.cmdptr,bx mov ah,0FFH mov comand.cmsflg,ah jmp comand.cmrprs ; go back to reparse address ; This address can be jumped to on a parsing error prserr: mov sp,comand.cmostp ; Set new sp to old one mov bx,offset comand.cmdbuf mov comand.cmcptr,bx ; Initialize the command pointer mov comand.cmdptr,bx mov ah,0 mov comand.cmaflg,ah ; Zero the flags mov comand.cmccnt,ah mov comand.cmsflg,0FFH cmp taklev,0 ; in take cmd? jne prser1 ; yes, don't print prompt mov ah,prstr ; Print the prompt mov dx,comand.cmprmp ; Get the prompt int dos ; Instead return to before the prompt call prser1: jmp comand.cmrprs PARSE ENDP ; FCB must be remembered if found "*" in filename. [7 start] ; Copy from place addressed by BX to place addressed by DI ; Also use to get the filename to the FCB from the DTA FCBCPY PROC NEAR push es push si mov ax,ds mov es,ax ; make sure destination segment is correct mov ch,0 ; high-order part of length jcxz fcbcp1 ; zero argument (is this necessary???) mov si,bx ; this is source rep movsb ; copy the whole thing fcbcp1: pop si pop es ret ; and return FCBCPY ENDP ; Rainbow-specific routine -- ; ; During command screen input, the user may hit a keypad key desiring a ; certain number or a DASH, COMMA, PERIOD or ENTER ; Since these are 'function keys' they have strange scan codes instead of ; the correct ASCII codes - we fix 'em up here Check_for_sensible_func_keys PROC NEAR Cld ; Set direction to from Left-to-Right Mov cx, Func_table_length ; Length of translate table Mov di, OFFSET Sensible_func_keys ; Address of lookup table RepNE ScasB ; Look for function key value jE Found ; Found it! jmp Rskp ; Didn't find it - skip return ; If found translate to correct ASCII code Found: Dec di ; Make di point to found entry Sub di, OFFSET Sensible_func_keys ; Turn address into array dimension Mov al, To_ASCII_scan_codes[di] ; Translate function key to ASCII Ret ; and return Check_for_sensible_func_keys 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