; * * * * * * * * * * * * * * * 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