title PAPER utility name ('PAPER') ; The AMSTRAD PAPER utility for PCW machines ; Disassembled by W.Cirsovius ; Call: PAPER {option {option..}} BDOS equ 0005h CCPcmd equ 0080h _Conout equ 2 _Lstout equ 5 _String equ 9 lf equ 0ah cr equ 0dh eot equ '$' esc equ 1bh eof equ 'Z'-'@' eos equ -1 ; End of table marker _EO equ 5 _EX equ 4 _NM equ 3 _HX equ 2 _AN equ 1 _IG equ 0 _Def equ 2 _Gap equ 3 _Lines equ 4 _Pitch equ 5 _Defeat equ 6 _Sheet equ 7 Ln.Gap equ 1 SHL _Lines + 1 SHL _Gap MSB equ 7 LoMask equ 00001111b jr PAPER db 'PAPER #115',cr,lf db 'Developed by Locomotive Software Ltd.',cr,lf db 'Copyright (C) 1985 ' db 'Amstrad Consumer Electronics PLC',cr,lf ; ; %%%%%%%%%%%%%%%%%%% ; %%% START PAPER %%% ; %%%%%%%%%%%%%%%%%%% ; PAPER: ld (UsrStk),sp ; Save callers stack ld sp,LocStk ; Get local stack call PrepCCPline ; Prepare command line call c,ProcPAPER ; Process set up ld sp,(UsrStk) ; Get back stack ret ; ; Process command line ; ProcPAPER: xor a ld (Defeat),a ; .. clear defeat ld (OptSel),a ; Clear any option call ExexOptions ; Execute command line jr z,CmdErr ld a,(OptSel) ; Get option and Ln.Gap ; Map line and gap set cp Ln.Gap ; Test either jp nz,SetPrinter ; .. init printer if so ld hl,(LinLen) ; Get length of line ld a,(RealLen) ; Test length set inc a jr nz,PP.noFix ; .. ON ld b,h ; .. copy length PP.FixIt: add a,l ; Fix length djnz PP.FixIt ld l,a PP.noFix: ld a,(Gap) ; Get gap cp l ; Compare against line length jp c,SetPrinter ; .. go init if OK ld de,$GAP.LT.LEN ; .. else tell error CmdErr: call ProcErr ; Process error ld de,$NO.CHNG jp String ; Tell nothing changed ; $NO.CHNG: db 'No change has been made to the printer ' db 'settings.',cr,lf,eot $GAP.LT.LEN: db 'Gap Length must be less than Form Length.' db cr,lf,eot ; ; Execute command options ; EXIT Zero set on error ; ExexOptions: call ChrGet ; Get character call FixNL ; Test end of line ret nz ; .. yeap ld hl,$CMD.TAB call Decode ; .. decode command call JPr jr nz,ExexOptions ; Loop till error ret ; ; Main command table ; $CMD.TAB: db 'A' dw SetA4.5 db 'C' dw SetContinous db 'D' dw SetDefaults db 'F' dw SetForm db 'G' dw SetGap db 'L' dw SetLine db 'P' dw SetPaper db 'S' dw SetSingle db eos dw SetNumber ; ; Execute via register ; ENTRY Reg HL points to address ; JPr: jp (hl) ; ; Option : A4 or A5 ; SetA4.5: call ChkRange ; Check range 4 or 5 db 4,5+1 dw $BAD.A4..5 ld de,$BAD.A4..5 ret z ; .. error cp 4 ; .. test A4 ld a,70 ; .. select lines jr z,..A4 ld a,50 ..A4: or a call StLines ; Store lines ld a,3 call StGap ; Set gap of three jr SetSheet ; Set sheet ; $BAD.A4..5: db 'Badly formed "A4" or "A5" parameter.' db cr,lf,eot ; ; Option : SINGLE SHEET ; SetSingle: call GetSxxx ; Skip SHEET SetSheet: ld a,-1 ; Set single sheet jr StSheet ; ; Option : CONTINOUS STATIONARY ; SetContinous: call GetSxxx ; Skip STATIONARY StConSheet: xor a ; Set continous sheet StSheet: ld hl,Sheet ld (hl),a ; Set flag inc hl set _Sheet,(hl) ; .. set sheet bit set _Defeat,(hl) ; .. set defeat off inc hl inc (hl) dec (hl) ret nz inc hl ld (hl),a or 1 ret ; ; Option : DEFAULTS ; SetDefaults: ld hl,OptSel set _Def,(hl) ; Indicate bit or (hl) ; .. set success ret ; ; Option : FORM LENGTH ; SetForm: call GetLxxx ; Skip LENGTH call ChkRange ; Check range 6..99 db 6,99+1 dw $ILL.FORM ret z ; .. error or a jr StLines ; Store lines ; $ILL.FORM: db 'Form Length must be between 6 and 99 lines.' db cr,lf,eot ; ; Option : GAP LENGTH ; SetGap: call GetLxxx ; Skip LENGTH call ChkRange ; Check range 0..99 db 0,99+1 dw $ILL.GAP ret z ; .. error jr StGap ; .. set gap ; $ILL.GAP: db 'Gap Length must be 99 lines or less.' db cr,lf,eot ; ; Store lines ; ENTRY Accu holds line length ; Carry set indicates PAPER OUT DEFEAT OFF ; StLines: ld (LinLen),a ; Store lines sbc a,a ld (RealLen),a ; Set real length set call SetPitch ; Set default pitch of 6 ld hl,OptSel set _Lines,(hl) ; Indicate lines attached ld a,(hl) ; Get state and 1 SHL _Gap ; Test gap set ret nz ; .. yes, else set gap 0 ; ; Store gap ; ENTRY Accu holds gap ; StGap: ld (Gap),a ; Store gap ld hl,OptSel set _Gap,(hl) ; Indicate set cp 1 ; Test any ret c ; .. nope jr SetPitch ; Set default pitch of 6 ; ; Option : LINE PITCH ; SetLine: ld hl,$PITCH call Decode ; .. throw away PITCH call ChkRange ; Check range 6..8 db 6,8+1 dw $ILL.PITCH ret z ; .. error cp 7 ; Verify 6 or 8 ret z ; .. error jr StPitch ; Store pitch ; $ILL.PITCH: db 'Line Pitch must be 6 or 8 lines per inch.' db cr,lf,eot $PITCH: db 'P',0,0 db eos ; ; Set default pitch of 6 ; SetPitch: ld a,(OptSel) and 1 SHL _Pitch ; Test pitch selected ret nz ; .. don't change ld a,6 ; .. set 6 StPitch: ld (Pitch),a ld hl,OptSel set _Pitch,(hl) ; Set pitch selected or (hl) ; .. force non zero ret ; ; Option : PAPER OUT DEFEAT ON/OFF ; SetPaper: call Get.ON.OFF ; Try ON/OFF ret nz ; .. got it ld hl,$OUT call Decode ; Throw away OUT call Get.ON.OFF ; Now ON/OFF ? ret nz ; .. yeap ld hl,$DEFEAT call Decode ; Throw away DEFEAT Get.ON.OFF: ld hl,$ON.OFF call FindStr ; Find ON or OFF ld de,$ILL.DEFEAT dec l ret z ; .. error, neither ld (Defeat),hl ; Set code ld hl,OptSel set _Defeat,(hl) ; Set defeat ret ; $ON.OFF: db 'ON',eos,0,-1 db 'OFF',eos,0,0 db eos,1,0 $ILL.DEFEAT: db 'Paper Out Defeat on/off badly formed.' db cr,lf,eot $OUT: db 'O',0,0 db eos $DEFEAT: db 'D',0,0 db eos ; ; Option : ; SetNumber: call ChkRange ; Check range 1..17 db 1,17+1 dw $INV.FORM ret z scf call StLines xor a call StGap ; Set no gap jp StConSheet ; Set continous sheet ; $INV.FORM: db 'Form length must be between 1 and 17 inches.' db cr,lf,eot ; ; Find and skip secondary option SHEET or STATIONARY ; GetLxxx: ld hl,$Lxxx jp Decode ; .. throw away ; $Lxxx: db 'L',0,0 db eos ; ; Find and skip secondary option SHEET or STATIONARY ; GetSxxx: ld hl,$Sxxx jp Decode ; .. throw away ; $Sxxx: db 'S',0,0 db eos ; ; Check range ; Call follows: Lower limit ; Upper limit ; Address of error message ; EXIT Zero set on invalid parameter ; Reg DE holds address of error message ; ChkRange: call GetNum ; Get number ex (sp),hl ; .. save ld c,(hl) ; Get lower limit inc hl ld b,(hl) ; .. and upper limit inc hl ld e,(hl) ; .. and address inc hl ld d,(hl) inc hl ex (sp),hl ; Bring back the stack jr z,CR.err ; .. no number ld a,h or a ; HI should be zero jr nz,CR.inval ld a,l cp c ; .. compare LO jr c,CR.inval cp b ; .. and HI ret c CR.inval: xor a ; Set error ret CR.err: ld de,$BAD.PAR ret ; $BAD.PAR: db 'Badly formed parameter.',cr,lf,eot ; ; Init printer ; SetPrinter: ld a,(OptSel) ; Get what we sampled ld c,a sla c call c,DefSheet sla c call c,DefDefeat sla c call c,DefPitch sla c call c,DefLine sla c call c,DefGap sla c ret nc ; .. no more, exit ld a,'d' call ESCout ; Set default ld de,$DEF.SET jp String ; .. and tell it ; $DEF.SET: db 'Defaults set',cr,lf,eot ; ; Print escape prefixed character on printer ; ENTRY Accu holds character ; ESCout: push af ; Save character ld a,esc call Lstout ; .. give prefix pop af ; .. and selection ; ; Print character on printer ; ENTRY Accu holds character ; Lstout: push hl push de push bc push af ld e,a ld c,_Lstout call BDOS ; .. print pop af pop bc pop de pop hl ret ; ; Define pitch ; DefPitch: ld a,'8' ld hl,Pitch sub (hl) call ESCout ; Set pitch ld de,$LIN.PITCH call String ; Give statistic ld a,(Pitch) call PrASCII ; .. give count ld de,$LIN.INCH call String jp NL ; .. close line ; $LIN.PITCH: db 'Line Pitch ',eot $LIN.INCH: db ' (lines per inch)',eot ; ; Give new line to console ; NL: ld de,$CR.LF jp String ; .. do it $CR.LF: db cr,lf,eot ; ; Print decimal number ; ENTRY Accu holds number ; PrDec: ld b,-1 ; Set init PD.loop: inc b sub 10 ; Subtract tens jr nc,PD.loop add a,10 ; Make real again push af ld a,b ; Test tens or a jr nz,PD.0..9 ; .. yeap ld a,' '-'0' ; .. give blank PD.0..9: call PrASCII pop af PrASCII: add a,'0' ; Add offset jp Conout ; .. print ; ; Define length of line ; DefLine: ld a,'C' call ESCout ; Give length of line ld a,(RealLen) ; Test real length set inc a push af call z,Lstout ; .. yeap, set it ld a,(LinLen) ; Get length of line call Lstout ; .. to printer ld de,$FORM.LEN call String ; Give statistic call PrDec ; .. tell line count ld de,$INCHES pop af call z,String call nz,TellLines ; Tell lines jp NL ; $FORM.LEN: db 'Form Length ',eot $INCHES: db ' (inches)',eot ; ; Give simple string ; TellLines: ld de,$LINES jp String ; $LINES: db ' (lines)',eot ; ; Define gap ; DefGap: ld a,(Gap) or a push af ld a,'O' call z,ESCout ; Set gap ld a,'N' call nz,ESCout pop af call nz,Lstout ld de,$GAP.LEN call String call PrDec ; Give gap count call TellLines ; Tell lines jp NL ; $GAP.LEN: db 'Gap Length ',eot ; ; Define defeat ; DefDefeat: ld a,'9' ld hl,OnFlag add a,(hl) call ESCout ; .. give defeat ld de,$OUT.DEF call String ; Tell it ld a,(OnFlag) ; Check state or a ld de,$DEF.OFF ; Tell it call z,String ld de,$DEF.ON call nz,String jp NL ; $OUT.DEF: db 'Paper Out Defeat ',eot $DEF.OFF: db 'Off',eot $DEF.ON: db 'On',eot ; ; Define sheet ; DefSheet: ld a,(Sheet) or a ld a,'c' call z,ESCout ; Give continous ld a,'$' call nz,ESCout ; .. or single sheet ld de,$CONT.SHEET call z,String ; Tell state ld de,$SNGL.SHEET call nz,String jp NL ; $CONT.SHEET: db 'Continuous Stationery',eot $SNGL.SHEET: db 'Single Sheet',eot ; ; Process error ; ENTRY Reg DE points to error message ; ProcErr: push bc push af call String ; Print error call GetAttr ; Test EOL or EOF jr nz,PE.ex ; .. yeap ld de,$IGNORE call String ; Tell ignoring jr PE.go PE.loop: ld a,c call Conout ; Print character PE.go: call GetChr ; Get character and attribute call GetAttr ; Test EOL or EOF call Get ; Get character jr z,PE.loop ; .. there is more to print ld de,$CRLF call String ; .. close line PE.ex: pop af pop bc ret $IGNORE: db 'Ignoring rest of line: ',eot $CRLF: db cr,lf,eot ; ; Print string on console ; ENTRY Reg DE points to string closed by '$' ; String: push hl push de push bc push af ld c,_String call BDOS ; .. print pop af pop bc pop de pop hl ret ; ; Print character on console ; ENTRY Accu holds character ; Conout: push hl push de push bc push af ld e,a ld c,_Conout call BDOS ; .. print pop af pop bc pop de pop hl ret ; ; Get number from input ; EXIT Zero set if no number ; Reg HL holds number ; GetNum: push bc call ChrGet ; Get valid character bit _NM,b ; Test number jr z,GN.hex ; .. nope call GetDec jr GN.ex GN.hex: bit _EX,b ; Test hex prefix jr z,GN.ex ; .. nope call GetHex ; .. get it GN.ex: pop bc ret ; ; Get decimal number ; EXIT Reg HL holds number ; GetDec: push de push bc call ChrGet ; Get valid character bit _NM,b ; Test number jr z,GD.ex ; .. no ld hl,0 ; Init result jr GD.go GD.loop: ld e,l ; Copy number ld d,h add hl,hl ; * 2 add hl,hl ; * 4 add hl,de ; * 5 add hl,hl ; * 10 GD.go: ld a,c sub '0' ; Strip off offset add a,l ld l,a ; .. add to old number adc a,h sub l ld h,a call Get ; Get character from file call GetChr ; .. and attribute bit _NM,b ; Test still number jr nz,GD.loop ; .. yeap or 1 ; .. set success GD.ex: pop bc pop de ret ; ; Get hex number ; EXIT Reg HL holds number ; GetHex: push bc call ChrGet ; Get valid character bit _EX,b ; Test expansion prefix jr z,GH.ex ; .. nope call Get ; Get character from file call GetChr ; .. and attribute bit _HX,b ; Test hex call z,UnGet ; Unget character if not jr z,GH.ex ; .. and exit ld hl,0 ; Init result jr GH.go GH.loop: add hl,hl ; * 2 add hl,hl ; * 4 add hl,hl ; * 8 add hl,hl ; * 16 GH.go: ld a,c ; Get character and LoMask ; Mask lower part bit _NM,b ; Test 0..9 jr nz,GH.dec ; .. yeap add a,9 ; Fix for hex GH.dec: or l ld l,a ; Put into result call Get ; Get character from file call GetChr ; .. and attribute bit _HX,b ; Test still hex jr nz,GH.loop ; .. yeap or 1 ; Set success GH.ex: pop bc ret ; ; Read character, test end ; FixNL: call GetAttr ; Get attributes call nz,Get ; .. read if EOL or EOF ret ; ; Decode from table ; ENTRY Reg HL points to table ; Entry: Command key, execution address ; Closed by -1, execution address ; EXIT Reg HL holds execution address ; Decode: push de push bc push af call ChrGet ; Get character jr Dec.go ; .. start Dec.loop: inc hl ; Skip address inc hl Dec.go: ld a,(hl) ; Get character inc hl cp eos ; Test end of table jr z,Dec.ex call CmpChr ; Find character jr nz,Dec.loop Dec.skip: call Get ; Skip alphanumeric characters call GetChr bit _AN,b jr nz,Dec.skip Dec.ex: ld e,(hl) ; Fetch address inc hl ld d,(hl) ex de,hl pop af pop bc pop de ret ; ; Find string from table ; ENTRY Reg HL points to table ; EXIT Reg L holds 1st operand ; Reg H holds 2nd operand or -1 if not found ; FindStr: push de push bc push af call ChrGet ; Get valid character ld d,b ; Save attribute dec hl ; .. fix list jr FS.go FS..unget: inc e FS.unget: dec e call nz,UnGet ; Unget character jr nz,FS.unget FS.skip: ld a,(hl) ; Get character inc hl inc a jr nz,FS.skip ; .. skip item inc hl FS.go: ld e,0 ; Init counter jr FS.cmp FS.loop: call CmpChr ; Compare character jr nz,FS..unget ; .. not found call Get ; Get character from line inc e FS.cmp: call GetChr ; Get character and attribute inc hl ld a,(hl) cp eos ; Test end of string jr nz,FS.loop ; .. nope inc e dec e ; Test total end jr z,FS.end ; .. yeap ld a,b xor d ; Test same attribute and 00101011b ; Test result jr z,FS..unget ; .. still searching FS.end: inc hl ld e,(hl) ; Get operands inc hl ld d,(hl) ex de,hl ; .. into right reg pop af pop bc pop de ret ; ; Compare characters ; ENTRY Accu and reg C hold characters ; EXIT Zero set if same ; CmpChr: sub c ; Compare ret z ; .. found cp -' ' ; Test blank ???? ret nz ; .. nope ld a,b or 11111101b ; Fix attribute inc a ; .. fix result ret ; ; Get valid definition character from command line ; ChrGet: jr .ChrGet ; .. skip reading CG.loop: call Get ; Get character .ChrGet: call GetChr ; Get character and attribute bit _EO,b ; Test end of input ret nz ; .. exit bit _IG,b ; Test valid character jr nz,CG.loop ; .. nope ret ; ; Prepare CCP command line ; EXIT Carry set if line OK ; PrepCCPline: push hl push de push bc ld hl,CCPcmd ld a,(hl) ; Fetch length of input inc a ld (RecPtr),a ; .. save it inc hl ld (BufPtr),hl ; Init buffer dec a add a,l ; Point to end of line ld l,a adc a,h sub l ld h,a ld (hl),eof ; Close line scf pop bc pop de pop hl ret nc ; ; Get character from command line ; Store character and attribute ; Get: push hl push de push bc push af ld hl,(BufPtr) ; Get current pointer ld c,(hl) ; .. get character ex de,hl call PutChr ; .. save it ld a,c cp eof ; Test end of line jr z,Get.eof ld a,(RecPtr) dec a ; Fix pointers ld (RecPtr),a ex de,hl inc hl ld (BufPtr),hl Get.eof: pop af pop bc pop de pop hl ret ; ; Unget current character ; UnGet: push hl push de push bc push af ld a,(Char) ; Get character cp eof ; Test end of line ld hl,(BufPtr) jr z,UG.dummy ; .. yeap, skip ld hl,RecPtr inc (hl) ; Fix pointers if not ld hl,(BufPtr) dec hl ld (BufPtr),hl UG.dummy: dec hl ld c,(hl) call PutChr ; Save character and attribute pop af pop bc pop de pop hl ret ; ; Put character and attribute into memory ; ENTRY Reg C holds character ; PutChr: bit MSB,c ; Test 80..FF ld b,01h jr nz,.PutChr ; .. yeap, set standard ld b,0 ld hl,AttrTable add hl,bc ld b,(hl) ; Fetch attribute .PutChr: ld (Char),bc ; Save character and attribute ret ; ; Get current character and attribute ; EXIT Reg C holds character ; Reg B holds attribute ; GetChr: ld bc,(Char) ; Get character and attribute ret ; ; Get EOL or EOF state of current character ; EXIT Zero set if not EOL or EOF ; GetAttr: ld a,(Attr) ; Get attribute and 1 SHL _EO ; .. test bit ret ; ; Attribute table of all ASCII characters ; Bit definitions: ; ; 7 6 5 4 3 2 1 0 ; +----+----+----+----+----+----+----+----+ ; | xx | xx | EO | EX | NM | HX | AN | IG | ; +----+----+----+----+----+----+----+----+ ; ; xx N.C. ; EO EOL or EOF ; EX Extension string ; NM Numeric 0..9 ; HX Hex range A..F ; AN Alphanumeric prefix ; IG Ignore for definition ; AttrTable: ; ; Control characters ; db 01h,01h,01h,01h,01h,01h,01h ; 00..06 db 01h,01h,01h,01h,01h,01h,21h ; 07..0D db 01h,01h,01h,01h,01h,01h,01h ; 0E..14 db 01h,01h,01h,01h,01h,21h,01h ; 15..1B db 01h,01h,01h,01h ; 1C..1F ; ; ASCII characters ; db 01h,01h,00h,10h,01h,01h,10h ; !"#$%& db 01h,01h,01h,01h,01h,01h,01h ; '()*+,\ db 00h,01h,0ch,0ch,0ch,0ch,0ch ; ./01234 db 0ch,0ch,0ch,0ch,0ch,01h,01h ; 56789:; db 01h,01h,01h,01h,01h,06h,06h ; <=>?@AB db 06h,06h,06h,06h,02h,02h,02h ; CDEFGHI db 02h,02h,02h,02h,02h,02h,02h ; JKLMNOP db 02h,02h,02h,02h,02h,02h,02h ; QRSTUVW db 02h,02h,02h,01h,01h,01h,01h ; XYZ[\]^ db 01h,01h,06h,06h,06h,06h,06h ; _`abcde db 06h,02h,02h,02h,02h,02h,02h ; fghijkl db 02h,02h,02h,02h,02h,02h,02h ; mnopqrs db 02h,02h,02h,02h,02h,02h,02h ; tuvwxyz db 01h,01h,01h,01h,01h ; {|}~DEL db eof ds 113,0 DATA equ 1100h UsrStk equ DATA LocStk equ UsrStk+258 LinLen equ UsrStk+258 Pitch equ LinLen+1 RealLen equ Pitch+1 Gap equ RealLen+1 Sheet equ Gap+1 OptSel equ Sheet+1 Defeat equ OptSel+1 OnFlag equ Defeat+1 BufPtr equ OnFlag+1 RecPtr equ BufPtr+2 Char equ RecPtr+1 Attr equ Char+1 end