> SJCCP140/src + SJ Research CCP as supplied with ZNOS 1 Source recreated and tweeked by J.G.Harston (: 72 1984 v1.39 John Spencer Cox at SJ Research << 04-Aug-1992 v1.40 JGH: Added command search user/drive DF TYPE deals with any EOL, REN old new allowed P: 9ZA%=0:X%=1:os%=24:?&FFF4=&C3:os%=((&FFF4)&FF00)256 OPT endif :\ Remove if not original version D.InputBuffer:B CCPstack-InputText :\ Input buffer maximum size G.InputLength:B &00 :\ Input buffer length, 0=empty .InputText :M 16," ") +M "SJCCP version ":M ver$:B 13:B 10 OPT if(jsc%) Q::M "Another quality product from JSC wundersystems":B 13:B 10:B 13:B 10 OPT endif M "$" M "(C)SJ Research 1984." : 2M start%+&C1-ver$-P%,0) :\ Tweekable space : 6.CCPstack :\ Top of internal stack K.LD8CD :B &04 :\ Number of columns for DIR, 4 fits in 80 cols G.SEARCH:B &01 :\ User/Drive to search if object not found @&.LD8CF :B &00 :\ Bad Filename flag in ReadFilename -0.ESCFLG:B &01 :\ Escape enabled 0:.ADDR :W &00 :\ Address workspace 9D.CCPDRV:B &00 :\ CCP's current search drive N: 2X\ -------------------------------------------- $b\ Restart CCP with current drive 0l\ If entered via *, will have InputLength=0 ;v\ If entered via RESET command, will have InputLength=0 1\ So can optimise by falling through CCPClear 2\ -------------------------------------------- 3.ResetCCP:.entry% :\ Enter here if *RUN 7LD A,(DRIVE):LD C,A :\ Get current user+drive 6: :\ Fall through to start : +\ ------------------------------------- \ C=user+drive to start with &\ ZNOS BIOS Warm enters with C=&00 &\ Acorn BIOS never enters via here &\ DRDOS BIOS never enters via here !\ No startup command executed +\ ------------------------------------- .CCPClear 3 SUB A:LD (InputLength),A :\ Clear input buffer : + \ ------------------------------------- *\ C=user+drive to start with &4\ ZNOS BIOS Cold enters with C=&00 @>\ Acorn BIOS Cold+Warm enters with C=user+drive from (DRIVE) +H\ Input buffer contains startup command +R\ ------------------------------------- \.CCPStart CfLD SP,CCPstack :\ Set up stack and save startup flag pOPT if(bbc%) z::LD HL,ErrorHandler 5::LD (BRKV),HL :\ Set up error handler OPT endif : 6LD HL,DRIVE:LD (HL),C :\ Save entry user/drive ELD C,&0D: callBDOS :\ Reset disk system and log into drive A: OPT if(optimise%) E:: SelectDriveUser :\ Select specified drive and user in (HL) OPT else .::LD A,(HL): 15:LD E,A :\ Get entry drive /::LD C,&0E: callBDOS :\ Select this drive .::SUB A:RLD:LD E,A:RRD :\ Get user to E .::LD C,&20: BDOS :\ Select this user OPT endif =LD HL,(LF204):LD (ADDR),HL:\ Save BIOS warm start address 9LD HL,LD922:LD (LF204),HL :\ Redirect BIOS warm start 8LD C,&0F: SubmitBDOS :\ Try to open '$$$.SUB' file ?$INC A:LD (BATCH),A :\ Set batch file active/inactive .: "8\ Redirected WARM returns here B.LD922 0LLD SP,CCPstack :\ Reset CCP stack @VLD HL,(ADDR):LD (LF204),HL:\ Restore BIOS warm start address S`LD A,(BATCH): A :\ Fetch again in case we lost it via WARM redirection >jJR NZ,LD92B :\ No title if batch file active Jt CRLF :\ Annoying, but BDOS ERROR and ^C leaves POS>0 ~OPT if(banner%) .:: vers: CRLF :\ Display CCP version OPT endif .LD92B H AddCR:JP ExecInput :\ Execute any command and enter command loop : .commands M "DIR" :NOP:W dir M "TYPE" :NOP:W type M "ERA" :NOP:W era M "REN" :NOP:W ren M "SAVE" :NOP:W save M "USER" :NOP:W user M "LOAD" :NOP:W load  M "GO" :NOP:W go M "VDU" :NOP:W vdu M "PRINT":NOP:W print (M "OLD" :NOP:W old 2M "RUN" :NOP:W run <M "RESET":NOP:W ResetCCP FM "VERS" :NOP:W vers PNOP Z: .d\ ---------------------------------------- .n\ VERS - Print CCP and ZNOS version string .x\ ---------------------------------------- .title M "SJCCP version ":M ver$ M "$" : .vers 1LD DE,title: PrMessage:\ Print out CCP title 5LD C,&4A: BDOS :\ Get ZNOS version string -LD A,H: L:RET Z :\ HL=0, no ZNOS IEX DE,HL:JP PrMessage :\ Print out ZNOS version string and return : \ ------------- \ Error handler \ ------------- .ErrorHandler OPT if(bbc%) ;::LD SP,CCPstack: CRLF:\ Reset stack and print newline ;"::LD HL,(FAULT) :\ Get address of error block ,::.err_lp @6::INC HL:LD A,(HL) :\ Get character from error string .@:: A: NZ,PrChar :\ Print if not zero 8J::JR NZ,err_lp: CRLF :\ Loop until zero terminator TOPT endif ^: h.LD9D3 rOPT if(bbc%) =|::LD A,&7E: OSBYTE :\ Acknowledge any pending Escapes ::LD HL,(ESCFLG):LD H,0 3::LD A,&E5: OSBYTE :\ Restore Escape action 7::JR MainLoop :\ Return to command loop OPT endif : .LD9E5  CRLF .LD9E8 7 LDAA9 :\ Delete any '$$$.SUB' file # abort:M "* Aborted *":M "$" : %\ Print in-line message and abort %\ ------------------------------- .abort CPOP DE: CRLF :\ Get address of message, print newline 7 PrMessage :\ Print message and newline &: 0\ ------------------------ :\ Main command prompt loop D\ ------------------------ N.MainLoop /XLD SP,CCPstack :\ Set up stack DRIVE, E=USER 7::LD (CCPDRV),A :\ Set CCP drive number 2::ADD A,&40: PrChar :\ Print drive letter 1::LD A,E: PrDec :\ Print user number OPT else =:: ResetUser :\ Reset user, returns HL=>DRIVE 2::LD A,(HL): 15:LD E,A :\ Get current drive 1::LD C,&0E: callBDOS :\ Select this drive 7 ::LD A,E:INC A:LD (CCPDRV),A:\ Set CCP drive number 2::ADD A,&40: PrChar :\ Print drive letter / ::LD E,&FF: GetSetUser :\ Get user number 1*:: PrDec :\ Print user number 4OPT endif >: 5HLD C,&4A: BDOS :\ Get ZNOS version string :RLD A,H: L:LD A,">" :\ If ZNOS not present, use '>' 4\JR Z,prompt:LD A,"]" :\ ZNOS present, use ']' f.prompt @p PrChar :\ If ZNOS, print A], if not print A> 5z LDA5D: CRLF :\ Read a line to InputBuffer : .ExecInput :SUB A:LD (InputLength),A :\ Flag InputBuffer as empty . ResetDMA :\ Set DMA to &0080 8 ExecLine:JR MainLoop :\ Execute line and loop back : -\ --------------------------------------- -\ Delete $$$.SUB and read a line of input -\ --------------------------------------- .LDA5A 5 LDAA9 :\ Delete any '$$$.SUB' file : 5\ ----------------------------------------------- 5 \ Read a line of input from console or batch file 5 \ ----------------------------------------------- " \ Returns DE=>no longer needed $ .LDA5D =. LD DE,InputBuffer :\ Prepare to read to InputBuffer <8 LD A,(BATCH) :\ Is there a batch file active? CB A:JR NZ,LDA78 :\ Jump to read a record from batch file =L LD C,&0A: BDOS :\ Read a line of input from console V : %` \ Returns DE=>start of input line %j \ ------------------------------- t .AddCR 3~ LD HL,InputLength :\ Point to line length 4 LD E,(HL):LD D,0 :\ Get input line length 6 INC HL:EX DE,HL :\ DE=>start of input line 4 ADD HL,DE :\ HL=>end of input line 4 LD (HL),13:RET :\ Put CR at end of text  : - \ Read a record from '$$$.SUB' batch file - \ --------------------------------------- .LDA78 5 INC DE :\ Point to InputLength E SetDMA :\ Set DMA address to InputBuffer contents 0 LD A,(SUBFCB+15) :\ Get RecordCount K DEC A:JP M,LDA5A :\ No more, delete $$$.SUB, read from console : PUSH AF:LD (SUBFCB+32),A :\ Set record number to read ) LD C,&14: SubmitBDOS :\ Read record B AddCR :\ Add CR and point DE to start of text  .LDA98 :( LD A,(DE) :\ Get character from buffer 32 CP 13: NZ,PrChar :\ If not , print it 0< INC DE:JR NZ,LDA98 :\ Loop until 9F LDE19 :\ Check for keypress to abort >P POP AF:LD (SUBFCB+15),A :\ Set RecordCount for next call 5Z RET NZ :\ Return if not at end d : n \ Delete any batch file x \ --------------------- .LDAA9 : LD A,(BATCH): A:RET Z :\ No batch file, just return . LD C,&13: SubmitBDOS :\ Delete '$$$.SUB' ; SUB A:LD (BATCH),A :\ Set 'no batch file active'  RET  : ) \ ----------------------------------- ) \ Execute command line in InputBuffer ) \ ----------------------------------- .ExecLine C LD DE,InputText :\ Point to start of entered line 4 SkipSpace:LD (ADDR),DE :\ Save start of text 0 CP ";":RET Z :\ Comment, exit 5 CP 13:RET Z :\ Empty line, exit  OPT if(bbc%) < ::CP "*":JR NZ,NotOscli :\ Jump past if not *command >" ::LD HL,0:LD A,&E5: OSBYTE:\ Escape key sets Escape state -, ::EX DE,HL: OS_CLI :\ Do *command P6 ::JP LD9D3 :\ Restore Escape, and go back to command loop @ OPT endif J : T \ -------------------------- ^ \ Check for built-in command h \ -------------------------- r .NotOscli 7| LD HL,commands :\ Point to command table .comm_lp I LD DE,(ADDR):LD A,(HL) :\ Get pointer to text, get byte from table H A:JR Z,comm_end :\ If at end of table, try to run from disk .comm_lp2 F GetCharNxt :\ Get upper case character from input line C LD C,A:JR NZ,not_end :\ C=char, Z if end marker ( = ,) ' SUB A :\ at end .not_end @ CP (HL):JR NZ,no_match :\ Doesn't match, try next command 7 INC HL: A:JR NZ,comm_lp2:\ Check another character 4 LD A,(HL):INC HL:LD H,(HL):\ Get command address 7 LD L,A:LD A,C:JP (HL) :\ Enter with A=character .no_match 8 LD A,(HL): A:INC HL :\ Find end of command text 5 JR NZ,no_match :\ Loop until zero byte I INC HL:INC HL:JR comm_lp :\ Step past address and check next command & : "0 \ ---------------------------- ": \ Try to run command from disk "D \ ---------------------------- N .comm_end 4X read_filename :\ Parse filename to FCB1 ;b PUSH DE:LD DE,&65 :\ Point to extension in FCB1 :l LD HL,com_txt:LD BC,3:LDIR:\ Force extension to '.COM' @v POP DE:LD A,(&5D) :\ Get first character of filename 7 CP " ":JP NZ,run_comm :\ If command there, run it  : / \ ----------------------------------------- / \ No filename, see if drive specifier given / \ ----------------------------------------- 8 LD A,(&5C):DEC A:RET M :\ No drive given, exit  .ResetDrive * LD E,A:LD C,&E: callBDOS :\ Set drive 7 LD HL,DRIVE:LD A,(HL) :\ Get user from DRIVE < &F0: E:LD (HL),A:RET :\ Merge with drive and return  :  OPT if(optimise%)  ::.SelectDriveUser  ::RET :\\\ DO \\\  OPT endif  : .com_txt :* M "COM" :\ Extension for command files 4 : > \ Print message H \ ------------- R .PrMessage \ PrString f : p \ Print newline z \ ------------- .CRLF  LD A,13: PrChar  LD A,10:JR PrChar  :  \ Print A in decimal  \ ------------------ .PrDec LD B,&FF .PrDecLp  INC B:SUB 10:JR NC,PrDecLp  LD C,A:LD A,B  A: NZ,PrDigit  LD A,C:ADD A,10 .PrDigit ADD A,"0" : *$\ Print character in A, preserving all *.\ ------------------------------------ ?8\ Error reporting and SUBMIT echoing expects Z/NZ preserved B.PrChar #LPUSH AF:PUSH BC:PUSH DE:PUSH HL VLD E,A:LD C,&02: BDOS #`POP HL:POP DE:POP BC:POP AF:RET j: "t\ Parse and check for filename "~\ ---------------------------- .LDB64 )LD HL,&5C :\ HL=>FCB1 .LDB67 PUSH HL: read_filename2 ;LD C,A:POP HL:INC HL :\ HL=>first character of FCB 3LD A,(HL):CP " " :\ Check if no filename 7LD A,C:RET NZ :\ Ok if filename present .LDB73 $ abort:M "Syntax error":M "$" : "\ Parse filename at DE to FCB1 "\ ---------------------------- .read_filename ) LD HL,&5C :\ HL=>FCB1 : \ Parse filename at DE to HL (\ -------------------------- 2\ On entry, DE=>text to scan <\ HL=>FCB to fill )F\ On exit, DE=>terminating character )P\ A = terminating character "Z\ Z = valid filename d\ NZ= bad filename 4n\ Filename terminated with ',' or '=' x.read_filename2 (PUSH HL:POP IX :\ IX=>FCB 1LD (IX+0),0:LD (IX+&20),0 :\ Drive=0, default LD B,11 .LDB93 9LD (IX+1)," " :\ Set filename+ext to spaces INC IX:DJNZ LDB93 LD B,4 .LDB9D 8LD (IX+1),0 :\ Set rest of FCB to zero INC IX:DJNZ LDB9D 2PUSH DE :\ Save line pointer 8 GetCharNxt:JR C,LDBD5:\ Error if control character ?LD C,A: GetUpChar :\ Save in C in case drive character 2CP ":":JR NZ,LDBBA :\ Not drive specifier DLD A,&3F: C:LD (HL),A :\ Convert to drive num or '?' and store 8INC SP:INC SP :\ Drop saved line pointer >"PUSH DE :\ Replace with new line pointer ,.LDBBA ;6POP DE:INC HL:PUSH HL :\ DE=>line, HL=>FCB filename F@LD B,9 :\ Scan 9 characters (should this be 8?) J.LDBBF 8T GetCharNxt:JR C,LDBD5:\ Error if control character 3^JR NZ,LDBC8 :\ Skip if not at end >hPOP HL:RET :\ Drop saved pointer and return r.LDBC8 8|CP ".":JR Z,LDBD8 :\ Jump if '.' for extension 7CP "*": Z,LDC07 :\ If '*', fill rest with '?'s 0LD (HL),A :\ Store character -INC HL:DJNZ LDBBF :\ Step to next .LDBD5 BPOP HL:JR LDBEE :\ Too many characters, bad filename .LDBD8 ,POP HL :\ Get HL=>FCB 3LD BC,8:ADD HL,BC :\ Point to extension FLD B,4 :\ Scan 4 characters (should this be 3?) .LDBDF 8 GetCharNxt:JR C,LDBEE:\ Error if illegal character .RET Z :\ End character 7CP "*": Z,LDC07 :\ If '*', fill rest with '?'s 0LD (HL),A :\ Store character -INC HL:DJNZ LDBDF :\ Step to next .LDBEE ?&LD A,(LD8CF): A:RET NZ :\ If flag set, allow bad filename 0.LDBF3 (: abort:M "Illegal filename":M "$" D: N.LDC07 ,XLD A,"?" :\ Fill with '?' ?bDEC B:JR Z,LDC12 :\ Only one to do, exit to caller l.LDC0C ;vLD (HL),A:INC HL :\ Fill rest of FCB with '?'s DJNZ LDC0C 8DEC HL:INC B :\ Point to last character .LDC12 3INC B:RET :\ Returns B=1 or B=2 : $\ Get character and step to next $\ ------------------------------ %\ On entry, DE=>current character '\ On exit, A =upper case character .\ DE=>next character if not .GetUpChar LD A,(DE):CP 13:RET Z  &5F:CP "A" JR C,LDC22 6 CP "[":JR C,LDC23 :\ 'a'-'z' becomes 'A'-'Z' .LDC22 LD A,(DE) *.LDC23 4INC DE:RET >: $H\ Get next character and test it $R\ ------------------------------ %\\ On entry, DE=>current character 'f\ On exit, A =upper case character .p\ DE=>next character if not )z\ Z = terminator , = spc cr %\ C = control character .GetCharNxt 6 GetUpChar :\ Get upper case character @CP 13:RET Z :\ Exit with terminating character CP ",":RET Z CP "=":RET Z 7CP " ":RET NZ :\ Exit with non-terminator .PUSH AF: SkipSpace :\ Step past spaces >POP AF:RET :\ And return with Z= found : .SkipSpace LD A,(DE) CP " ":RET NZ INC DE:JR SkipSpace : %\ ------------------------------- %$\ DIR - List objects in catalogue %.\ ------------------------------- 8.dir 4B read_filename :\ Parse filename to FCB1 :LSUB A:LD (LDD06),A :\ Set 'drive not specified' >VLD HL,&5D:LD A,(HL) :\ Get first character from FCB1 =`CP " ":JR NZ,LDC76 :\ Jump as contains file to match jLD B,11 t.LDC71 =~LD (HL),"?" :\ Set filename to '????????.???' INC HL:DJNZ LDC71 .LDC76 ;LD A,(&5C) :\ Get drive number from FCB1 >CP "?":JR Z,LDC80 :\ If drive '?', use current drive @ A:JR NZ,LDC86 :\ If drive<>0, use specified drive .LDC80 8LD (LDD06),A :\ Set drive to &00 or '?' 2LD A,(CCPDRV) :\ Get current drive .LDC86 6ADD A,"@":LD (LDD05),A :\ Convert to drive letter 6LD C,&11: LDC50 :\ Search for first to FCB1 9INC A:RET Z :\ If nothing found, return 9LD C,1:PUSH BC :\ Start at "column zero"+1  : .LDC96 < LDE19 :\ Check for keypress interuption F(DEC A :\ A=index into current directory record 12RRCA:RRCA:SCF:RRA :\ A=&0080+index*32 B<LD L,A:LD H,0 :\ HL points to this directory entry RFBIT 7,(HL):JR NZ,LDCF1 :\ If UserNum.b7=1, no entry or hidden, skip to next 9PLD A,(LDD06) :\ Check if drive specified BZ A:JR NZ,LDCB5 :\ If '?', skip check for "SYS" files =dPUSH HL:POP IX :\ IX points to directory entry InBIT 7,(IX+10):JR NZ,LDCF1 :\ If "SYS" file, don't print, skip to next x.LDCB5 8POP BC:DEC C :\ Decrement column number GLD A,&20:JR NZ,LDCC5 :\ Jump to print space if between columns 1LD A,(LDD05) :\ Get drive letter 6LD BC,(LD8CD) :\ Get number of columns .LDCC5 3PUSH BC :\ Save column number 9 PrChar :\ Print drive letter or space ALD A,":": PrChar :\ Print drive colon or column seperator 6LD A,(LDD06) :\ Check drive specified > A:JR Z,LDCDD :\ If not '?', ignore user number ELD A,(HL):CP 10 :\ Get user number from directory entry I C,PrSpace: PrDec :\ Print space padded user number, corrupts A,B,C .LDCDD < PrSpace:LD B,11 :\ Prepare to print 11 characters .LDCE2 <INC HL:LD A,(HL) :\ Get character from filename =" &7F: PrChar :\ Mask out bit7 and print character :,LD A,B:CP 4: Z,PrSpace:\ Print space before extension 76DJNZ LDCE2 :\ Loop for 11 characters =@POP BC:PUSH BC :\ Get column number back again 5JDEC C: Z,CRLF :\ Print newline if needed T: =^.LDCF1 :\ Step to next directory entry GhLD C,&12: BDOS :\ Search for next to FCB use by SearchFirst 9rINC A:JR NZ,LDC96 :\ Loop back if entry found <|POP BC:DEC C:JP NZ,CRLF :\ Final CRLF if middle column RET : .PrSpace PUSH AF:LD A,32 ) PrChar:POP AF:RET :\ Print space : +.LDD05:B &2B :\ Drive letter =.LDD06:B &CD :\ Drive 0=current, <>0=specified : \ -------------------------- \ SAVE - Save memory to disk \ -------------------------- .LDD07 & abort:M "Catalogue full":M "$" : .save <& ScanDec:PUSH BC :\ Scan number of 256-byte blocks 40 LDB64 :\ Parse filename to FCB1 A: ScanHex:PUSH HL :\ Scan start address, default to &100 6DLD C,&13: LDC41 :\ Delete any existing file )NLD C,&16: LDC50 :\ Create file )XINC A:JR Z,LDD07 :\ Cat full 4bPOP DE:POP HL :\ DE=start, HL=length 0lSUB A:LD H,A :\ Ensure HL=&00nn >vCP L:JR Z,LDD60 :\ Zero length, close and finish :ADD HL,HL :\ HL=num of 128-byte blocks OPT if(znos%) A::LD A,(&5C) :\ Check returned drive from Create D::CP &10:JR Z,LDD65 :\ If &10, direct ZNOS saves available OPT endif : .LDD40 6PUSH HL :\ Save number of blocks FLD (ADDR),DE: SetDMA :\ Save current address and set DMA address >LD C,&15: LDC50 :\ Write 128 bytes from current DMA ) A:JR NZ,LDD75 :\ Disk full @LD HL,(ADDR):LD DE,128 :\ Update to next 128-byte address ADD HL,DE:EX DE,HL CPOP HL:DEC HL :\ Decrement number of blocks to save 9 LD A,H: L:JR NZ,LDD40 :\ Loop back if more to save : .LDD60 6*LD C,&10:JP LDC50 :\ Close file and return 4: >OPT if(znos%) H::.LDD65 ?R::PUSH HL :\ Save number of 128-byte blocks 6\:: SetDMA :\ Set DMA address to start 3f::POP IX :\ Get save size back Ap::LD C,&59: LDC50 :\ Save whole file, DMA=start, IX=size Az:: A:JR Z,LDD60 :\ Save ok, jump to close and return OPT endif : .LDD75 ! abort:M "Disc full":M "$" : 1\ ------------------------------------------- 1\ Perform action if filename has no wildcards 1\ ------------------------------------------- .LDC41 @PUSH BC:LD HL,&5C :\ Save call number, point to FCB1 6LD BC,12:LD A,"?" :\ Search 12 bytes for '?' ECPIR:POP BC:JP Z,LDBF3 :\ If found, jump to 'Illegal filename' .LDC50 DLD DE,&5C:JR JumpBDOS :\ Point to FCB1, call BDOS and return : <.ResetDMA :LD DE,&80 :\ Set DMA to &0080 9$.SetDMA :LD C,&1A:JR JumpBDOS :\ Set DMA to DE H..SubmitBDOS:LD DE,SUBFCB:JR JumpBDOS :\ Call BDOS pointing to SUBFCB >8.PrString :LD C,9 :\ Print string at DE @B.JumpBDOS :JP BDOS :\ Call BDOS and return L: V\ ------------------ `\ Reset current User j\ ------------------ t.ResetUser <~LD HL,DRIVE :\ Point to current User/Drive .SetUser ?XOR A:JR SetUser1 :\ Cy=0, use supplied User number : \ ----------------------- \ USER - Select user area \ ----------------------- .user 0 ScanDec:LD A,C :\ Read decimal value .CP &10:JR NC,BadNumber :\ If >15, error 5LD HL,DRIVE :\ Cy=1, use drive in C .SetUser1 9RLD:JR NC,SetUser2:LD A,C :\ Merge user number from C .SetUser2 6 LD E,A:RRD :\ Pass user number to E 0.GetSetUser:LD C,&20 :\ Set user number E: :\ Fall through to call BDOS and return (: %2\ Call BDOS, preserving registers %<\ ------------------------------- F.callBDOS PPUSH DE:PUSH HL: BDOS ZPOP HL:POP DE:RET d: (n\ ---------------------------------- $x\ - Send characters to printer (\ ---------------------------------- .print +LD L,5:JR vdu2 :\ LST output : &\ -------------------------------- $\ - Send characters to console &\ -------------------------------- .vdu 2LD L,6 :\ Direct CON output .vdu2 0 ScanDec:PUSH DE :\ Read decimal value LD E,C:LD C,L 0 callBDOS :\ Send to LST or CON 6POP DE:LD A,(DE) :\ Get line pointer back 7CP 13:JR NZ,vdu2 :\ Loop until end of line RET ": ",\ Scan an 8-bit decimal number "6\ ---------------------------- #@\ On entry, DE=>first character J\ On exit, A = number -T\ DE=>first non-digit character ^.ScanDec .hSUB A :\ Accumulator=0 r.ScanDecLp .|LD C,A :\ C=accumulator 0 GetCharNxt:RET Z :\ Exit if terminator /CP ":":JR NC,BadNumber :\ Non-digit, error /SUB "0":JR C,BadNumber :\ Non-digit, error .LD B,10 :\ Multipy by 10 .ScanDecAdd 3ADD A,C:JR C,BadNumber :\ Add 10*accumulator DJNZ ScanDecAdd 9JR ScanDecLp :\ Loop back for next digit .BadNumber " abort:M "Bad number":M "$" : !\ --------------------------- !\ TYPE - Type file to console !\ --------------------------- .type 4 LDB64 :\ Parse filename to FCB1 3&LD HL,&62:SET 7,(HL) :\ Set a flag in FCB1 '0LD C,&F: LDC50 :\ Open file /:INC A:JP Z,LDFCF :\ File not found 1DXOR A:LD (ADDR),A :\ Clear CR/LF flag N.LDDE8 ,XLD C,&14: LDC50 :\ Read 128 bytes =b A:JP NZ,LDD60 :\ End of file, close and return ElLD B,128:LD HL,&80 :\ Prepare to type 128 bytes from &0080 v.type_lp 0LD A,(HL):LD C,A :\ Get a character 4\CP 32:\JR NC,type_char :\ Printable character @CP &1A:JP Z,LDD60 :\ If EOF character, jump to close 6CP 13:JR Z,type_cr :\ Check if or ACP 10:JR NZ,type_char :\ Not or , type character .type_cr =LD A,(ADDR) :\ Check last character printed >XOR 7:CP C:JR Z,type_skip :\ Different EOL character, skip + CRLF:JR type_last :\ Print newline .type_char -LD A,C: PrChar :\ Print character .type_last 5LD A,C:LD (ADDR),A :\ Set last chararacter .type_skip 0  LDE22 :\ Check for keypress 7PUSH AF: NZ,LDD60 :\ Close file if key pressed 5 POP AF:JP NZ,LD9E5 :\ Abort if key pressed F*INC HL:DJNZ type_lp :\ Point to next character and loop back ;4JR LDDE8 :\ Loop for another 128 bytes >: H.LDE19 0RPUSH AF: LDE22 :\ Check for keypress ;\JP NZ,LD9E5:POP AF:RET :\ Close batch file and abort f.LDE22 /pPUSH BC:PUSH DE:PUSH HL :\ Save registers 0zLD C,&0B: BDOS :\ Get Console Status 5 A:JR Z,LDE37 :\ Nothing pending, exit /LD C,&01: BDOS :\ Get Console Input 2SUB A:DEC A :\ A=&FF for aborted .LDE37 2POP HL:POP DE:POP BC :\ Restore registers RET : \ ----------------- \ ERA - Erase files \ ----------------- .era_txt 'M "Erase all files? (Y/N) ":M "$" .era 4 LDB64 :\ Parse filename to FCB1 ,LD A,"?":LD B,11 :\ Check for *.* LD HL,&5C $.LDE60 7.INC HL:CP (HL) :\ Check character in FCB <8JR NZ,LDE79 :\ Not '?', continue to delete =BDJNZ LDE60 :\ Loop to check all characters LLD DE,era_txt 3V PrString :\ Print confirm message :` LDA5D :\ Read line of text from input jLD DE,InputText At GetUpChar :\ Get first character from input line -~CP "Y":JP NZ,LD9E8 :\ Not 'Y', abort  CRLF : .LDE79 /LD C,&13: LDC50 :\ Erase the file(s) /INC A:JP Z,LDFCF :\ File not found RET : \ ----------------- \ REN - Rename file \ ----------------- .ren 2LD HL,&6C: LDB67 :\ Parse first filename 3PUSH AF: LDB64:POP AF :\ Parse second filename 2 CP "=":JR Z,ren2 :\ REN newname=oldname ?CP " ":JP NZ,LDB73 :\ Error if not REN oldname newname 7LD HL,&5C:LD DE,&6C:LD B,16 :\ Prepare to swap FCBs (.ren1 32LD A,(DE):LD C,(HL) :\ Get bytes from FCB 1<LD (HL),A:LD A,C:LD (DE),A:\ Swap them around 6FINC HL:INC DE:DJNZ ren1 :\ Loop for all 16 bytes P.ren2 4ZLD C,&11:LD DE,&6C: BDOS:\ See if newname exits @dINC A:JR Z,LDEB3 :\ newname doesn't exist, go ahead +n abort:M "File already exists":M "$" x.LDEB3 +LD C,&17: LDC41 :\ Do the rename :INC A:JP Z,LDFCF:RET :\ Error if source not found : .txtNF M " not found":M "$" : \ ----------------------- \ - Run arbitary file \ ----------------------- .run 3 read_filename :\ Read filename to FCB1 @LD A,(&5D) :\ Get first character of filename ACP " ":JR Z,old :\ No filename, enter current program : ,\ -------------------------------------- ,\ Run a command file from command prompt ,"\ -------------------------------------- ,.run_comm 6PUSH DE:LD HL,&100 7@ LDF3D:POP DE :\ Load file in FCB1 to &100 J: 5T\ ----------------------------------------------- 5^\ OLD - Enter current program with new parameters 5h\ ----------------------------------------------- r.old 2|PUSH DE: LDF16 :\ Close any batch file . ResetDMA:POP DE :\ Set DMA to &0080 .LDEEA CPUSH DE :\ Save address of command parameters ALD A,&FF:LD (LD8CF),A :\ Prevent errors from ReadFilename 9 read_filename :\ Read first filename to FCB1 .LD HL,&6C :\ Point to FCB2 : read_filename2 :\ Read second filename to FCB2 BPOP DE :\ Get address of command parameters :LD HL,&80:PUSH HL :\ Point to parameter buffer DLD B,&FF:LD A,(DE) :\ Get first character from input text ICP 13:JR Z,LDF06:DEC DE :\ Step back to copy space before parameter .LDF06 -\ Note, DRCCP doesn't force to upper case 0 \ We do the same so, eg ECHO CamelCase works @ LD A,(DE):INC DE :\ Get a character from input line  \ GetUpChar H& INC HL:LD (HL),A:INC B :\ Store in parameter buffer and inc count 00 SUB &0D:JR NZ,LDF06 :\ Loop until @: LD (HL),A:POP HL :\ Store <00> at end of parameters KD LD (HL),B:JP &100 :\ Store parameter length and execute program N : X \ Close any batch file b \ -------------------- l .LDF16 !\ Load a file H!\ ----------- R!\ On entry, FCB1=filename "\!\ HL =start address f!.LDF3D p!PUSH HL:EX DE,HL -z! SetDMA :\ Set DMA address >!LD HL,&62:SET 7,(HL) :\ Set F6 flag to open Read-Only !.LDF49 !OPT if(znos%) 6!::LD C,&5A: LDC50 :\ Attempt ZNOS direct load =!:: A:JR Z,LDF59 :\ Not supported, do manual load 9!::INC A: Z,LDFB8 :\ Not found, try search drive 7!::JR Z,LDF49 :\ Jump back to try again 6!::POP HL:JR LDF83 :\ Reset User and return !OPT endif !: !.LDF59 /!LD C,&0F: LDC50 :\ Open file in FCB1 >!INC A: Z,LDFB8 :\ If not found, try changing drive F"JR Z,LDF59:POP DE :\ Another drive found, jump back to try ".LDF65 F"LD (ADDR),DE: SetDMA :\ Save current address and set DMA address >$"LD C,&14: LDC50 :\ Read a record to current address B." A:JR NZ,LDF80 :\ Jump to finish when at End Of File 48"LD HL,(ADDR) :\ Get current address @B"LD DE,&80:ADD HL,DE :\ Update to next 128-byte address :L"EX DE,HL:JR LDF65 :\ Loop back for next record V".LDF80 (`" LDD60 :\ Close file j".LDF83 6t"JP ResetUser :\ Reset User and return ~": ".ReadHex 1"\ Scan an 16-bit hex address, default to &100 1"\ ------------------------------------------- #"\ On entry, DE=>first character "\ On exit, A = number -"\ DE=>first non-digit character ".ScanHex ."LD HL,&100 :\ Default value 6"LD A,(DE) :\ Get current character 7"CP 13: NZ,LDF94 :\ Not , scan hex number 4"CP 13:RET Z :\ Nothing after, exit 8"JP LDB73 :\ Abort with Syntax error #: #\ Scan an 16-bit hex address #\ -------------------------- #.LDF94 .(#LD HL,0 :\ Accumulator=0 2#.LDF97 0<# GetCharNxt:RET Z :\ Exit if terminator 0F#SUB "0" :\ Reduce to 0+digit P#.LDF9D ,Z#JP C,BadNumber :\ <'0', error 'F', error #.LDFAB =#PUSH BC:LD B,4 :\ Prepare to move up four bits #.LDFAE <#ADD HL,HL:JR C,LDF9D :\ Multiply by two, four times #DJNZ LDFAE 8#POP BC: L:LD L,A :\ Add digit to accumulator 4#JR LDF97 :\ Loop for next digit #: #\ Try changing search drive #\ ------------------------- #.LDFB8 4#LD HL,&5C:LD A,(HL) :\ Get drive from FCB1 O# A:JR NZ,FileNotFound :\ If drive specified, print 'not found' and abort 6$LD A,(CCPDRV):LD B,A :\ Get CCP current drive 1$LD A,(SEARCH) :\ Get search drive F$ A:JR Z,FileNotFound :\ No search drive, 'not found' and abort M"$CP B:JR Z,FileNotFound :\ Same as current drive, 'not found' and abort 4,$LD (HL),A :\ Store drive in FCB1 26$LD HL,SEARCH: SetUser :\ Set user from SEARCH 2@$CP A:RET :\ Return with Z set J$: T$.FileNotFound ^$.LDFCF 1h$ CRLF: LDFDE :\ Print filename in FCB1 /r$LD DE,txtNF: PrMessage:\ Print 'not found' 7|$JP MainLoop :\ Return to command loop $: $\ Print filename in FCB1 $\ ---------------------- $.LDFDE ?$LD B,8 :\ Print up to first 8 characters $LD HL,&5D: LDFF0 6$LD A,".": PrChar :\ Print dot before extension C$LD B,3:LD HL,&65 :\ Print up to remaining 3 characters $: $\ Print B characters $\ ------------------ $.LDFF0 ?$LD A,(HL): &7F :\ Get character and mask out bit 7 :%CP &20:RET Z :\ Unprintable, return early 1% PrChar :\ Print the character :%INC HL:DJNZ LDFF0 :\ Loop to do all characters &%RET 0%: :%OPT if( znos%) 7D%.BATCH :B &00 :\ Batch file active flag BN%.SUBFCB:B &00 :\ Current drive to match SUBMIT.COM 3X%\ F241 :M "$$$ SUB" :\ "$$$.SUB" filename #b%\ F240 :B &00 :\ EX #l%\ F241 :B &00 :\ S1 #v%\ F242 :B &00 :\ S2 #%\ F243 :B &00 :\ RC '%W 0:W 0:W 0:W 0 :\ Alloc Vector %W 0:W 0:W 0:W 0 #%\ F254 :B &00 :\ CR $%\ F255 :W &0000:B &00 :\ R0-R2 %OPT endif %: %.end% %OPT if(P%31: 4&A%=CCPstack-InputText +>&"Input buffer size/stack space:";8;A% -H& A%<127:"WARNING: Too small for SUBMIT" ,R&"Stack space during SUBMIT:";12;A%-128 \&A%=end%-start% -f& A%<&801:"Spare code space:"21;&800-A% 8p& A%>&800:"WARNING: Code too long by: ";11;A%-&800 z&: E&A$="SAVE "+fn$+" "+~mcode%+"+800 "+~entry%+" "+~start%,os%<8) &A$;: A$: & &os%<8:*Quit