; CPSCMD.ASM ; KERMIT - (Celtic for "FREE") ; ; This is the CP/M-80 implementation of the Columbia University ; KERMIT file transfer protocol. ; ; Version 4.0 ; ; Copyright June 1981,1982,1983,1984,1985 ; Columbia University ; ; Originally written by Bill Catchings of the Columbia University Center for ; Computing Activities, 612 W. 115th St., New York, NY 10025. ; ; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben, ; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many ; others. ; ; ; This file provides a user oriented way of parsing commands. ; It is similar to that of the COMND JSYS in TOPS-20. ; ; revision history (latest first): ; ;edit 13, 17-Jan-1991 by MF. Modified "cmifil" routine to zero the entire ; fcb (not just the extent) to fix a bug in the COPY command which ; prevented successive COPY commands from working properly. ;edit 12, 16-Jan-1991 by MF. Modified routine "cmkeyw" to ignore leading ; spaces/tabs before a keyword. This apparently was the intent in ; "prompt" and "repars" (at least for command-lines) as the variable ; "cmsflg "is set upon command parse and reparse. The intent was , ; subverted, however, as "cmkeyw" did not reset the flag to ignore ; leading white space for each search thru the key tables (even though ; the buffer pointer to the keyword entered was reset). The fix was ; to reset the "spaces seen" flag (cmsflg) after "cmkey2" so that ; it is reset each time a new table entry is compared to the text ; the user has entered from the keyboard/TAKE-file etc. The upshot ; of all this is that the kluge code in "cminbf" at "cminb0" designed ; to force Kermit to ignore leading white space on command-lines in ; TAKE-files and on the CP/M command-line is no longer needed and, ; therefore, has been eliminated. Also modify "comnd" to expect leading ; spaces for functions other than "get keyword". ;edit 11, 26-Dec-1990 by MF. Modified routines to ignore leading white space ; in lines from TAKE-files as well as during input from the CP/M ; command-line (form-feeds are now considered white space under these ; circumstances). ;edit 10, 8-Sep-1990 by Mike Freeman. Modified routines to ignore leading ; spaces/tabs when processing Kermit commands from the CP/M ; command-line. ; Added flag CMBFLG to allow initial word on a command-line ; to be blank (useful for Remote commands such as Remote CWD etc). ; Added flag cmqflg to prevent character-echoing while entering ; commands so Remote CWD etc can have nonechoing password entry. ; edit 9, 15 June, 1987 by OBSchou. Bug fixing to allow a second filename ; (quiet) be entered as d:. Previous revision put the drive name ; in first character of FCB, I put that character back to a space. ; ; edit 8, 12 June, 1987 by OBSchou. Addedin code in cmkeyw to print ; 20 lines of help, then pause for a key from the user befor ; proceeding with help. ; ; edit 7, 11 March, 1987 by OBSchou for Richard Russell, BBC. He writes: ; Bug in cmtext which prevented use of octal characters (\nnn) fixed. ; ; edit 6, 18 June, 1986 by OBSchou, Loughborough University, Leics. UK ; added code to parse a number from user input. Added check to make ; sure the input command buffer does not overflow the limit. ; ; edit 5a: 7 March, 1986. OBSchou. Added stuff rom MJ Carter. He writes: ; 7th May 85, MJ Carter [majoc], Nottingham University ; Code in cmifil() put one too many spaces in the FCB; this caused ; the BDOS of the British Micro Mimi to search for exteny 32, ; rather than extent 0, so era() always said "can't find file" ; Puttig a null at the point in question ought to fix 9 it. ; ; edit 5: 6-Feb-85 by Charles Carvalho ; Make ffussy a runtime (rather than assembly-time) switch, to ; eliminate conditional assembly in system-independent module. ; Don't allow _%|()/\ in filenames if ffussy set; my CP/M manual ; disallows those, too. ; ; edit 4: 13-Jan-85 by Vanya J.Cooper Pima Commun. College Tel: 602-884-6809 ; ;pcc006 2-jan-85 VJC modules:cp4cmd,cp4utl ; Problems with "?" in filespecs. On reparse, may cause action ; flag to be reset at wrong point, requiring multiple 's ; to terminate the line or other weird stuff. Also need to ; check flag and complain if wild-cards illegal. ;pcc007 2-Jan-85 vjc modules:cp4def,cp4cmd ; Cmifil is too fussy about what characters to accept in a ; filespec. My CP/M manual says any printable character is ok ; except <>.,;:?*[], and lower case. In practice, even those work ; sometimes. Kermit itself uses '&' if file warning is on, ; and then won't let you reference the file. Allow all ; printable characters except those above. Add conditional ; ffussy, so that if not ffussy, all special characters will be ; allowed, just convert lower to upper-case. ; edit 3: July 8, 1984 (CJC) ; integrate Toad Hall changes for LASM compatibility: CP4CPM is linked ; by CP4WLD, and links CP4UTL. ; ; edit 2: June 5, 1984 (CJC) ; formatting and documentation; delete unnecessary code at cminb7; add ; module version string. ; ; edit 1: May, 1984 (CJC) ; extracted from CPMBASE.M80 version 3.9; modifications are described in ; the accompanying .UPD file. cmdver: db 'CPSCMD.ASM (13) 17-Jan-1991$' ; name, edit number, date ; This routine prints the prompt in DE and specifies the reparse ; address. ; called by: kermit prompt: pop h ;Get the return address. push h ;Put it on the stack again. shld cmrprs ;Save it as the address to go to on reparse. lxi h,0 ;Clear out hl pair. dad sp ;Get the present stack pointer. shld cmostp ;Save for later restoral. xchg ;Save the pointer to the prompt. shld cmprmp xchg lxi h,cmdbuf shld cmcptr ;Initialize the command pointer. shld cmdptr xra a sta cmaflg ;Zero the flags. sta cmccnt ; mvi a,0FFH ;Try it this way (Daphne.) ; sta cmsflg call prcrlf ;Print a CR/LF [Toad Hall] jmp prprmp ;Print the prompt. [Toad Hall] ; ; This address is jumped to on reparse. ; here from: cmcfrm, cmkeyw, cmifil, cminbf repars: lhld cmostp ;Get the old stack pointer. sphl ;Make it the present one. lxi h,cmdbuf shld cmdptr ; mvi a,0FFH ;Try it this way (Daphne.) ; sta cmsflg lhld cmrprs ;Get the reparse address. pchl ;Go there. ; This address can be jumped to on a parsing error. ; here from: cmkeyw, cminbf prserr: lhld cmostp ;Get the old stack pointer. sphl ;Make it the present one. lxi h,cmdbuf shld cmcptr ;Initialize the command pointer. shld cmdptr xra a sta cmaflg ;Zero the flags. sta cmccnt ; mvi a,0FFH ;Try it this way (Daphne.) ; sta cmsflg call prcrlf ;Print a CR/LF [Toad Hall] call prprmp ;Print the prompt [Toad Hall] ;* Instead return to before the prompt call. lhld cmrprs pchl ; ; This routine parses the specified function in A. Any additional ; information is in DE and HL. ; Returns +1 on success ; +4 on failure (assumes a JMP follows the call) ; called by: log, setcom, read, send, xmit, dir, era, keycmd, cfmcmd ; and CPSREM comnd: sta cmstat ;Save what we are presently parsing. call cminbf ;Get chars until an action or a erase char. push psw ;[MF]Save function mvi a,0ffh ;[MF]Expect leading spaces sta cmsflg ;[MF]... pop psw ;[MF]Restore function cpi cmcfm ;Parse a confirm? jz cmcfrm ;Go get one. cpi cmkey ;Parse a keyword? jz cmkeyw ;Try and get one. cpi cmifi ;Parse an input file spec? jz cmifil ;Go get one. cpi cmifin ;Input file-spec silent? jz cmifil ;do as he wishes cpi cmofi ;Output file spec? jz cmofil ;Go get one. cpi cmtxt ;Parse arbitrary text? jz cmtext ;Go do it. cpi cmnum ;[7] Parse a number? jz cmnumb ;[7] go do it lxi d,cmer00 ;"?Unrecognized COMND call" call prtstr ret ; ; This routine parses arbitrary text up to a CR. ; Accepts DE: address to put text ; Returns in A: number of chars in text (may be 0) ; DE: updated pointer ; called by: comnd cmtext: xra a ; clear counters erc for slashes etc sta slshsn ; if we are in a slash sequence sta slashn ; the octal number being entered sta slashc ; number of characters entered xchg ;Put the pointer to the dest in HL. shld cmptab ;Save the pointer. mvi b,0 ;Init the char count cmtxt1: call cmgtch ;Get a char. ora a ;Terminator? jp cmtx3 ;No, put in user space. [rtr] was cmtx5 ani 7FH ;Turn off minus bit. cpi esc ;An escape? jnz cmtxt2 ;No. mvi c,conout mvi e,bell ;Get a bell. call bdos xra a sta cmaflg ;Turn off the action flag. lhld cmcptr ;Move the pointer to before the escape. dcx h shld cmcptr shld cmdptr lxi h,cmccnt ;Get the char count. dcr m ;Decrement it by one. jmp cmtxt1 ;Try again. cmtxt2: cpi '?' ;Is it a question mark? jz cmtxt4 ;If so put it in the text. [rtr] was cmtx3 cpi ff ;Is it a formfeed? cz clrtop ;If so blank the screen. mov a,b ;Return the count. lhld cmptab ;Return updated pointer in HL. xchg jmp rskp ;Return success. cmtx3: cpi '\' ; slash? jnz cmtx3a ; nope, so try something else lda slshsn ; a slash already entered? ana a cma ;[rtr] jnz cmtx3a ; yes, so assume its a valid slash to enter sta slshsn ; make sure the flag is set for next time routnd jmp cmtxt1 ; get another character cmtx3a: ; lxi h,cmaflg ;Point to the action flag. ; mvi m,0 ;Set it to zero. mov e,a ; save it in case we are interpreting a slash lda slshsn ; slash already entered? ana a ; test flag mov a,e ; restore it in case... jz cmtx5 ; not a slash seen, so enter as a normal character cpi '\' jnz cmtx3b ; \\ not detected lda slashn ; else get number jmp cmtx5b ; and enter it ( in the case of \n or \nn) ; here if an octal number of 1 or 2 digits ; entered instead of 3, followed by \ again cmtx3b: sui 30h ; else it should be an octal number jm cmtxt6 ; if not a digit complain cpi 8 ; ditto jp cmtxt6 ;[rtr] was cmtxt mov e,a ; else add it to the number already entered lda slashn add a add a add a ; multiply by 8 add e sta slashn lda slashc ; get the count inr a sta slashc ; plus one. If three then a number entered cpi 3 lda slashn ; get the number in case... jz cmtx5 jmp cmtxt1 ; else loop cmtxt4: lhld cmdptr ;[rtr] Get a pointer into the buffer inx h ;[rtr] Bump past '?' shld cmdptr ;[rtr] cmtx5: call cmtx5c jmp cmtxt1 ; put this into a subroutine cmtx5b: call cmtx5c ; here if we see \n\ or \nn\ rather than \nnn\ mvi a,'\' ; so send slash number to buffer, sta slshsn ; re-store a slash seen jmp cmtxt1 ; try next one cmtx5c: inr b ;Increment the count. lhld cmptab ;Get the pointer. mov m,a ;Put the char in the array. inx h shld cmptab ;Save the updated pointer. xra a ; clear slash counters etc sta slashc sta slashn sta slshsn ret ; and exit cmtxt6: lxi d,cmer05 ; complain - not a valid \ parameter call prtstr jmp kermit ; and try another command ds 20h ; for debugging ; ; This routine gets a number from user input. ; Called by: comnd ; cmnumb: lxi h,0 ; make sure the number is zero to start with shld number cmnum0: call cmgtch ; get another character ora a ; if negative then its an action jp cmnum1 ; nope, so (possibly) valid input ani 7fh ; else lets see what it is... cpi esc ; do not know what to do with this one... cpi ' ' ; if it is a space then either a return or more jnz cmnum2 ; else jmp rskp ; space is a deliminter dw 0 ; set three bytes aside for a jump/call dw 0 ; and then another three just in case... dw 0 ; making 6 bytes cmnum2: cpi '?' ; user is curious jz gnum2 cpi cr ; end of input? jz cmnumx gnum1: jmp prserr ; did not under stand this, so error cmnumx: dw 0 dw 0 jmp rskp ; return ok gnum2: lhld number ; get the number.. if at all entered mov a,l ora h ; if hl = 0 then possibly no number entered lxi d,cmin02 ; say confirm...or more on line jnz gnum21 ; else say enter a return lxi d,cmin01 ; say enter a number gnum21: call prtstr ; say it call prcrlf ; do a lf call prprmp ; another reprompt lhld cmdptr ; get pointer of string already entered mvi m,'$' ; dollar it to set end of line lhld cmcptr dcx h ; decrement and save the buffer pointer shld cmcptr lxi d,cmdbuf call prtstr ; print what has already been entered xra a sta cmaflg ; turn the action flag off jmp repars ; and try again mvi a,cmcfm ; parse a confirm dw 0 dw 0 dw 0 dw 0 dw 0 ; some space to patch... dw 0 cmnum1: ani 7fh ; here for a (potentially) valid number sui '0' ; less ascii bias jc gnum3 cpi 10 ; if 10 or more its still bad jnc gnum3 cmc lhld number ; now multiply number by ten and add the new value push h pop d dad h ; hl = hl * 2 dad h ; * 4 dad d ; * 5 dad h ; * 10 mvi d,0 mov e,a ; add de to hl... dad d shld number jmp cmnum0 ; gnum3: lxi d,cmer04 ; invalid number... call prtstr jmp rskp ; ; ; This routine gets a confirm. ; called by: comnd cmcfrm: call cmgtch ;Get a char. ora a ;Is it negative (a terminator;a space or ;a tab will not be returned here as they ;will be seen as leading white space.) rp ;If not, return failure. ani 7FH ;Turn off the minus bit. cpi esc ;Is it an escape? jnz cmcfr2 mvi c,conout mvi e,bell ;Get a bell. call bdos xra a sta cmaflg ;Turn off the action flag. lhld cmcptr ;Move the pointer to before the escape. dcx h shld cmcptr shld cmdptr lxi h,cmccnt ;Get the char count. dcr m ;Decrement it by one. jmp cmcfrm ;Try again. cmcfr2: cpi '?' ;Curious? jnz cmcfr3 lxi d,cmin00 ;Print something useful. call prtstr call prcrlf ;Print a crlf. [Toad Hall] call prprmp ;Reprint the prompt [Toad Hall] lhld cmdptr ;Get the pointer into the buffer. mvi a,'$' ;Put a $ there for printing. mov m,a lhld cmcptr dcx h ;Decrement and save the buffer pointer. shld cmcptr lxi d,cmdbuf call prtstr xra a ;Turn off the action flag. sta cmaflg jmp repars ;Reparse everything. cmcfr3: cpi ff ;Is it a form feed? cz clrtop ;If so blank the screen. jmp rskp ; ; This routine parses a keyword from the table pointed ; to in DE. 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. ; db a,b ;Where a & b are pieces of data ; ;to be returned. (Must be two of them.) ; ; The keywords must be in alphabetical order. ;**** Note: The data value a is returned in registers A and E. The ;**** data value b is returned in register D. This allows the two data ; bytes to be stored as: ; dw xxx ; and result in a correctly formatted 16-bit value in register pair ; DE. ; called by: comnd cmkeyw: shld cmhlp ;Save the help. xchg ;Get the address of the table. shld cmptab ;Save the beginning of keyword tab for '?'. mov b,m ;Get the number of entries in the table. inx h shld cmkptr lhld cmdptr ;Save the command pointer. shld cmsptr cmkey2: mov a,b ;Get the number of entries left. ora a ;Any left? rz ;If not we failed. mvi a,0ffh ;[MF]Make sure we ignore leading spaces sta cmsflg ;[MF]... lhld cmkptr mov e,m ;Get the length of the keyword. inx h cmkey3: dcr e ;Decrement the number of chars left. mov a,e cpi 0FFH ;Have we passed the end? jm cmkey5 ;If so go to the next. call cmgtch ;Get a char. ora a ;Is it a terminator? jp cmkey4 ;If positive, it is not. ani 7FH ;Turn off the minus bit. cpi '?' jnz cmky31 xra a sta cmaflg ;Turn off the action flag. lxi h,cmccnt ;Decrement the char count. dcr m ;* Must go through the keyword table and print them. lhld cmhlp ;For now print the help text. xchg call p20ln ;[8] print at most 20 lines then pause ; call prtstr call prcrlf ;Print a crlf [Toad Hall] call prprmp ;Reprint the prompt [Toad Hall] lhld cmdptr ;Get the pointer into the buffer. mvi a,'$' ;Put a $ there for printing. mov m,a lhld cmcptr dcx h ;Decrement and save the buffer pointer. shld cmcptr lxi d,cmdbuf call prtstr jmp repars ;Reparse everything. cmky31: cpi esc ;Is it an escape? jnz cmky35 xra a sta cmaflg ;Turn off the action flag. push d push b push h call cmambg jmp cmky32 ;Not ambiguous. mvi c,conout mvi e,bell call bdos ;Ring the bell. lhld cmcptr ;Move the pointer to before the escape. dcx h shld cmcptr shld cmdptr lxi h,cmccnt ;Get the char count. dcr m ;Decrement it by one. pop h pop b pop d inr e ;Increment the left to parse char count. jmp cmkey3 cmky32: lhld cmcptr ;Pointer into buffer. dcx h ;Backup to the escape. xchg pop h push h cmky33: mov a,m ;Get the next char. cpi '$' ;Finished? jz cmky34 inx h xchg mov m,a ;Move it into the buffer. inx h xchg lda cmccnt ;Increment the char count. inr a sta cmccnt jmp cmky33 cmky34: lda cmccnt ;Get the character count. inr a ;Increment and save it. sta cmccnt xchg ;Put the command buffer pointer in HL. mvi a,' ' ;Get a blank. mov m,a ;Put it in the command buffer. inx h ;Increment the pointer shld cmcptr ;Save the updated pointer. shld cmdptr pop h push h xchg call prtstr ;Print the rest of the keyword. mvi c,conout mvi e,' ' call bdos ;Print a blank. pop h pop b pop d jmp cmky37 cmky35: push h push d call cmambg jmp cmky36 lxi d,cmer01 call prtstr ;Say its ambiguous. jmp prserr ;Give up. cmky36: pop d pop h cmky37: inr e ;Add one incase it is negative. mvi d,0 dad d ;Increment past the keyword. inx h ;Past the $. mov e,m ;Get the data. inx h mov d,m mov a,e jmp rskp cmkey4: cpi 'a' ;Is it less than a? jm cmky41 ;If so don't capitalize it. cpi 'z'+1 ;Is it more than z? jp cmky41 ;If so don't capitalize it. ani 137O ;Capitalize it. cmky41: mov d,m ;Get the next char of the keyword. inx h cmp d ;Match? jz cmkey3 ;If so get the next letter. cmkey5: mvi d,0 mov a,e ;Get the number of chars left. ora a ;Is it negative? jp cmky51 mvi d,0FFH ;If so, sign extend. cmky51: dad d ;Increment past the keyword. lxi d,0003H ;Plus the $ and data. dad d shld cmkptr dcr b ;Decrement the number of entries left. lhld cmsptr ;Get the old cmdptr. shld cmdptr ;Restore it. ;* check so we don't pass it. jmp cmkey2 ;Go check the next keyword. ; ; Test keyword for ambiguity. ; returns: nonskip if ambiguous, skip if OK. ; called by: cmkeyw cmambg: dcr b ;Decrement the number of entries left. rm ;If none left then it is not ambiguous. inr e ;This is off by one;adjust. mov c,e ;Save the char count. mov a,e ora a ;Any chars left? rz ;No, it can't be ambiguous. mvi d,0 dad d ;Increment past the keyword. mvi e,3 ;Plus the $ and data. dad d mov b,m ;Get the length of the keyword. inx h xchg lhld cmkptr ;Get pointer to keyword entry. mov a,m ;Get the length of the keyword. sub c ;Subtract how many left. mov c,a ;Save the count. cmp b jz cmamb0 rp ;If larger than the new word then not amb. cmamb0: lhld cmsptr ;Get the pointer to what parsed. cmamb1: dcr c ;Decrement the count. jm rskp ;If we are done then it is ambiguous. xchg ;Exchange the pointers. mov b,m ;Get the next char of the keyword inx h xchg ;Exchange the pointers. mov a,m ;Get the next parsed char. inx h cpi 'a' ;Is it less than a? jm cmamb2 ;If so don't capitalize it. cpi 'z'+1 ;Is it more than z? jp cmamb2 ;If so don't capitalize it. ani 137O cmamb2: cmp b ;Are they equal? rnz ;If not then its not ambiguous. jmp cmamb1 ;Check the next char. ; ; cmofil - parse output filespec ; cmifil - parse input filespec ; here from: comnd cmofil: mvi a,0 ;Don't allow wildcards. ; jmp cmifil ;For now, the same as CMIFI. cmifil: sta cmfwld ;Set wildcard flag xchg ;Get the fcb address. shld cmfcb ;Save it. mvi e,0 ;Initialize char count. mvi m,0 ;Set the drive to default to current. inx h shld cmfcb2 xra a ;Initialize counter. cmifi0: mvi m,' ' ;Blank the FCB. inx h inr a ; cpi 0CH ;Twelve? [5a dont use this] cpi 0Bh ; [majoc 850585] Eleven? jm cmifi0 cmif0a: ;[MF]Zero entire fcb, not just the extent mvi m,0 ; [majoc 850507] Specify extent 0 inx h ;[MF]Increment fcb byte pointer inr a ;[MF]Increment fcb byte count cpi 32 ;[MF]Done with fcb? jm cmif0a ;[MF]No, zero until done cmifi1: call cmgtch ;Get another char. ora a ;Is it an action character? jp cmifi2 ani 7FH ;Turn off the action bit. cpi '?' ;A question mark? jnz cmif12 lda cmfwld ;[pcc006] Wildcards allowed? ora a ;[pcc006] jz cmif11 ;[pcc006] complain if not lhld cmdptr ;[jd] Increment buffer pointer inx h ;[jd] that was decremented in cmgtch shld cmdptr ;[jd] since we want this chr lda cmcptr ;[pcc006] get lsb of real input pointer cmp l ;[pcc006] is this the last chr input? jnz cmif1a ;[pcc006] no, don't reset action flag xra a ;[pcc006] yes, reset action flag sta cmaflg ;[pcc006] cmif1a: mvi a,'?' ;[pcc006] get it back in A jmp cmifi8 ;Treat like any other character cmif12: cpi esc ;An escape? jnz cmif13 ;Try to recognize file-spec a'la TOPS-20 xra a sta cmaflg ;Turn off the action flag. lhld cmcptr ;Move the pointer to before the escape. dcx h shld cmcptr shld cmdptr lxi h,cmccnt ;Get the char count. dcr m ;Decrement it by one. mov a,e ;Save character count up to now. sta temp1 cpi 9 ;Past '.'? jm cmfrec ;No. dcr a ;Yes, don't count point. cmfrec: lhld cmfcb2 ;Fill the rest with CP/M wildcards. cmfrc1: cpi 11 ;Done? jp cmfrc2 ;Yes. mvi m,'?' inx h inr a jmp cmfrc1 cmfrc2: mvi c,sfirst ;Find first matching file? lhld cmfcb xchg call bdos cpi 0FFH jz cmfrc9 ;No, lose. lxi h,fcbblk ;Copy first file spec. call fspcop lxi h,fcbblk+10H ;Get another copy (in case not ambiguous). call fspcop mvi c,snext ;More matching specs? lhld cmfcb xchg call bdos cpi 0FFH jz cmfrc3 ;Only one. lxi h,fcbblk+10H ;Copy second file spec. call fspcop cmfrc3: lxi d,fcbblk ;Start comparing file names. lxi h,fcbblk+10H lda temp1 ;Bypass characters typed. cpi 9 ;Past '.'? jm cmfrc4 ;No. dcr a ;Yes, don't count point. cmfrc4: mvi c,0 cmfrl1: cmp c ;Bypassed? jz cmfrl2 ;Yes. inx d inx h inr c jmp cmfrl1 ;Repeat. cmfrl2: mov a,c ;Get file name characters processed. cpi 11 ;All done? jz cmfrc5 ;Yes. cpi 8 ;End of file name? jnz cmfrl3 ;No. lda temp1 ;Exactly at point? cpi 9 jz cmfrl3 ;Yes, don't output a second point. mvi a,'.' ;Output separator. call cmfput cmfrl3: ldax d ;Get a character from first file spec. inx d mov b,m ;Get from second file spec. inx h cmp b ;Compare. jnz cmfrc5 ;Ambiguous. inr c ;Same, count. cpi ' ' ;Blank? jz cmfrl2 ;Yes, don't output. call cmfput ;Put character into buffer. jmp cmfrl2 ;Repeat. cmfrc5: mov a,c ;Get count of characters processed. sta temp1 ;Save it. mvi a,'$' ;Get terminator. call cmfput ;Put it into buffer. lhld cmdptr ;Output recognized characters. xchg mvi c,prstr call bdos lhld cmcptr ;Remove terminator from buffer. dcx h shld cmcptr lxi h,cmccnt dcr m lda temp1 ;Characters processed. cpi 11 ;Complete file name. jz repars ;Yes, don't beep. cmfrc9: mvi c,conout mvi e,bell call bdos ;Ring the bell. jmp repars ; ; Continue file spec parsing. cmif13: mov a,e ;It must be a terminator. ora a ;Test the length of the file name. jz cmifi9 ;If zero complain. cpi 0DH jp cmifi9 ;If too long complain. jmp rskp ;Otherwise we have succeeded. cmifi2: cpi '.' jnz cmifi3 inr e mov a,e cpi 1H ;Any chars yet? jz cmifi9 ;No, give error. cpi 0AH ;Tenth char? jp cmifi9 ;Past it, give an error. mvi c,9H mvi b,0 lhld cmfcb dad b ;Point to file type field. shld cmfcb2 mvi e,9H ;Say we've gotten nine. jmp cmifi1 ;Get the next char. cmifi3: cpi ':' jnz cmifi4 inr e mov a,e cpi 2H ;Is it in the right place for a drive? jnz cmifi9 ;If not, complain. lhld cmfcb2 dcx h ;Point to previous character. mov a,m ;Get the drive name. sui '@' ;Get the drive number. shld cmfcb2 ;Save pointer to beginning of name field. mvi m,space ;[obs] restore a space in FCB dcx h ;Point to drive number. mov m,a ;Put it in the fcb. mvi e,0 ;Start character count over. jmp cmifi1 cmifi4: cpi '*' jnz cmifi7 lda cmfwld ;Wildcards allowed? cpi 0 jz cmif11 ;No,complain mov a,e cpi 8H ;Is this in the name or type field? jz cmifi9 ;If its where the dot should be give up. jp cmifi5 ;Type. mvi b,8H ;Eight chars. jmp cmifi6 cmifi5: mvi b,0CH ;Three chars. cmifi6: lhld cmfcb2 ;Get a pointer into the FCB. mvi a,'?' mov m,a ;Put a question mark in. inx h shld cmfcb2 inr e mov a,e cmp b jm cmifi6 ;Go fill in another. jmp cmifi1 ;Get the next char. cmifi7: cpi '!' ;[pcc007] control chr or space? jm cmifi9 ;[pcc007] yes, illegal mov h,a ;[5] stash input char for a bit lda ffussy ;[5] while we check the fussy flag ora a ;[5] set the flags accordingly mov a,h ;[5] restore the input character jz cmif7a ;[5] if ffussy=0, allow <>.,;:?*[] ;[5] So far, we've eliminated "action characters" (including question), ;[5] period, colon, asterisk, control characters, and space. ;[5] That leaves us %(),/;<=>[\]_| to check for. cpi '%' ;[5] jz cmifi9 ;[5] cpi '(' ;[5] jz cmifi9 ;[5] cpi ')' ;[5] jz cmifi9 ;[5] cpi ',' ;[pcc007] weed out comma jz cmifi9 ;[pcc007] cpi '/' ;[5] jz cmifi9 ;[5] cpi '9'+1 ;[pcc007] anything else 21H-39H is ok jm cmifi8 ;[pcc007] except '*' never gets here cpi '@' ;[pcc007] all of 3AH-3FH is illegal jm cmifi9 ;[pcc007] cpi '[' ;[pcc007] [\] also illegal jm cmifi8 ;[pcc007] cpi ']'+1 ;[pcc007] jm cmifi9 ;[pcc007] cpi '_' ;[5] jz cmifi9 ;[5] (If I was doing CP/M, I would have cpi '|' ;[5] just eliminated all them funny chars jz cmifi9 ;[5] instead of a random selection) cmif7a: ;[5] cpi 'a' ;[pcc007] if not lower case its ok jm cmifi8 ;[pcc007] (DEL never gets here) cpi 'z'+1 ;[pcc007] only convert letters jp cmifi8 ;[pcc007] ani 137O ;Capitalize. cmifi8: lhld cmfcb2 ;Get the pointer into the FCB. mov m,a ;Put the char there. inx h shld cmfcb2 inr e jmp cmifi1 cmifi9: lda cmstat cpi cmifin ;"silent"? jz r ;Yes,let him go w/o check lxi d,cmer02 cmif10: mvi c,prstr call bdos ret cmif11: lxi d,cmer03 ;Complain about wildcards. jmp cmif10 ; ; copy filename from buffer ; called with HL = destination, A = position (0-3) in buffer ; called by: cmifil fspcop: push psw ;Save A. lxi d,buff ;Get the right offset in the buffer. rlc rlc rlc rlc rlc add e inr a ;Bypass drive spec. mov e,a mvi b,11 ;Copy file name. fspcp1: ldax d inx d mov m,a inx h dcr b jnz fspcp1 pop psw ;Restore A. ret ; append character in A to command buffer ; called by: cmifil cmfput: push h ;Save H. lhld cmcptr ;Get buffer pointer. mov m,a ;Store in buffer. inx h shld cmcptr lxi h,cmccnt ;Count it. inr m pop h ;Restore H. ret ; ; Read characters from the command buffer. ; called by: cmtext, cmcfrm, cmkeyw, cmifil cmgtch: push h push b cmgtc1: lda cmaflg ora a ;Is it set. cz cminbf ;If the action char flag is not set get more. lhld cmdptr ;Get a pointer into the buffer. mov a,m ;Get the next char. inx h shld cmdptr cpi ' ' ;Is it a space? jz cmgtc2 cpi tab ;Or a tab? jnz cmgtc3 cmgtc2: lda cmsflg ;Get the space flag. ora a ;Was the last char a space? jnz cmgtc1 ;Yes, get another char. mvi a,0FFH ;Set the space flag. sta cmsflg mvi a,' ' pop b pop h jmp cmgtc5 cmgtc3: push psw xra a sta cmsflg ;Zero the space flag. pop psw pop b pop h cpi esc jz cmgtc5 cpi '?' ;Is the user curious? jz cmgtc4 cpi cr jz cmgtc4 cpi lf jz cmgtc4 cpi ff rnz ;Not an action char, just return. cmgtc4: push h lhld cmdptr dcx h shld cmdptr pop h cmgtc5: ori 80H ;Make the char negative to indicate it is ret ;a terminator. ; ; Read characters from console into command buffer, processing ; editing characters (^H, ^M, ^J, ^L, ^U, ^X, ?, del). ; called by: comnd, cmgtch cminbf: push psw push d push h lda cmaflg ;Is the action char flag set? ora a jnz cminb9 ;If so get no more chars. cminb1: lxi h,cmccnt ;Increment the char count. inr m mvi c,conin ;Get a char. lda cmqflg ;[MF]but do we want it echoed? ora a ;[MF]... jz cmin1b ;[MF]Yup, proceed normally cmin1c: mvi e,0ffH ;[MF]Nope, do it with Direct mvi c,dconio ;[MF]Console I/O call bdos ;[MF]... ora a ;[MF]Did the user type anything? jz cmin1c ;[MF]No, don't go on until he/she does. jmp cmin1a ;[MF]We got a character cmin1b: call bdos cmin1a: lhld cmcptr ;Get the pointer into the buffer. mov m,a ;Put it in the buffer. inx h shld cmcptr cpi 25O ;Is it a ^U? jz cmnb12 ;Yes. cpi 30O ;Is it a ^X? jnz cminb2 cmnb12: call clrlin ;Clear the line. call prprmp ;Print the prompt [Toad Hall] lxi h,cmdbuf shld cmcptr ;Reset the point to the start. lxi h,cmccnt ;Zero the count. mvi m,0 jmp repars ;Go start over. cminb2: cpi 10O ;Backspace? jz cminb3 cpi del ;or Delete? jnz cminb4 lda cmqflg ;[MF]If we are echoing characters, ora a ;[MF]... cz delchr ;Print the delete string. [MF] cminb3: lda cmccnt ;Decrement the char count by two. dcr a dcr a ora a ;Have we gone too far? jp cmnb32 ;If not proceed. mvi c,conout ;Ring the bell. mvi e,bell call bdos jmp cmnb12 ;Go reprint prompt and reparse. cmnb32: sta cmccnt ;Save the new char count. lda cmqflg ;[MF]Echoing characters? ora a ;[MF]If we are, then cz clrspc ;Erase the character. [MF] lhld cmcptr ;Get the pointer into the buffer. dcx h ;Back up in the buffer. dcx h shld cmcptr jmp repars ;Go reparse everything. cminb4: cpi '?' ;Is it a question mark. jz cminb6 cpi esc ;Is it an escape? jz cminb6 cpi cr ;Is it a carriage return? jz cminb5 cpi lf ;Is it a line feed? jz cminb5 cpi ff ;Is it a formfeed? jnz cminb8 ;no - just store it and ;test if buffer overflowing, else get another character. call clrtop cminb5: lda cmbflg ;[MF]Allowing initial blank word ()? ora a ;[MF]... jnz cminb6 ;[MF]Yes lda cmccnt ;Have we parsed any chars yet? cpi 1 jz prserr ;If not, just start over. cminb6: mvi a,0FFH ;Set the action flag. sta cmaflg jmp cminb9 cminb8: lda cmccnt ; get the command character count cpi cmbufl ; check for comand buffer length jm cminb1 ; if less, then all ok mvi e,bell ; else beep at user call outcon ; send it to the console lda cmccnt ; back up one character dcr a sta cmccnt lhld cmcptr ; ditto pointer dcx h shld cmcptr ; save it again jmp cminb1 ; and try again cminb9: pop h pop d pop psw ret ; ;Little utility to print the prompt. (We do a LOT of these.) [Toad Hall] ;Enters with nothing. ;Destroys HL (and I suppose B and DE and A). prprmp: mvi e,cr ; do a cr first mvi c,dconio call bdos lhld cmprmp ;Get the prompt. xchg call prtstr ret ; Little code to allow some expansion of code without changing ; every futher address, only up to the end of this file. ; TO BE REMOVED FOR RELEASE! ; org ($+100h) AND 0FF00H IF lasm LINK CPSUTL ENDIF ;lasm [Toad Hall]