NAME msscmd ; File MSSCMD.ASM ; Edit history: ; Last edit 1 Jan 1988 ; 1 Jan 1988 version 2.30 ; 8 Oct 1987 Add syntax of "\;" is a literal semicolon and not a comment ; introducer (; prints as space, \; prints as ;) but only when doing a ; TAKE file or macro. [jrd] ; 28 Aug 1987 Show Kermit prompt when in Take file and echoing Take cmd. [jrd] ; 18 Aug 1987 Change ESC to escape, for MASM 4.5+ [jrd] ; 27 June 1987 Add allowance for bare c/r's (comand.cmcr != 0) in cminbf. ; Add global byte "intake" to say if reading from Take file (non-zero). [jrd] ; 1 Oct 1986 Version 2.29a ; 20 August 1986 Protect against buffer overflow and stop deleting of prompt ; 16 August 1986 Remove unneeded buffer tbuff. [jrd] ; 22 May 1986 Echo tabs as just a space, avoids corrupted cmd line. [jrd] ; [2.29] code frozen on 6 May 1986 [jrd] public comnd, cmcfrm, prserr, repars, cmgtch, comand public cmgetc, intake include mssdef.h datas segment public 'datas' extrn flags:byte, trans:byte extrn taklev:byte, takadr:word, dosnum:byte comand cmdinfo <> cmer00 db cr,lf,'?Program error Invalid COMND call$' cmer03 db cr,lf,'?Invalid command$' cmer04 db cr,lf,'?Invalid command or operand$' cmin00 db ' Confirm with carriage return$' cmin01 db ' One of the following:',cr,lf,'$' cmthlp dw 0 ; Text ptr to help message for cmds crlf db cr,lf,'$' ctcmsg db '^C$' prsp db ' $' ; Print a space. hlpmsg dw 0 ; Address of help message. escspc db BS,' ',BS,'$' ; Clear escape. clrspc db ' ',BS,'$' ; Clear space. temp db ? ; temp (counts char/line so far) cmdstk dw ? intake db ? ; last command line was from Take prevch db 0 ; previous char read by cmgetc noparse db 0 ; semicolons not special, if non-zero datas ends code segment public 'code' extrn dodel:near, ctlu:near, cmblnk:near, locate:near, takrd:near extrn clearl: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. mov prevch,0 ; clear old previous char mov noparse,0 ; say recognize semicolons in Take files 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 cm3 jmp cmkeyw ; Try and get one. cm3: cmp ah,cmtxt ; Parse arbitrary text. jnz cm4 jmp cmtext cm4: cmp ah,cmfile ; parse text surrounded by whitespace jnz cm5 jmp cmfil0 cm5: 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 mov comand.cmstat,cmcfm-1 ; make sure status isn't = cmcfm ret ; If not, return failure. cmcfr0: and ah,7FH ; Turn off the minus bit. cmp ah,escape ; Is it an escape? jne cmcfr2 mov ah,conout mov dl,bell ; Get a bell. int dos mov comand.cmaflg,0 ; Turn off the action flag. mov bx,comand.cmcptr ; Move pointer to before the escape. dec bx mov comand.cmcptr,bx mov comand.cmdptr,bx dec comand.cmccnt ; Decrement 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 dx,offset crlf ; Print a crlf. int dos mov dx,comand.cmprmp ; Reprint the prompt. int dos mov bx,comand.cmdptr ; Get the pointer into the buffer. mov byte ptr[bx],'$' ; Put a $ there for printing. dec comand.cmcptr ; Decrement & save the buffer pointer mov dx,offset comand.cmdbuf int dos mov comand.cmaflg,0 ; Turn off the action flag. 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, ; but they may be of mixed case. [jrd] 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 from the user cmp ah,0 ; Do we have a terminator? jns cmky2x ; ns = no jmp cmky4 ; Negative number means we do. cmky2x: inc bx ; Point to first letter of keyword. inc cl ; count the user's char mov al,[bx] call tolowr ; convert al (key) and ah (user) cmp ah,al ; do they match? je cmky3 ; e = yes jg cmky2y ; g = keychar < user's (keep looking) 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] call tolowr ; lower case the key word char cmp al,'$' ; End of keyword? jne cmky3x ; ne = not yet jmp cmky7 ; Succeed. cmky3x: mov dl,al ; Save al's char here. call cmgtch inc cl ; Read in another char. mov al,dl call tolowr ; lower case cmp ah,escape+80H ; Escape Recognition (escape w/minus bit on)? je cmky3y cmp ah,' '+80H ; A space? je cmky3y cmp ah,cr+80H ; Carriage return? je cmky3y cmp ah,'?'+80H ; A question mark? je cmky3y cmp ah,al ; user = keyword char? je cmky3 ; e = yes. Check next letter jmp cmky6 ; no. Go to end of keyword and try next cmky3y: mov comand.cmkptr,bx ; Save bx here. mov comand.cmsiz,cx ; Save size info. mov comand.cmchr,ah ; Save char for latter. cmp ah,'?'+80h ; question mark? je cmkyj1 ; yes, always print possibilities call cmambg ; See if input is ambiguous or not. jmp cmky32 ; Succeeded (not ambiguous). mov ah,comand.cmchr cmp ah,escape+80H ; Escape? je cmky3z 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. ; Question mark entered by user. Print out all the keywords that match cmkyj1: mov dx,offset cmin01 mov ah,prstr int dos mov temp,0 ; count # chars printed on this line 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 bx,comand.cmkptr ; start of keyword dec bx mov al,[bx] ; its length add temp,al ; count chars printed so far cmp temp,76 ; will this take us beyond column 78? jle cmkyj3 ; le = ok so far mov ah,prstr ; print string mov dx,offset crlf ; break the line int dos mov temp,0 ; and reset the count cmkyj3: mov dl,spc ; put two spaces before each keyword mov ah,conout int dos inc temp ; count output chars int dos inc temp 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 cmkyj4 ; l = 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 cmkyj4: 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,' '+80H ; Space? je cmky35 cmp comand.cmchr,'?'+80H ; Question mark? je cmky35 cmp comand.cmchr,cr+80H ; 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. call tolowr ; convert it to lower case 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. jmp rskp 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,escape ; 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 dec comand.cmcptr ;[ESC] don't trash BX here. dec comand.cmdptr ;[ESC] ditto 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 count 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. cmp byte ptr [bx],'$' jne cmky6 add bx,3 ; Beginning of next command. 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: cmp ah,'?'+80h ; question mark? jne cmky72 ; yes, don't return yet inc cl ; count the '?' Fix single char keywords jmp cmky3y ; and process ? correctly cmky72: inc bx ; Get necessary data. mov bx,[bx] cmp ah,escape+80h ; An escape? jne cmky73 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. cmky73: 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. call tolowr ; convert to lower case 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. ; 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. ; Produces asciiz string. Return updated pointer in BX and input size in AH. cmtext: mov comand.cmptab,bx ; Save pointer to data buffer. mov cmthlp,dx ; Save the help message. mov cl,0 ; Init the char count. cmtxt1: mov comand.cmsflg,0 ; Get all spaces. 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,escape ; 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 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 al,0 mov [bx],al ; insert null terminator mov comand.cmptab,bx jmp cmtxt1 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. dec comand.cmcptr ;[ESC] (moved 3 lines) Don't keep in buffer. dec comand.cmccnt ;[ESC] Don't count it. dec comand.cmdptr ;[ESC] don't count if printing help. 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 mov bx,comand.cmdptr ; Get the pointer into the buffer. mov byte ptr [bx],'$' mov ah,prstr mov dx,offset comand.cmdbuf int dos jmp cmtxt1 ; And keep going. ; [jrd] ; Parse arbitrary text up to whitespace. Put chars into data buffer sent to ; the host (pointed to by DX). Called with text of help message in BX. ; Produces asciiz string. Return updated pointer in DX and input size in AH. ; Skips leading whitespace. ; Does a return skip exit. Replaces old cmifi routine. cmfil0: push dx mov dx,bx ; interchange bx and bx internally pop bx mov comand.cmptab,bx ; Save pointer to data buffer. mov cmthlp,dx ; Save the help message. mov cl,0 ; Init the char count. mov comand.cmsflg,0ffH ; skip over leading spaces and tabs. cmfil1: call cmgtch ; Get a char. test ah,80H ; is high-order bit on (i.e. terminator seen)? jnz cmfi1a ; nz = yes jmp cmfil5 ; z = no, put char into the buffer. cmfi1a: and ah,07FH ; clear high order bit cmp ah,escape ; An escape? je cmfi1b ; e = yes. cmp ah,' ' ; is it a space or control char? jg cmfil2 ; g = no. keep it jmp cmfi2x ; else, a space or control char; end here. cmfi1b: mov ah,conout ; handle escape char; ie, complain 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 cmfil1 ; Try again. cmfil2: cmp ah,'?' ; Asking a question? jz cmfil3 ; z = yes cmp ah,ff ; Formfeed? jne cmfi2x ; ne = no call cmblnk ; a FF. clear the command line and end cmfi2x: mov bx,comand.cmptab ; Pointer into destination array. mov byte ptr[bx],0 ; Put null terminator into the buffer inc bx mov ah,cl ; Return count in AH. mov dx,comand.cmptab ; Return updated pointer. xchg dx,bx ; re-interchange bx and dx jmp rskp cmfil3: mov comand.cmaflg,0 ; Reset action flag to zero. inc comand.cmdptr ; count the ? cmp cl,0 ; Is "?" first char? jne cmfil5 ; No, just add to buffer. dec comand.cmcptr ;[ESC] (moved 3 lines) Don't keep in buffer. dec comand.cmccnt ;[ESC] Don't count it. dec comand.cmdptr ;[ESC] don't count if displaying help. mov ah,prstr ; Else, give some help. mov dx,cmthlp ; Address of help message. int dos mov dx,offset crlf ; Print a crlf. int dos mov dx,comand.cmprmp ; Reprint the prompt. int dos mov bx,comand.cmdptr ; Get the pointer into the buffer. mov byte ptr [bx],'$' mov dx,offset comand.cmdbuf int dos jmp cmfil1 ; And keep going. cmfil5: 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 cmfil1 ; the end of cmfil0. cmgetc: mov ah,taklev ; get current Take level mov intake,ah ; remember here for later callers cmp ah,0 ; in a Take file? jne cmget1 ; ne = yes jmp cmge10 ; no take file, get from keyboard cmget1: push bx push si mov bx,takadr mov ax,[bx].takcnt ; size of item or ax,[bx].takcnt+2 ; empty? jnz cmget5 ; nz = no cmget2: mov al,byte ptr [bx].taktyp ; get type of take cmp al,0ffh ; is it really a macro? je cmget4 ; yes, better not try to close it mov bx,word ptr [bx].takhnd ; get file handle 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... mov prevch,al ; remember last read character mov noparse,0 ret cmget5: cmp [bx].takchl,0 ; Any chars left in buffer? jne cmget6 ; ne = yes call takrd ; else read another buffer cmp [bx].takchl,0 ; anything in the file? je cmget2 ; e = no, quit 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 mov prevch,al ; remember last read character jmp cmgetc ; yes, ignore it. cmget7: cmp al,';' ; maybe a semicolon? jne cmget7c ; ne = no, accept as-is cmp prevch,5ch ; was previous char backslash escape? jne cmget9 ; ne = no, semicolon starts a comment cmp noparse,0 ; parsing this part of the command? jne cmget7a ; ne = no, observe but do not store pop bx mov bx,comand.cmcptr ; Get the pointer into the cmd buffer. mov byte ptr[bx-1],al ; stuff in the literal semicolon pop bx cmget7a:mov prevch,al ; remember last read character cmp flags.takflg,0 ; echoing take files? je cmget7b ; e = no push dx ; backspace cursor over backslash push ax ; and print the semicolon mov ah,conout mov dl,BS int dos mov dl,al int dos pop ax cmget7b:pop dx jmp cmgetc ; get next char cmget7c:mov prevch,al ; normal character acceptance pathway cmp flags.takflg,0 ; Echo contents of take file? je cmget8 ; e = no push dx mov dl,al mov ah,conout int dos pop dx cmget8: ret ; else just return... ; semicolon seen, echo and ignore chars until cr cmget9: push ax mov al,spc ; replace semicolon with a space call cmget7c ; echo the char pop ax cmget9a:mov prevch,al ; remember last read character mov noparse,1 ; defeat semicolon parsing call cmgetc ; get a character cmp al,cr ; carriage return? jne cmget9a ; no, keep reading mov prevch,al ; remember last read character mov noparse,0 ; done with escaped semicolon actions ret ; else return it cmge10: mov ah,coninq ; Get a char. int dos or al,al jnz cmge11 ; ignore null bytes of special keys int dos ; read and discard scan code byte jmp cmge10 ; try again cmge11: and al,7fh ; only allow 7-bit characters. push ax ; save the char cmp al,del je cmgex cmp al,' ' ; printable? jae cmge12 ; yes, no translation needed cmp al,cr ; this is printable je cmge12 cmp al,lf je cmge12 cmgex: mov al,' ' ; else echo a space cmge12: mov dl,al ; put char here cmp comand.cmquiet,0 ; quiet mode? jnz cmge13 ; yes, skip echoing... 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 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 backward 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 cld ; reset direction flag 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 dl,BS ; output backspaces mov ah,conout ctlw3: int dos ; backup cursor loop ctlw3 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. cmp comand.cmaflg,0 ; Is the action char flag set? je cminb1 jmp cminb9 ; If so get no more chars. cminb1: cmp comand.cmccnt,size cmdbuf ; max buffer size jb cminb1a ; b = not full push ax ; full. push dx mov ah,conout ; complain mov dl,bell int dos pop dx pop ax jmp cminb6 ; set action flag cminb1a: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: mov ah,comand.cmccnt ; Decrement the char count by two (char + BS) 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. call dodel ; Delete a character. mov ah,prstr ; Erase the character. mov dx,offset clrspc int dos dec comand.cmcptr ; Get the pointer into the buffer. dec comand.cmcptr ; Back up in the buffer. cmnb34: jmp repars ; Go reparse everything. cminb4: cmp ah,'?' ; Is it a question mark. jz cminb6 cmp ah,escape ; 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 ; FF: clear the screen and call locate ; Home the cursor. push bx ; make the FF parse like a cr mov bx,comand.cmcptr ; permanent storage of next char mov byte ptr [bx-1],cr ; pretend a carriage return were typed pop bx cminb5: cmp comand.cmccnt,1 ; Have we parsed any chars yet? jnz cminb6 cmp comand.cmcr,0 ; bare cr's allowed? jne cminb6 ; ne = yes jmp prserr ; If not, just start over. cminb6: mov comand.cmaflg,0FFH ; Set the action flag. jmp cminb9 cminb7: 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: cmp comand.cmaflg,0 ; is action flag 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: cmp comand.cmsflg,0 ; space flag, was last char a space? jne cmgtc1 ; Yes, get another char. mov comand.cmsflg,0FFH ; Set the space flag. 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,escape 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 comand.cmsflg,0ffh 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? je prser2 ; e = no cmp flags.takflg,0 ; echo contents of take file? je prser1 ; e = no prser2: mov ah,prstr mov dx,offset crlf int dos 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 ; Convert ascii characters in al and ah to lowercase. [jrd] ; All registers are preserved except AX, of course. TOLOWR PROC NEAR test ah,80H ; sign bit set? jnz tolow1 ; nz = yes cmp ah,'A' ; less that cap A? jl tolow1 ; l = yes. leave untouched cmp ah,'Z'+1 ; more than cap Z? jns tolow1 ; ns = yes. or ah,20H ; convert to lowercase tolow1: test al,80H ; sign bit set? jnz tolow2 ; nz = yes cmp al,'A' ; less that cap A? jl tolow2 ; l = yes. leave untouched cmp al,'Z'+1 ; more than cap Z? jns tolow2 ; ns = yes. or al,20H ; convert to lowercase tolow2: ret TOLOWR 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