home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
cpm86
/
cn8cmd.a86
< prev
next >
Wrap
Text File
|
1988-08-15
|
24KB
|
863 lines
; * * * * * * * * * * * * * * * version 2.8 * * * * * * * * * * * * * * *
; [32c] remove check for 0-length filename
; [32b] fix minor bugs
; [32a] fix prompt to show default drive and user
; RonB, 09/13/84
; * * * * * * * * * * * * * * * version 2.7 * * * * * * * * * * * * * * *
; [fdc] Fix small glitch w/CMLEVL that issued msg spuriously sometimes.
; [] Introduced CMLEVL flag to intercept "empty" command-options
; Reset by PRSERR, SET in 86KERMIT KERMIT:
; B.E.; EIBEN at DEC-MARLBORO 2-May-84
; [30c] Isolate ANSI escape sequences for machine independence.
; [30b] Make DEL work like BS and ^X like ^U in command input.
; RonB, 04/18/84
; * * * * * * * * * * * * * * * version 2.6 * * * * * * * * * * * * * * *
; [28d] Improve filename special character processing
; RonB, 03/27/84
; [25] Move logic for "seteol" and "escape" (from KERSYS) into here so those
; routines need not use internal CMD routines and variables. For this
; purpose add 2 parse routines and codes: "cmcha" and "cmnum". The point
; of this is to keep calls to CMD modular since I want to eventually
; replace the whole thing.
; R. Garland 9-Mar-1984
; * * * * * * * * * * * * * * * version 2.1 * * * * * * * * * * * * * * *
; [9] Fix filename parsing, and add wildcard ability.
; RonB,12/26/83
; [8] Show choices for ambiguous keywords, finish keyword on '?'
; RonB,12/26/83
; * * * * * * * * * * * * * * * version 2.0 * * * * * * * * * * * * * * *
; This module contains all the routines and storage necessary for the
; command parser. The command parser approximates that of the Tops-20
; COMND% JSYS. This code is adapted from the IBM PC Kermit code which
; was adapted from the CP/M-80 Kermit code.
; COMND definitions.
cmcfm equ 01H
cmkey equ 02H
cmifi equ 03H
cmofi equ 04H
cmtxt equ 05H
cmcha equ 06H
cmnum equ 07H
DSEG $ ; Resume the data segment.
; COMND storage.
cmer00 db bell,'?Program error -- Invalid COMND call$'
cmer01 db bell,'?Ambiguous command$'
cmer02 db bell,'?Illegal input file spec$'
cmer03 db bell,'?Unrecognized instruction$'
cmer04 db bell,'?Invalid command or operand$'
cmer05 db bell,'?Missing command-option$'
cmin00 db ' Confirm with carriage return$'
cmin01 db ' Input file spec (possibly wild) $'
cmin02 db ' One of the following:$' ;[8]
cmlevl db 0 ;0 at main-level, 1 otherwise
cmstat db 0 ;What is presently being parsed.
cmaflg db 0 ;Non-zero when an action char has been found.
cmccnt db 0 ;Non-zero if a significant char is found.
cmsflg db 0 ;Non-zero when the last char was a space.
cmostp dw 0 ;Old stack pointer for reparse.
cmrprs dw 0 ;Address to go to on reparse.
cmprmp dw 0 ;Address of prompt.
cmptab dw 0 ;Address of present keyword table.
cmhlp dw 0 ;Address of present help.
cmdbuf rb 80H ;Buffer for command parsing.
cmfcb dw 0 ;Pointer to FCB.
cmfcb2 dw 0 ;Pointer to position in FCB.
cmcptr dw 0 ;Pointer for next char input.
cmdptr dw 0 ;Pointer into the command buffer.
cmsiz dw 0 ;Size info of user input.
cmkptr dw 0 ;Pointer to keyword.
cmsptr dw 0 ;Place to save a pointer.
cmchr db 0 ;Save char when checking ambiguity.
cmten dw 10 ;the number "10"
spchar db '!#$%&()+-/@\^`|~0000' ;Valid special characters ;[8][28d]
; This set of routines provides a user oriented way of parsing
; commands. It is similar to that of the COMND JSYS in TOPS-20.
CSEG $ ;Resume coding.
; This routine prints the prompt in DX and specifies the reparse
; address.
prompt: pop bx ;Get the return address.
push bx ;Put it on the stack again.
mov cmrprs, bx ;Save as addr to go to on reparse.
mov bx, 0 ;Clear out register.
add bx, sp ;Get the present stack pointer.
mov cmostp, bx ;Save for later restoral.
mov cmprmp, dx ;Save pointer to the prompt.
mov bx, offset cmdbuf
mov cmcptr, bx ;Initialize the command pointer.
mov cmdptr, bx
mov cmaflg, 0 ;Zero the flags.
mov cmlevl, 0 ;[fdc]Including the level-flag
mov cmccnt, 0
mov cmsflg, 0FFH
reprompt: ;[32a] begin
call tcrlf
repmt2: mov dx, cmprmp ;Print the prompt.
call tmsg
mov dl,defdrv ;Print the default drive and user
add dl,'A'
call bout
mov al,defusr
cbw
or ax,ax ;Only print the user number if nonzero
jz repmt3
call nout
repmt3: mov dl,'>'
call bout ;[32a] end
ret
; This address is jumped to on reparse.
repars: mov sp, cmostp ;new sp <-- old sp
mov bx, offset cmdbuf
mov cmdptr, bx
mov cmsflg, 0FFH
mov bx, cmrprs ;Get the reparse address.
jmp bx ;Go there.
; This address can be jumped to on a parsing error.
prserr: mov ah, cmlevl ;What level are we in?
cmp ah, 0 ;
jz prser1 ;skip error-message
mov dx, offset cmer05 ;we're out of main-commands
call tcrmsg ;and got an empty option
mov cmlevl, 0 ;reset level-flag
prser1: mov sp, cmostp ;Set new sp to old one.
mov bx, offset cmdbuf
mov cmcptr, bx ;Initialize the command pointer.
mov cmdptr, bx
mov cmaflg, 0 ;Zero the flags.
mov cmccnt, 0
mov cmsflg, 0FFH
call reprompt ;[32a]
mov bx, cmrprs
jmp bx
; 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)
comnd: mov cmstat, ah ;Save what we are presently parsing.
call cminbf ;Get chars until an action or a erase char.
mov ah, 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.
jnz cm4
jmp cmtext
cm4: cmp ah, cmcha ;[25] parse a single character?
jnz cm5 ;[25]
jmp cmchar ;[25] go do it.
cm5: cmp ah, cmnum ;[25] parse a (decimal) number?
jnz cm99 ;[25]
jmp cmnumr ;[25] go do it.
cm99: mov dx, offset cmer00 ;"?Unrecognized COMND call" [25]
call tcrmsg
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 dl, bell ;Get a bell.
call bout ;Output the char.
mov cmaflg, 0 ;Turn off the action flag.
mov bx, cmcptr ;Move the pointer to before the escape.
dec bx
mov cmcptr, bx
mov cmdptr, bx
dec cmccnt ;Decrement the char count.
jmp cmcfrm ;Try again.
cmcfr2: cmp ah, '?' ;Curious?
jne cmcfr3
mov dx, offset cmin00 ;Print something useful.
call tmsg
call reprompt ;Reprint the prompt ;[32a]
mov bx, cmdptr ;Get the pointer into the buffer.
mov ah, '$' ;Put a $ there for printing.
mov [bx], ah
mov bx, cmcptr
dec bx ;Decrement & save the buffer pointer.
mov cmcptr, bx
mov dx, offset cmdbuf
call tmsg
mov cmaflg, 0 ;Turn off the action flag.
jmp repars ;Reparse everything.
cmcfr3: ;[8] begin
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 cmhlp, bx ;Save the help string.
mov cmptab, dx ;Save the beginning of keyword table.
mov bx, dx
mov ch, [bx] ;Get number of entries in table.
inc bx
mov dx, cmdptr ;Save command pointer.
mov cmsptr, dx ;Save pointer's here.
cmky1: cmp ch, 0 ;Any commands left to check?
jne cmky2
ret
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?
je cmky3y
cmp ah, ' '+80H ;A space?
je cmky3y
cmp ah, cr+80H ;Carriage return?
je cmky3y
jmp cmky38
cmky3y: mov cmkptr, bx ;Save bx here.
mov cmsiz, cx ;Save size info.
mov cmchr, ah ;Save char for latter.
call cmambg ;See if input is ambiguous or not.
jmp cmky32 ;Succeeded (not ambiguous).
mov ah, cmchr
cmp ah, esc+80H ;Escape?
; Display keyword choices and reparse if ambiguous ;[8] begin
je cmky3a
cmp ah, ' '+80H ;Space?
jne cmky3b
cmky3a: dec cmdptr ;If so, back up over it.
cmky3b: mov dx, offset cmin02 ;'One of the following:'
call tcmsgc
mov bx, cmkptr ;Find beginning of current keyword
mov cx, cmsiz
cmky3c: dec bx ;We are 'cl' characters into it
dec cl
jnz cmky3c
inc bx
mov cmkptr, bx ;Save beginning of keyword
cmky3d: mov dl, tab ;Precede each keyword with a tab
call bout
mov dx,cmkptr ;and display the keyword
call tmsg
mov bx, cmkptr ;Move to the next keyword
cmky3e: inc bx
cmp byte ptr [bx], '$'
jnz cmky3e
add bx,4 ;Bypass '$', 2-byte return value, next length
mov di, cmkptr ;Get previous keyword for comparison
mov cmkptr, bx ;and save beginning of this keyword
mov cx, cmsiz ;Get number of characters to match
dec ch ;Are we at end of table?
js cmky3g ; Yes, quit displaying
mov cmsiz, cx
cmky3f: dec cl
jz cmky3d ;This keyword also matches to 'cl' places
mov ah,[bx] ;Compare this keyword to last
cmp ah,[di]
jne cmky3g
inc di
inc bx
jmps cmky3f
cmky3g: jmp cmky50 ;Not equal or end of table, redisplay prompt
;[8] end
cmky32: mov cx, cmsiz ;Restore info.
mov bx, cmkptr ;Our place in the keyword table.
cmk32a: cmp cmchr, ' '+80H ;Space? ;[8]
je cmky35
cmp cmchr, cr+80H ;Carriage return?
je cmky35
dec cmcptr ;Pointer into buffer of input.
mov dx, 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 cmccnt
jmp cmky33
cmky34: push bx ;Save pointer to return value ;[8]
mov ah, ' '
mov di, dx
mov [di], ah ;Put a blank in the buffer.
inc dx
mov cmdptr, dx ;[8] begin
cmp cmchr, '?'+80H ;Question mark?
jne cmk34a
mov ah, '?'
mov di,dx
mov [di], ah
inc dx
inc cmccnt
push dx
mov dl, 08H ;Erase question mark from display
call bout
pop dx
cmk34a: mov cx, cmcptr ;Remember where we were (for printing below).
mov cmcptr, dx ;Update our pointers. ;[8] end
mov ah, '$'
mov di, dx
mov [di], ah ;Add '$' for printing.
mov dx, cx ;Point to beginning of filled in data.
call tmsg
pop bx ;Recover pointer to return value ;[8]
inc bx ;Point to address we'll need.
mov bx, [bx]
cmp cmchr, 0BFH ;Question mark? ;[8] begin
je cmk34b
mov cmaflg, 0 ;If esc, turn off action flag
mov cmsflg, 0FFH ; and pretend they typed a space
cmk34b: jmp rskp ;[8] end
cmky35: mov ah, [bx] ;Find end of keyword.
inc bx
cmp ah, '$'
jne cmky35
mov bx, [bx] ;Address of next routine to call.
jmp rskp
cmky38: cmp ah, al
jne cmky6 ;Go to end of keyword and try next.
jmp cmky3
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, esc ;Ignore escape?
je cmky43
cmky41: mov dx, offset cmer03
call tcrmsg
jmp prserr ;Parse error - give up.
cmky43: mov dl, bell ;Ring a bell.
call bout
mov bx, cmcptr
dec bx
mov cmcptr, bx
mov cmdptr, bx
dec cmccnt ;Don't count the escape.
mov cmaflg, 0 ;Reset action flag.
inc ch ;Account for a previous 'dec'.
jmp cmky1 ;Start over.
cmky5: mov dx,cmhlp ;Print the help text.
call tcmsgc
cmky50: call reprompt ;Reprint the prompt ;[32a]
mov bx,cmdptr ;Get pointer into buffer.
mov al, '$'
mov [bx], al ;Add dollar sign for printing.
mov dx, offset cmdbuf
call tmsg
mov bx, cmdptr ;[8] begin
mov cmcptr, bx
mov dx, offset cmdbuf
sub bx, dx
mov cmccnt, bl
mov cmaflg, 0 ;Turn off the action flag.
jmp repars
cmky51: jmp prserr
cmky6: inc bx ;Find end of keyword.
mov al, [bx]
cmp al, '$'
jne cmky6
add bx, 3 ;Beginning of next command.
mov dx, cmsptr ;Get old cmdptr.
mov cmdptr, dx ;Restore.
mov 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: mov cmchr, ah ;[8] begin
jmp cmk32a
; See if keyword is ambiguous 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, 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.
; Parse an input file spec.
cmifil: mov wldflg, 0 ;Set to no wildcards. ;[9]
mov bx, dx ;Get the fcb address in bx.
mov 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 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.
jns cmifi2
and ah, 7FH ;Turn off the action bit.
cmp ah, '?' ;A question mark?
jne cmif12
mov cmaflg, 0 ;Blank the action flag.
; '?' is a legal character in wildcard filenames. ;[9] begin
; Make ESC take its place by giving info instead of beeping. ;[32b]
mov wldflg, 0FFH ;Say we have a wildcard.
inc cmdptr
jmp cmifi8 ;Accept a '?'
cmif12: cmp ah, esc ;An escape?
jne cmif13
dec cmdptr
cmf12a: mov cmaflg, 0 ;Turn off the action flag ;[9] end
dec cmcptr ;Decrement the buffer pointer.
dec cmccnt ;Decrement count.
mov dx, offset cmin01 ;Help message.
call tmsg
call reprompt ;Reprint the prompt ;[32a]
mov bx, cmdptr
mov al, '$'
mov [bx], al ;Put in dollar sign for printing.
mov dx, offset cmdbuf
call tmsg
jmp repars
cmif13: mov ah, ch ;It must be a terminator.
; The check for 0-length filenames will be performed by the ;[32c]
; caller so as to allow the file specification to be optional.
cmp ah, 0DH
js cmf3y
jmp cmifi9 ;If too long complain.
cmf3y: jmp rskp ;Otherwise we have succeeded.
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, cmfcb
add bx, dx ;Point to file type field.
mov 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 bx, cmfcb2
dec bx
mov ah, [bx] ;Get the drive name.
cmp ah,'A' ;Make sure it's in range A-P ;[9] begin
jb cmif3y
cmp ah,'P'
jbe cmif3z
cmif3y: jmp cmifi9
cmif3z: sub ah,'@' ;Get the drive number. ;[9] end
mov cmfcb2, bx
mov bx, cmfcb
mov [bx], ah ;Put it in the fcb.
jmp cmifi1
cmifi4: cmp ah, '*'
jne cmifi7
mov ah, ch
cmp ah, 8H ;Is this in the name or type field?
jz cmifi9 ;If its where the dot should be give up.
jns cmifi5 ;Type.
mov cl, 8H ;Eight chars.
jmp cmifi6
cmifi5: mov cl, 0CH ;Three chars.
cmifi6: mov wldflg, 0FFH ;Remember we had a wildcard.
mov bx, cmfcb2 ;Get a pointer into the FCB.
mov ah, '?'
mov [bx], ah ;Put a question mark in.
inc bx
mov cmfcb2, bx
inc ch
mov ah, ch
cmp ah, cl
jl cmifi6 ;Go fill in another.
jmp cmifi1 ;Get the next char.
cmifi7:
cmif7x: cmp ah,'0'
jb cmif8x
cmp ah,'9'
jbe cmifi8
cmp ah,'A'
jb cmif8x
cmp ah,'Z'
jbe cmifi8
cmp ah,'a'
jb cmif8x
cmp ah,'z'
ja cmif8x ;[9] end
and ah, 137O ;Capitalize.
cmifi8: mov bx, cmfcb2 ;Get the pointer into the FCB.
mov [bx], ah ;Put the char there.
inc bx
mov cmfcb2, bx
inc ch
jmp cmifi1
cmif8x: push es ;Check list of special characters
mov cx, ds ; which are legal in filenames
mov es, cx ;Scan uses ES register.
mov di, offset spchar ;Special chars.
mov cx, 20 ;Twenty of them.
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
call tcrmsg
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). Return updated pointer in BX and
; input size in AH.
cmtext: mov cmptab, bx ;Save pointer to data buffer.
mov cl, 0 ;Init the char count.
cmtxt1: call cmgtch ;Get a char.
cmp ah, 0 ;Terminator?
jns cmtxt5 ;Nope, put into the buffer.
and ah, 07FH
cmp ah, esc ;An escape?
jne cmtxt2
mov dl, bell ;Ring a bell.
call bout
mov cmaflg, 0 ;Reset action flag.
dec cmcptr ;Move pointer to before the escape.
dec cmdptr
dec cmccnt ;Decrement count.
jmp cmtxt1 ;Try again.
cmtxt2: cmp ah, '?' ;Asking a question?
jz cmtx2y ;[32b]
cmp ah, ' ' ;Space? ;[32b]
jz cmtxt3
cmp ah, ff ;Formfeed?
jne cmtx2x
call clrscr
cmtx2x: mov ah, cl ;Return count in AH.
mov bx, cmptab ;Return updated pointer.
jmp rskp
cmtx2y: inc cmdptr ;[32b]
cmtxt3: mov cmaflg, 0 ;Reset action flag to zero.
cmtxt5: inc cl ;Increment the count.
mov bx, cmptab ;Pointer into destination array.
mov [bx], ah ;Put char into the buffer.
inc bx
mov cmptab, bx
jmp cmtxt1
cminbf: push dx
push bx
mov cx, dx ;Save value here too.
mov ah, cmaflg ;Is the action char flag set?
cmp ah, 0
je cminb1
jmp cminb9 ;If so get no more chars.
cminb1: inc cmccnt ;Increment the char count.
call bin
mov ah, al ;Keep char in 'ah'.
mov bx, cmcptr ;Get the pointer into the buffer.
mov [bx], ah ;Put it in the buffer.
inc bx
mov cmcptr, bx
cmp ah, 15h ;Is it a ^U?
je cmnb12 ;[30b]
cmp ah, 18h ; or ^X? ;[30b]
jne cminb2
cmnb12: call clrlin ;[30c]
call repmt2 ;Reprint the prompt (no crlf) ;[32a]
mov bx, offset cmdbuf
mov cmcptr, bx ;Reset the point to the start.
mov cmccnt, 0 ;Zero the count.
mov dx, cx ;Preserve original value of dx.
jmp repars ;Go start over.
cminb2: cmp ah, 08h ;Is it a backspace? ;[30b]
jz cminb3
cmp ah, 7fh ; or delete? ;[30b]
jne cminb4
mov dx, offset delstr
call tmsg
cminb3: mov ah, 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 dl, bell ;Ring the bell.
call bout
jmp cmnb12 ;Go reprint prompt and reparse.
cmnb32: mov cmccnt, ah ;Save the new char count.
mov dx, offset clrspc ;Erase the character.
call tmsg
mov bx, cmcptr ;Get the pointer into the buffer.
dec bx ;Back up in the buffer.
dec bx
mov 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 cminb6
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 clrscr
cminb5: mov ah, cmccnt ;Have we parsed any chars yet?
cmp ah, 1
jnz cminb6
jmp prserr ;If not, just start over.
cminb6: mov cmaflg, 0FFH ;Set the action flag.
jmp cminb9
cminb7: jmp cminb1 ;Get another char.
cminb9: pop bx
pop dx
ret
cmgtch: push cx
push bx
push dx
cmgtc1: mov ah, cmaflg
cmp ah, 0 ;Is it set.
jne cmgt10
call cminbf ;If the action char flag is not set get more.
cmgt10: mov bx, cmdptr ;Get a pointer into the buffer.
mov ah, [bx] ;Get the next char.
inc bx
mov cmdptr, bx
cmp ah, ' ' ;Is it a space?
jz cmgtc2
cmp ah, tab ;Or a tab?
jne cmgtc3
cmgtc2: mov ah, cmsflg ;Get the space flag.
cmp ah, 0 ;Was the last char a space?
jne cmgtc1 ;Yes, get another char.
mov cmsflg, 0FFH ;Set the space flag.
mov ah, ' '
pop dx
pop bx
jmp cmgtc5
cmgtc3: mov cmsflg, 0 ;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 cmgtc6 ;[8]
cmp ah, ff
je cmgtc6 ;[8]
pop cx
ret ;Not an action char, just return.
cmgtc6: mov ah, cr ;Convert lf & ff to cr ;[8]
cmgtc4: dec cmdptr
cmgtc5: or ah, 80H ;Make the char negative to indicate
pop cx ;it is a terminator.
ret
; Parse a single character ;[25] start
; this is for setting the escape character
cmchar:
call cmgtch ;get a char
cmp ah, 0
jns cmchr1 ;go if not negative
and ah, 7FH ;turn off sign bit
cmp ah, '?' ;user curious?
jne cmchr0 ;no - an error
mov dx, bx ;help string pointer was in bx
call tmsg ;print help stuff ;[32a]
call reprompt ;Reprint the prompt ;[32a]
mov bx, cmdptr
mov al, '$'
mov [bx], al ;add a "$" to what was typed
mov dx, offset cmdbuf
call tmsg ;type it again
dec cmcptr ;but don't leave "$" ..
dec cmccnt ;in buffer
mov cmaflg, 0 ;turn off action flag
jmp repars ;try again
cmchr0: mov dx, offset erms20
call tcrmsg ;"illegal value" error
ret
cmchr1: mov temp, ax
call cmcfrm ;get a confirm
jmp cmchr0 ;or else complain
mov ax, temp
mov bl, ah ;return the character
jmp rskp
; parse a (decimal) number. Maximum allowed value in dx
cmnumr:
mov temp1, 001H ;initial multiplier of 1
mov temp2, dx ;storage for maximum
mov temp, 0 ;zero running sum
call cmgtch ;get a char
cmp ah, 0
jns cmnum1 ;go if not negative
and ah, 7FH ;turn off sign bit
cmp ah, '?' ;user curious?
jne cmnum0 ;no - an error
mov dx, bx ;help string pointer was in bx
call tmsg ;print help stuff ;[32a]
call reprompt ;Reprint the prompt ;[32a]
mov bx, cmdptr
mov al, '$'
mov [bx], al ;add a "$" to what was typed
mov dx, offset cmdbuf
call tmsg ;type it again
dec cmcptr ;but don't leave "$" ..
dec cmccnt ;in buffer
mov cmaflg, 0 ;turn off action flag
jmp repars ;try again
call cmcfrm ;get character (or confirm)
jmp cmnum1 ;got a character
;fall through - too early for confirm
cmnum0: mov dx, offset erms20
call tcrmsg ;"illegal value" message
ret
cmnum1: sub ah, 030H ;ASCII -> binary
jl cmnum0 ;too small
cmp ah, 09H
jg cmnum0 ;too big
mov bl, ah
mov bh, 0 ;get number in low part of bx
mov ax, temp ;get running sum
mul temp1 ;multiply by decimal place value
add ax, bx ;add in this digit
cmp ax, temp2 ;over the maximum
jg cmnum0 ;yes - error
mov temp, ax ;save running sum
mov ax, temp1 ;get multiplier
mul cmten ;multiply multiplier by 10
mov temp1, ax ;save it
call cmcfrm ;get another character
jmp cmnum1 ;not terminator - process it
mov bx, temp ;get value of number
jmp rskp ;return success
;[25] end