> SJCCP/SRC + SJ Research CCP as supplied with ZNOS 1 Source recreated and tweeked by J.G.Harston (: 2:start%=&D800 : Start address, ZNOS=&D800, Acorn=&D400 <$jsc%= : Original JSC version F#sj%= : Amended to 'SJCCP' P5znos%= : Allowed to use workspace within ZNOS Z+bbc%= : BBC entry points available d: n,start%=&D400:jsc%=:sj%=:znos%=:bbc%= x: CDRIVE=4:BDOS=5:OSBYTE=&FFF4:OS_CLI=&FFF7:BRKV=&FFFA:FAULT=&FF82 5ݤopt(A%):o%=(P%-z%)A%:P%=P%-o%:O%=O%-o%:=P*p%+4 : p%=3: mcode% &900 P=0 1 O%=mcode%:P%=start% [OPT P*p%+4 BJP ColdEntry :\ Execute any command in InputBuffer ?JP WarmEntry :\ Clear InputBuffer and start CCP .z% GJP ResetCCP :\ Standard CCP must have only two entries ;OPT opt(jsc%) :\ Remove if not original version 7.InputBuffer:B &7F :\ Input buffer maximum size :.InputLength:B &00 :\ Input buffer length, 0=empty .InputText :M 16," ") .z%:M "S":OPT opt(sj%) "&M "JCCP version 1.40":B 13:B 10 ,G.z%:M "Another quality product from JSC wundersystems":B 13:B 10 6OPT opt(jsc%) @ M "$" J!.z%:M "(C)SJ Research 1984." TOPT opt(sj% jsc%) ^: h6M start%+&C1+37*znos%-P%,0) :\ Tweekable space r: | .entry% 0LD C,0:JR ColdEntry :\ Enter here if * 5.CCPstack :\ Top of internal stack 7.LD8CD :B &04 :\ Number of columns for DIR A.LD8CE :B &01 :\ Drive to search if object not found ?.LD8CF :B &00 :\ Bad Filename flag in ReadFilename .escflg:B 1 .addr :W 0 .ccpdrv:B &00 : $\ ------------------------------ $\ Restart CCP with current drive $\ ------------------------------  .ResetCCP 6LD A,(DRIVE):LD C,A :\ Get current drive/user : !\ --------------------------- &\ C=drive to start with 0!\ No startup command executed :!\ --------------------------- D.WarmEntry N2SUB A:LD (InputLength),A :\ Clear input buffer X: b+\ ------------------------------------- l\ C=drive to start with v+\ Input buffer contains startup command +\ ------------------------------------- .ColdEntry BLD SP,CCPstack:PUSH DE :\ set up stack and save startup flag .z% ;LD HL,ErrorHandler:LD (BRKV),HL :\ set up error handler OPT opt(bbc%) 7LD HL,DRIVE:LD (HL),C :\ store user/drive number .LD C,&D: callBDOS :\ reset disk system 5\LD (BATCH),A :\ Set '$*.*' found flag 8SUB A:RLD:LD E,A:RRD :\ get user code from DRIVE * GetSetUser :\ Set user code >LD HL,(LF204):LD (addr),HL :\ save BIOS warm start address :LD HL,LD922:LD (LF204),HL :\ redirect BIOS warm start 7LD C,&F: SubmitBDOS :\ Try to open '$$$.SUB' file  >INC A:LD (BATCH),A :\ Set batch file active/inactive  .LD922  /LD SP,CCPstack :\ Reset CCP stack *ALD HL,(addr):LD (LF204),HL :\ restore BIOS warm start address 44PUSH AF: PrNewline :\ Print newline if needed >=POP AF:JR NZ,LD92B :\ No title if batch file active H- vers: cr_lf :\ Display CCP version R .LD92B \G add_CR:JP ExecInput :\ Execute any command and enter command loop f: p .commands zM "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 M "RUN" :NOP:W run M "RESET":NOP:W ResetCCP M "VERS" :NOP:W vers NOP : .\ ---------------------------------------- $.\ VERS - Print CCP and ZNOS version string ..\ ---------------------------------------- 8 .title B*.z%:M "S" :OPT opt(sj%) L2M "JCCP version 1.40" :OPT opt(sj% jsc%) V M "$" `: j .vers t2LD DE,title: PrMessage :\ Print out CCP title ~4LD C,&4A: BDOS :\ Get ZNOS version string ,LD A,H: L:RET Z :\ HL=0, no ZNOS HEX DE,HL:JP PrMessage :\ Print out ZNOS version string and return : \ ------------- \ Error handler \ ------------- .ErrorHandler .z% :LD SP,CCPstack: cr_lf:\ Reset stack and print newline :LD HL,(FAULT) :\ Get address of error block  .err_lp ?INC HL:LD A,(HL) :\ Get character from error string - A: NZ,PrChar :\ Print if not zero  7JR NZ,err_lp: cr_lf :\ Loop until zero terminator OPT opt(bbc%) : ( .LD9D3 2.z% <zero, print it OPT opt() .z% . PrDec :\ Print user number OPT opt() 4LD C,&4A: BDOS :\ Get ZNOS version string :LD A,L: H:LD A,">" :\ If no version string, use '>' =JR Z,prompt:LD A,"]" :\ Version string present, use ']'  .prompt ? PrChar :\ If ZNOS, print A], if not print A> 4 LDA5D: cr_lf :\ Read a line to InputBuffer : .ExecInput 9SUB A:LD (InputLength),A :\ Flag InputBuffer as empty - ResetDMA :\ Set DMA to &0080 7 ExecLine:JR MainLoop:\ Execute line and loop back &: 0-\ --------------------------------------- :-\ Delete $$$.SUB and read a line of input D-\ --------------------------------------- N .LDA5A X6 LDAA9 :\ Delete any '$$$.SUB' file b: l5\ ----------------------------------------------- v5\ Read a line of input from console or batch file 5\ -----------------------------------------------  .LDA5D =LD A,(BATCH) :\ Is there a batch file active? D A:JR NZ,LDA78 :\ Jump to read a record from batch file LD DE,InputBuffer >LD C,&A: BDOS :\ Read a line of input from console :  .add_CR 4LD HL,InputLength :\ Point to line length 5LD E,(HL):LD D,0 :\ Get input line length :ADD HL,DE:INC HL :\ Point to end of input line 5LD (HL),13:RET :\ Put CR at end of text : -\ ---------------------------------------  -\ Read a record from '$$$.SUB' batch file -\ ---------------------------------------  .LDA78 *>LD DE,InputLength :\ Set DMA address to InputBuffer 4, SetDMA:LD A,(LF243) :\ Get RecordCount >JDEC A:JP M,LDA5A :\ No more, delete $$$.SUB, read from console H9PUSH AF:LD (LF254),A :\ Set record number to read R(LD C,&14: SubmitBDOS :\ Read record \H add_CR:LD HL,InputText :\ Add CR and point HL to start of text f .LDA98 p;LD A,(HL):CP 13: NZ,PrChar :\ Display text to console z/INC HL:JR NZ,LDA98 :\ Loop until 8 LDE19:POP AF :\ Check for keypress to abort ELD (LF243),A:RET NZ :\ Set RecordCount, return if not at end :  .LDAA9 9LD A,(BATCH): A:RET Z :\ No batch file, just return PUSH DE:LD C,&13 - SubmitBDOS :\ Delete '$$$.SUB' :SUB A:LD (BATCH),A :\ Set 'no batch file active' POP DE:RET : )\ ----------------------------------- )\ Execute command line in InputBuffer )\ -----------------------------------  .ExecLine  = ,) &SUB A :\ at end .not_end ?CP (HL):JR NZ,no_match :\ Doesn't match, try next command 8INC HL: A:JR NZ,comm_lp2 :\ Check another character 5LD A,(HL):INC HL:LD H,(HL) :\ Get command address 6LD L,A:LD A,C:JP (HL) :\ Enter with A=character ( .no_match 27LD A,(HL): A:INC HL :\ Find end of command text <4JR NZ,no_match :\ Loop until zero byte FHINC HL:INC HL:JR comm_lp :\ Step past address and check next command P: Z"\ ---------------------------- d"\ Try to run command from disk n"\ ---------------------------- x .comm_end 3 read_filename :\ Parse filename to FCB1 :PUSH DE:LD DE,&65 :\ Point to extension in FCB1 ;LD HL,com_txt:LD BC,3:LDIR :\ Force extension to '.COM' ?POP DE:LD A,(&5D) :\ Get first character of filename 6CP " ":JP NZ,run_comm :\ If command there, run it : /\ ----------------------------------------- /\ No filename, see if drive specifier given /\ ----------------------------------------- 8LD A,(&5C):DEC A:RET M :\ No drive given, exit *LD E,A:LD C,&E: callBDOS :\ Set drive 7LD HL,DRIVE:LD A,(HL) :\ Get user from DRIVE < &F0: E:LD (HL),A:RET :\ Merge with drive and return :  .com_txt 9M "COM" :\ Extension for command files ": ,2.PrMessage :\ Print string at DE 6 PrString:JR cr_lf @: J7.PrNewline :\ Print newline if needed T.z% ^4LD A,&86: OSBYTE :\ Get cursor X,Y position h3LD A,L: A:RET Z :\ Return if not needed rOPT opt(bbc%) |-.cr_lf :\ Print newline LD A,13: PrChar LD A,10:JR PrChar 2.PrDec :\ Print A in decimal LD B,&FF .PrDecLp INC B:SUB 10:JR NC,PrDecLp LD C,A:LD A,B  A: NZ,pr_digit LD A,C:ADD A,10 .pr_digit ADD A,"0" .PrChar PUSH AF:PUSH BC:PUSH DE LD E,A:LD C,2: callBDOS POP DE:POP BC:POP AF:RET : & .LDB64 0 LD HL,&5C : .LDB67 DPUSH HL: read_filename2 NLD C,A:POP HL:INC HL XLD A,(HL):CP " " b*LD A,C:RET NZ:\ Ok if filename present l .LDB73 v$ abort:M "Syntax error":M "$" .read_filename LD HL,&5C .read_filename2 PUSH HL:POP IX:\ copy to IX LD (IX+0),0:LD (IX+&20),0 LD B,11 .LDB93 LD (IX+1)," " INC IX:DJNZ LDB93 LD B,4 .LDB9D !LD (IX+1),0:INC IX:DJNZ LDB9D PUSH DE: get_upper JR C,LDBD5 LD C,A: get_char -CP ":":JR NZ,LDBBA:\ not drive specifier LD A,&3F: C:LD (HL),A *$INC SP:INC SP:\ lose old pointer 4 PUSH DE > .LDBBA HPOP DE:INC HL:PUSH HL R LD B,9 \ .LDBBF f get_upper:JR C,LDBD5 pJR NZ,LDBC8 zPOP HL:RET:\ end .LDBC8 CP ".":JR Z,LDBD8 .CP "*": Z,LDC07:\ if '*', fill with '?'s LD (HL),A INC HL:DJNZ LDBBF .LDBD5 &POP HL:JR LDBEE:\ Illegal filename .LDBD8 POP HL *LD BC,8:ADD HL,BC:\ point to extension LD B,4 .LDBDF  get_upper JR C,LDBEE:\ illegal RET Z:\ end CP "*": Z,LDC07:\ '*' $LD (HL),A:INC HL .DJNZ LDBDF 8 .LDBEE B1LD A,(LD8CF): A:RET NZ:\ no error if flagged L .LDBF3 V( abort:M "Illegal filename":M "$" ` .LDC07 jLD A,"?":DEC B tJR Z,LDC12 ~ .LDC0C LD (HL),A:INC HL DJNZ LDC0C DEC HL:INC B  .LDC12  INC B:RET :  .get_char LD A,(DE):CP 13:RET Z  &5F:CP "A" JR C,LDC22 CP "[":JR C,LDC23  .LDC22  LD A,(DE)  .LDC23 INC DE:RET : (.get_upper 2 get_char <CP 13:RET Z FCP ",":RET Z PCP "=":RET Z ZCP " ":RET NZ dPUSH AF: SkipSpace nPOP AF:RET x.SkipSpace LD A,(DE):CP " "  RET NZ INC DE:JR SkipSpace :  .callBDOS PUSH DE:PUSH HL: BDOS POP HL:POP DE:RET : %\ ------------------------------- %\ DIR - List objects in catalogue %\ ------------------------------- .dir 3 read_filename :\ Parse filename to FCB1 9SUB A:LD (LDD06),A :\ Set 'drive not specified' =LD HL,&5D:LD A,(HL) :\ Get first character from FCB1 0, use specified drive r .LDC80 |7LD (LDD06),A :\ Set drive to &00 or '?' 1LD A,(ccpdrv) :\ Get current drive  .LDC86 5ADD A,"@":LD (LDD05),A:\ Convert to drive letter -LD C,&11: LDC50 :\ Search for first 8INC A:RET Z:LD C,1 :\ If nothing found, return :  .LDC96 ;PUSH BC: LDE19 :\ Check for keypress interuption EDEC A :\ A=index into current directory record 0RRCA:RRCA:SCF:RRA :\ A=&0080+index*32 ALD L,A:LD H,0 :\ HL points to this directory entry GBIT 7,(HL):JR NZ,LDCF1 :\ If UserNum.b7=1, no entry, skip to next 5LD A,(LDD06) :\ Check drive specified > A:JR NZ,LDCB5 :\ If '?', skip check for ș files -.Pr2Space: PrSpace :\ Print two spaces H .PrSpace RPUSH AF:LD A,32 \( PrChar:POP AF:RET :\ Print space f: p,.LDD05:DEC HL :\ Drive letter z<.LDD06:B &CD :\ Drive 0=current, <>0=specified :  \ -------------------------- \ - Save memory to disk  \ --------------------------  .LDD07 & abort:M "Catalogue full":M "$" :  .save  ReadDec:PUSH BC  LDB64: ReadHex  PUSH HL LD C,&13: LDC41 "LD C,&16: LDC50:\ create file INC A:JR Z,LDD07:\ Cat full POP DE:\ start POP HL:\ length $SUB A:LD H,A .!CP L:JR Z,LDD60:\ zero length 8'ADD HL,HL:\ =num of 128-byte blocks BLD A,(&5C) L/CP &10:JR Z,LDD65:\ direct ENDIFs available V .LDD40 ` PUSH HL j(LD (addr),DE: SetDMA:\ Set DMA addr t&LD C,&15: LDC50:\ write 128 bytes ~ A:JR NZ,LDD75:\ Disk full LD HL,(addr)  LD DE,128 ADD HL,DE:EX DE,HL POP HL:DEC HL LD A,H: L:JR NZ,LDD40  .LDD60 "LD C,&10:JP LDC50:\ close file  .LDD65 #PUSH HL: SetDMA:\ Set DMA addr  POP IX LD C,&59: LDC50:\ save  A:JR Z,LDD60:\ ok  .LDD75  ! abort:M "Disc full":M "$" : 1\ ------------------------------------------- (1\ Perform action if filename has no wildcards 21\ ------------------------------------------- < .LDC41 F?PUSH BC:LD HL,&5C :\ Save call number, point to FCB1 P5LD BC,12:LD A,"?" :\ Search 12 bytes for '?' ZDCPIR:POP BC:JP Z,LDBF3 :\ If found, jump to 'Illegal filename' d .LDC50 nCLD DE,&5C:JR JumpBDOS :\ Point to FCB1, call BDOS and return x: <.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 >.PrString :LD C,9:JR JumpBDOS :\ Print string at DE : \ ----------------------- \ USER - Select user area \ -----------------------  .user / ReadDec:LD A,C :\ Read decimal value -CP &20:JR NC,BadNumber :\ If >31, error  or @CP 10:JR NZ,type_last :\ Not or , type character  .type_cr ** cr_lf:JR type_last :\ Print newline H.type_char R,LD A,C: PrChar :\ Print character \.type_last f4LD A,C:LD (addr),A :\ Set last chararacter p.type_skip z/ LDE22 :\ Check for keypress 6PUSH AF: NZ,LDD60 :\ Close file if key pressed 4POP AF:JP NZ,LD9E5 :\ Abort if key pressed EINC HL:DJNZ type_lp :\ Point to next character and loop back :JR LDDE8 :\ Loop for another 128 bytes :  .LDE19 /PUSH AF: LDE22 :\ Check for keypress :JP NZ,LD9E5:POP AF:RET :\ Close batch file and abort  .LDE22 .PUSH BC:PUSH DE:PUSH HL :\ Save registers /LD C,&B: BDOS :\ Get Console Status 4 A:JR Z,LDE37 :\ Nothing pending, exit .LD C,1: BDOS :\ Get Console Input 1SUB A:DEC A :\ A=&FF for aborted  .LDE37 1POP HL:POP DE:POP BC :\ Restore registers $RET .: 8\ ----------------- B\ ERA - Erase files L\ ----------------- V .era_txt `&M "Erase all files (Y/N)?":M "$" j.era t LDB64:LD A,"?" ~LD B,11:LD HL,&5C  .LDE60 INC HL:CP (HL) JR NZ,LDE79:DJNZ LDE60 LD DE,era_txt  PrString  LDA5D: get_char  &DF:CP "Y":JP NZ,LD9E8  cr_lf  .LDE79 LD C,&13: LDC50 INC A:JP Z,LDFCF RET :  \ ----------------- \ REN - Rename file \ ----------------- (.ren 21LD HL,&6C: LDB67 :\ Parse first filename <2PUSH AF: LDB64:POP AF:\ Parse second filename F1CP "=":JR Z,ren2 :\ REN newname=oldname P>CP " ":JP NZ,LDB73 :\ Error if not REN oldname newname Z7LD HL,&5C:LD DE,&6C:LD B,16 :\ Prepare to swap FCBs d .ren1 n2LD A,(DE):LD C,(HL) :\ Get bytes from FCB x3LD (HL),A:LD A,C:LD (DE),A :\ Swap them around 5INC HL:INC DE:DJNZ ren1 :\ Loop for all 16 bytes  .ren2 4LD C,&11:LD DE,&6C: BDOS:\ See if newname exits ?INC A:JR Z,LDEB3 :\ newname doesn't exist, go ahead + abort:M "File already exists":M "$"  .LDEB3 *LD C,&17: LDC41 :\ Do the rename 9INC A:JP Z,LDFCF:RET :\ Error if source not found :  .NFtxt M " not found":M "$" : \ ----------------------- \ - Run arbitary file \ ----------------------- .run "2 read_filename :\ Read filename to FCB1 ,?LD A,(&5D) :\ Get first character of filename 6@CP " ":JR Z,old :\ No filename, enter current program @: J,\ -------------------------------------- T,\ Run a command file from command prompt ^,\ -------------------------------------- h .run_comm rPUSH DE:LD HL,&100 |6 LDF3D:POP DE :\ Load file in FCB1 to &100 : 5\ ----------------------------------------------- 3\ - Enter current program with new parameters 5\ ----------------------------------------------- .old 1PUSH DE: LDF16 :\ Close any batch file - ResetDMA:POP DE :\ Set DMA to &0080  .LDEEA BPUSH DE :\ Save address of command parameters @LD A,&FF:LD (LD8CF),A :\ Prevent errors fron ReadFilename 8 read_filename :\ Read first filename to FCB1 -LD HL,&6C :\ Point to FCB2 9 read_filename2 :\ Read second filename to FCB2 APOP DE :\ Get address of command parameters 9LD HL,&80:PUSH HL :\ Point to parameter buffer =LD B,&FF:LD A,(DE) :\ Get character from input text &@CP 13:JR Z,LDF06:DEC DE :\ Step back to prepare for GetChar 0 .LDF06 :< get_char :\ Get a character from input line DGINC HL:LD (HL),A:INC B :\ Store in parameter buffer and inc count N/SUB &0D:JR NZ,LDF06 :\ Loop until X?LD (HL),A:POP HL :\ Store at end of parameters bJLD (HL),B:JP &100 :\ Store parameter length and execute program l: v .LDF16 ;LD A,(BATCH): A:RET Z :\ No batch file active, return .PUSH DE:PUSH HL :\ Save registers .LD HL,LF242:RES 7,(HL) :\ Reset b7 of S2 'LD C,&10: SubmitBDOS :\ Close file .LDF3D:\ load a file HPUSH HL:EX DE,HL R) SetDMA :\ Set DMA addr \LD HL,&62:SET 7,(HL) f .LDF49 p0LD C,&5A: LDC50 :\ Attempt direct load z< A:JR Z,LDF59 :\ Not supported, do manual load 8INC A: Z,LDFB8 :\ Not found, try search drive 6JR Z,LDF49 :\ Jump back to try again POP HL:RET :  .LDF59 .LD C,&F: LDC50 :\ Open file in FCB1 =INC A: Z,LDFB8 :\ If not found, try changing drive EJR Z,LDF49:POP DE :\ Another drive found, jump back to try  .LDF65 ELD (addr),DE: SetDMA :\ Save current address and set DMA address =LD C,&14: LDC50 :\ Read a record to current address A A:JR NZ,LDF80 :\ Jump to finish when at End Of File 3LD HL,(addr) :\ Get current address ?LD DE,&80:ADD HL,DE :\ Update to next 128-byte address 9EX DE,HL:JR LDF65 :\ Loop back for next record  .LDF80 $5JP LDD60 :\ Close file and return .: 8 .ReadHex BLD HL,&100:\ default value L LD A,(DE) VCP 13: NZ,LDF94 `CP 13:RET Z j JP LDB73 t .LDF94 ~ LD HL,0  .LDF97  get_upper:RET Z  SUB "0"  .LDF9D JP C,BadNumber CP 10:JR C,LDFAB  SUB 7 CP &10:JP NC,BadNumber  .LDFAB  PUSH BC  LD B,4  .LDFAE ADD HL,HL:JR C,LDF9D  DJNZ LDFAE POP BC: L:LD L,A  JR LDF97 (: 2 .LDFB8 <3LD HL,&5C:LD A,(HL) :\ Get drive from FCB1 FN A:JR NZ,LDFCF :\ If drive specified, print 'not found' and abort P6LD A,(ccpdrv):LD B,A :\ Get current drive to B Z-LD A,(LD8CE) :\ Get something dC A:JR Z,LDFCF :\ If zero, print 'not found' and abort nOCP B:JR Z,LDFCF :\ If same as current drive, 'not found' and about xCLD (HL),A:CP A:RET :\ Store in FCB1 and return with Z set :  .LDFCF 0 cr_lf: LDFDE :\ Print filename in FCB1 1LD DE,NFtxt: PrMessage :\ Print 'not found' 6JP MainLoop :\ Return to command loop : \ ---------------------- \ Print filename in FCB1 \ ----------------------  .LDFDE LD B,8:LD HL,&5D: LDFF0 LD A,".": PrChar LD B,3:LD HL,&65  .LDFF0 LD A,(HL): &7F CP &20:RET Z " PrChar ,INC HL:DJNZ LDFF0 6RET @: J.z% T?.BATCH :B &00 :\ Batch file active flag ^;.SUBFCB:B &01:M "$$$ SUB" :\ 'A $$$.SUB' filename h+\ F240 :B &00 :\ EX r+\ F241 :B &00 :\ S1 |+\ 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 opt(znos%) : ] BIOS_WARM=&EA03 &znos%:BIOS_WARM=&F203:BATCH=&F233 : $LF204=BIOS_WARM+1:SUBFCB=BATCH+1 3LF242=SUBFCB+14:LF243=SUBFCB+15:LF254=SUBFCB+32  :f$="SJCCP/SYS" ="**SAVE ";f$;" ";~mcode%;" ";~O%;" ";~entry%;" ";~start%